Response
: ์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ก ๋ณด๋ด๋ ์๋ต ๋ฉ์์ง๋ก, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ๋ํ ์ํ ๋ฐ ํด๋น ์์ฒญ๊ณผ ํจ๊ป ์ ๋ฌ๋๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ํฉ๋๋ค.
Overview
โข
์คํ๋ง ๋ถํธ๋ก ์๋ฒ์์ ์๋ตํ๊ธฐ
โข
@RestController
โฆ
์๋ต ํ์
โช
void
โช
String
โช
๊ฐ์ฒด
โช
์ปฌ๋ ์
โช
ResponseEntity<>
โข
@Controller
โฆ
์๋ต ํ์
โช
void
โช
String
โช
@ResponseBody
โข
์๋ต ์ํ ์ฝ๋
โข
๋ฆฌ๋ค์ด๋ ํธ
โข
์ด๋ฏธ์ง ์๋ต (์ธ๋ค์ผ)
โข
ํ์ผ ์๋ต (๋ค์ด๋ก๋)
โข
API ๊ฐ๋ฐ ๋ฌธ์ํ ๋๊ตฌ
โฆ
Swagger
์คํ๋ง ๋ถํธ๋ก ์๋ฒ์์ ์๋ตํ๊ธฐ
@RestController
: JSON ๋๋ XML๊ณผ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ ์ปจํธ๋กค๋ฌ๋ฅผ ์ง์ ํ๋ ์ด๋
ธํ
์ด์
@RestController = @Controller + @ResponseBody
/**
* ๐ข๐ก๐ด @RestController
* : JSON ๋๋ XML๊ณผ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ ์ปจํธ๋กค๋ฌ๋ฅผ ์ง์ ํ๋ ์ด๋
ธํ
์ด์
* ๐ต RESTful ์น ์๋น์ค๋ฅผ ์์ฑํ๋ ๋ฐ ์ฌ์ฉ
* ๐ต @Controller ์ @ResponseBody๋ฅผ ํฉํ ์ญํ ์ ํ๋ ์ด๋
ธํ
์ด์
* โ @Controller โก View๋ฅผ ๋ฐํ
* โ @RestController โก ์๋ต ๋ฐ์ดํฐ(๋ฉ์์ง[์ํ์ฝ๋,์๋ตํค๋,์๋ต๋ณธ๋ฌธ(body)])๋ฅผ ๋ฐํ
*/
@Slf4j
@RestController
public class ResponseController {
}
Java
๋ณต์ฌ
์๋ต ํ์
void
void๋ฅผ ๋ฐํํ๋ ๊ฒฝ์ฐ, ์คํ๋ง๋ถํธ๋ ํด๋น ์๋ํฌ์ธํธ์ ๋ํด ์๋ฌด๊ฒ๋ ๋ฐํํ์ง ์์ต๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ์ด๋ ๋ฆฌ๋ค์ด๋ ์
, ํ์ด์ง ์ด๋ ๋ฑ์ ๊ธฐ๋ฅ์ ์ฌ์ฉ๋ฉ๋๋ค.
/**
* ๐ void
* - ์ด๋ค ์์
์ ์ํํ๊ณ ์๋ต์ด ํ์ ์๋ ๊ฒฝ์ฐ
* โ
์ํ์ฝ๋ : 200 OK
* โ
body : โ
*/
@GetMapping("/void")
public void voidResponse() {
log.info("[GET] - /void");
}
Java
๋ณต์ฌ
String
String์ ๋ฐํํ๋ ๊ฒฝ์ฐ, ํด๋น String ๊ฐ์ HTTP ์๋ต ๋ณธ๋ฌธ์ผ๋ก ๋ฐํ๋ฉ๋๋ค. ์คํธ๋ง์ ์ผ๋ฐ์ ์ผ๋ก HTML, JSON, XML ๋ฑ๊ณผ ๊ฐ์ ํ
์คํธ ๊ธฐ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ์๋ตํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
/**
* ๐ String
* - ๋ฐํํ๋ ๋ฌธ์์ด๋ก, HTTP ์๋ต์ ๋ณธ๋ฌธ(body)์ ์ง์ ํ๋ค.
* โ
์ํ์ฝ๋ : 200 OK
* โ
body : "๋ฌธ์์ด ๋ฐ์ดํฐ๋ฅผ ์๋ตํฉ๋๋ค."
*/
@GetMapping("/string")
public String stringResponse() {
log.info("[GET] - /string");
return "๋ฌธ์์ด ๋ฐ์ดํฐ๋ฅผ ์๋ตํฉ๋๋ค.";
}
Java
๋ณต์ฌ
๊ฐ์ฒด
๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ ๊ฒฝ์ฐ, ์คํ๋ง๋ถํธ๋ ํด๋น ๊ฐ์ฒด๋ฅผ JSON ๋๋ XML๊ณผ ๊ฐ์ ํ์์ผ๋ก ์ง๋ ฌํํ์ฌ HTTP ์๋ต ๋ณธ๋ฌธ์ผ๋ก ๋ฐํํฉ๋๋ค. ์ฃผ๋ก JSON ํ์์ผ๋ก ๋ฐํ๋๋ฉฐ, ๊ฐ์ฒด์ ํ๋์ ๊ฐ์ด HTTP ์๋ต์ผ๋ก ์ ์ก๋ฉ๋๋ค.
/**
* ๐ ๊ฐ์ฒด
* - ๊ฐ์ฒด๋ฅผ JSON ํ์์ผ๋ก ๋ณํํ๊ณ , ์ด๋ฅผ HTTP ์๋ต ๋ณธ๋ฌธ์ ์ง์ ํ๋ค.
* โ
์ํ์ฝ๋ : 200 OK
* โ
body : {"boardNo":0,"title":"์ ๋ชฉ1","writer":"์์ฑ์1","content":"๋ด์ฉ1","regDate":null,"updDate":null,"views":0}
* @return
*/
@GetMapping("/object")
public Board objectResponse() {
log.info("[GET] - /object");
Board board = new Board("์ ๋ชฉ1", "์์ฑ์1", "๋ด์ฉ1");
return board;
}
Java
๋ณต์ฌ
์ปฌ๋ ์
์ปฌ๋ ์
์ ๋ฐํํ๋ ๊ฒฝ์ฐ, ์คํ๋ง๋ถํธ๋ ํด๋น ์ปฌ๋ ์
์ JSON ๋๋ XML๊ณผ ๊ฐ์ ํ์์ผ๋ก ์ง๋ ฌํํ์ฌ HTTP ์๋ต ๋ณธ๋ฌธ์ผ๋ก ๋ฐํํฉ๋๋ค. ๊ฐ ํญ๋ชฉ์ ๊ฐ์ฒด์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ง๋ ฌํ๋์ด ์ ์ก๋ฉ๋๋ค.
List<>
/**
* ๐ ์ปฌ๋ ์
* - ์ปฌ๋ ์
์ JSON ๋ฐฐ์ด ํ์์ผ๋ก ๋ณํํ๊ณ , ์ด๋ฅผ HTTP ์๋ต ๋ณธ๋ฌธ์ ์ง์ ํ๋ค.
* โ
์ํ์ฝ๋ : 200 OK
* โ
body : [{"boardNo":0,"title":"์ ๋ชฉ1","writer":"์์ฑ์1","content":"๋ด์ฉ1","regDate":null,"updDate":null,"views":0},{"boardNo":0,"title":"์ ๋ชฉ2","writer":"์์ฑ์2","content":"๋ด์ฉ2","regDate":null,"updDate":null,"views":0},{"boardNo":0,"title":"์ ๋ชฉ3","writer":"์์ฑ์3","content":"๋ด์ฉ3","regDate":null,"updDate":null,"views":0}]
* @return
*/
@GetMapping("/collection")
public List<Board> collectionResponse() {
log.info("[GET] - /collection");
List<Board> boardList = new ArrayList<>();
boardList.add(new Board("์ ๋ชฉ1", "์์ฑ์1", "๋ด์ฉ1"));
boardList.add(new Board("์ ๋ชฉ2", "์์ฑ์2", "๋ด์ฉ2"));
boardList.add(new Board("์ ๋ชฉ3", "์์ฑ์3", "๋ด์ฉ3"));
return boardList;
}
Java
๋ณต์ฌ
Map<>
/**
* ๐ Map<String, ?>
* - Map ์ปฌ๋ ์
์ JSON ํ์์ผ๋ก ๋ณํํ์ฌ,
* key ์ ๋ํ value ๋ก ๋ค์ํ ๊ฐ์ฒด๋ค์ ๊ณ์ธต์ ์ธ ๊ตฌ์กฐ๋ก HTTP ์๋ต ๋ณธ๋ฌธ์ ์ง์ ํ๋ค.
* โ
์ํ์ฝ๋ : 200 OK
* โ
body : {"student":{"name":"๊น์กฐ์","age":20,"studentId":1001,"grade":"1"},"person":{"name":"๊น์กฐ์","age":20},"board":{"boardNo":0,"title":"์ ๋ชฉ","writer":"์์ฑ์","content":"๋ด์ฉ","regDate":null,"updDate":null,"views":0}}
* @return
*/
@GetMapping("/map")
public Map<String, ?> mapResponse() {
log.info("[GET] - /map");
Map<String, Object> map = new HashMap<>();
map.put("board", new Board("์ ๋ชฉ", "์์ฑ์", "๋ด์ฉ"));
map.put("person", new Person());
map.put("student", new Student());
return map;
}
Java
๋ณต์ฌ
ResponseEntity<>
ResponseEntity๋ HTTP ์๋ต์ ๋ค์ํ๊ฒ ์ ์ดํ ์ ์๋ ํด๋์ค์
๋๋ค. ๊ฐ๋ฐ์๋ ์ํ ์ฝ๋, ํค๋, ๋ณธ๋ฌธ์ ์ง์ ์ ์ํ์ฌ ResponseEntity ๊ฐ์ฒด๋ฅผ ๋ฐํํ ์ ์์ต๋๋ค.
ResponseEntity<>
/**
* ๐ ResponseEntity<โก>
* : ResponseEntity ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ฉด, "์ํ์ฝ๋/ํค๋/๋ณธ๋ฌธ"์ ์ง์ ํ์ฌ ์๋ตํ ์ ์๋ค.
* โ
<โก> ํ์
๋งค๊ฐ๋ณ์์ ์๋ตํ ๋ฐ์ดํฐ์ ํ์
์ ์ง์ ํ ์ ์๋ค.
* - String, Object, Collection ๋ฑ ์ง์ ๊ฐ๋ฅ
* - ? ์์ผ๋ ์นด๋๋ก ์ง์ ํ๋ฉด, ํน์ ํ์ง ์๊ณ ์ํฉ์ ๋ฐ๋ผ ๋์ ์ผ๋ก ์ฒ๋ฆฌ ๊ฐ๋ฅ
*
* 1๏ธโฃ ์ํ์ฝ๋ : ok(), badRequest(), created(URI), status()
* โ HttpStatus ์๋ต ์ํ ์ฝ๋๋ฅผ ๊ฐ์ง๊ณ ์๋ enum (์ด๊ฑฐํ์
)
*
* 2๏ธโฃ ํค๋ : ResponseEntity.1๏ธโฃ.header("ํค๋ ๋ช
", "ํค๋ ๊ฐ")
*
* 3๏ธโฃ ๋ณธ๋ฌธโญ : ResponseEntity.1๏ธโฃ.body( data )
* ResponseEntity.1๏ธโฃ.2๏ธโฃ.body( data )
*
* 4๏ธโฃ ๋ณธ๋ฌธโ : ResponseEntity.1๏ธโฃ.build( data )
* ResponseEntity.1๏ธโฃ.2๏ธโฃ.build( data )
* @return
*/
@GetMapping("/responseString")
public ResponseEntity<String> responseEntityResponse() {
log.info("[GET] - /responseString");
// ๐ข ์์ฒญ ์ฑ๊ณต
// - ์ํ์ฝ๋: 200
// - body :"200 OK - ์์ฒญ ์ฑ๊ณต"
// return ResponseEntity.ok("200 OK - ์์ฒญ ์ฑ๊ณต");
// ๐ ์๋ชป๋ ์์ฒญ - ์ํ์ฝ๋
// - ์ํ์ฝ๋: 400
// - body :"400 Bad Request - ์๋ชป๋ ์์ฒญ"
// return ResponseEntity.badRequest().body("400 Bad Request - ์๋ชป๋ ์์ฒญ");
// ๐ด ์๋ฒ ์๋ฌ
// - ์ํ์ฝ๋: 500
// - body :"500 Internal Server Error - ์๋ฒ ๋ด๋ถ ์๋ฌ"
// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("500 Internal Server Error - ์๋ฒ ๋ด๋ถ ์๋ฌ");
return ResponseEntity.ok("200 OK - ์์ฒญ ์ฑ๊ณต");
}
Java
๋ณต์ฌ
ResponseEntity<byte[]>
โข
Content-Type : image/* (์ด๋ฏธ์ง)
/**
* ๐ ResponseEntity<byte[]>
* @return
* @throws IOException
*/
@GetMapping("/img")
public ResponseEntity<byte[]> thumbnailImg() throws IOException {
log.info("[GET] - /img");
// ์ด๋ฏธ์ง ํ์ผ์ ์ฝ์ด์ด
ClassPathResource imgFile = new ClassPathResource("sample.png");
byte[] bytes = Files.readAllBytes(imgFile.getFile().toPath());
// ์ด๋ฏธ์ง ํ์ผ์ ์ฝ์ด์ ์๋ต
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
}
Java
๋ณต์ฌ
ClassPathResource ๊ฐ์ฒด๋ resources ํด๋์ ํ์ผ๋ฅผ ์ง์ ํ์ฌ ๊ฐ์ ธ์ต๋๋ค.
ResponseEntity<byte[]>
โข
Content-Type : application/octet-stream
โข
Content-Disposition : form-data; name="attachment"; filename="sample.pngโ
/**
* ๐ ResponseEntity<byte[]>
* @return
* @throws IOException
*/
@GetMapping("/download")
public ResponseEntity<byte[]> download() throws IOException {
log.info("[GET] - /download");
// ์ด๋ฏธ์ง ํ์ผ์ ์ฝ์ด์ด
ClassPathResource imgFile = new ClassPathResource("sample.png");
byte[] bytes = Files.readAllBytes(imgFile.getFile().toPath());
// ํ์ผ์ ๋ค์ด๋ก๋ ๋ฐ๋๋ก ์๋ต
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment", "sample.png");
return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
}
Java
๋ณต์ฌ
@Controller
: Spring MVC ์ HTTP ์์ฒญ์ ์๋ตํ๋ ์ปจํธ๋กค๋ฌ ํด๋์ค๋ก ์ง์ ํ๋ ์ด๋
ธํ
์ด์
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
SQL
๋ณต์ฌ
์๋ต ํ์
void
: URL ๊ณผ ๋์ผํ ๊ฒฝ๋ก์ ๋ทฐ๋ฅผ ์๋ตํ๋ค.
String
: ๋ฌธ์์ด๋ก ์๋ตํ ๋ทฐ์ ๊ฒฝ๋ก๋ฅผ ์ง์ ํ๋ค.
@ResponseBody
: ์ปจํธ๋กค๋ฌ ๋ฉ์๋ ์์ ๋ถ์ฌ, ๋ฉ์๋๊ฐ ๋ฐํํ๋ ๊ฐ์ฒด๋ฅผ ์๋ต ๋ฉ์์ง ๋ณธ๋ฌธ์ ํฌํจ์ํค๋ ์ด๋
ธํ
์ด์
( ๋ทฐ๋ฅผ ์๋ตํ์ง ์๋๋ค. )
์๋ต ์ํ ์ฝ๋
์๋ต ์ํ ์ฝ๋
HTTP ์๋ต ์ํ ์ฝ๋๋ ํด๋ผ์ด์ธํธ์๊ฒ ์์ฒญ์ด ์ฑ๊ณต์ ์ผ๋ก ์ฒ๋ฆฌ๋์๋์ง๋ฅผ ์๋ ค์ฃผ๋ ์ญํ ์ ํฉ๋๋ค. ๋ช ๊ฐ์ง ์ผ๋ฐ์ ์ธ ์ํ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
โข
200 OK: ์์ฒญ์ด ์ฑ๊ณต์ ์ผ๋ก ์ฒ๋ฆฌ๋์์์ ๋ํ๋
๋๋ค.
โข
201 Created: ์์ฒญ์ด ์ฑ๊ณต์ ์ผ๋ก ์ฒ๋ฆฌ๋์๊ณ , ์๋ก์ด ๋ฆฌ์์ค๊ฐ ์์ฑ๋์์์ ๋ํ๋
๋๋ค.
โข
400 Bad Request: ์๋ชป๋ ์์ฒญ์ผ๋ก ์ธํด ์๋ฒ๊ฐ ์์ฒญ์ ์ดํดํ ์ ์์์ ๋ํ๋
๋๋ค.
โข
403 Forbidden : ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญํ ๋ฆฌ์์ค์ ์ ๊ทผํ ๊ถํ์ด ์์์ ๋ํ๋
๋๋ค. ์๋ฒ๋ ์์ฒญ์ ์ดํดํ๊ณ ์์ง๋ง, ํด๋ผ์ด์ธํธ์๊ฒ ํด๋น ๋ฆฌ์์ค์ ์ ๊ทผํ ๊ถํ์ด ์๋ค๋ ๊ฒ์ ์๋ ค์ค๋๋ค.
โข
404 Not Found: ์์ฒญํ ๋ฆฌ์์ค๊ฐ ์๋ฒ์์ ์ฐพ์ ์ ์์์ ๋ํ๋
๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ ์๋ชป๋ URL์ ์์ฒญํ ๊ฒฝ์ฐ๋ ์์ฒญํ ๋ฆฌ์์ค๊ฐ ์ญ์ ๋์๊ฑฐ๋ ์ด๋๋์์ ๋ ๋ฐ์ํฉ๋๋ค.
โข
500 Internal Server Error: ์๋ฒ ๋ด๋ถ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ฌ ์์ฒญ์ ์ฒ๋ฆฌํ ์ ์์์ ๋ํ๋
๋๋ค.
๊ฐ ์ํ ์ฝ๋๋ ๋ค๋ฅธ ์๋ฏธ๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ํด๋ผ์ด์ธํธ๋ ์ด๋ฌํ ์ฝ๋๋ฅผ ํตํด ์์ฒญ์ ๋ํ ์ ์ ํ ์กฐ์น๋ฅผ ์ทจํ ์ ์์ต๋๋ค.
200 OK
: ์์ฒญ์ด ์ฑ๊ณต์ ์ผ๋ก ์ฒ๋ฆฌ๋์์์ ๋ํ๋
๋๋ค.
@GetMapping("/200")
public ResponseEntity<String> ok() {
log.info("[GET] - /200 - ์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฑ๊ณต์ ์ผ๋ก ์ฒ๋ฆฌํ์ ๋ ์๋ตํ๋ ์ํ์ฝ๋ ์
๋๋ค.");
return ResponseEntity.ok("์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฑ๊ณต์ ์ผ๋ก ์ฒ๋ฆฌํ์ ๋ ์๋ตํ๋ ์ํ์ฝ๋ ์
๋๋ค.");
}
Java
๋ณต์ฌ
201 Created
: ์์ฒญ์ด ์ฑ๊ณต์ ์ผ๋ก ์ฒ๋ฆฌ๋์๊ณ , ์๋ก์ด ๋ฆฌ์์ค๊ฐ ์์ฑ๋์์์ ๋ํ๋
๋๋ค.
@GetMapping("/201")
public ResponseEntity<String> created() {
log.info("[GET] - /200 - ์๋ฒ๊ฐ ์๋ก์ด ๋ฆฌ์์ค๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ์์ฑ ํ์ ๋ ์๋ตํ๋ ์ํ์ฝ๋์
๋๋ค.");
return ResponseEntity.status(HttpStatus.CREATED).body("์๋ฒ๊ฐ ์๋ก์ด ๋ฆฌ์์ค๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ์์ฑ ํ์ ๋ ์๋ตํ๋ ์ํ์ฝ๋์
๋๋ค.");
}
Java
๋ณต์ฌ
400 Bad Request
: ์๋ชป๋ ์์ฒญ์ผ๋ก ์ธํด ์๋ฒ๊ฐ ์์ฒญ์ ์ดํดํ ์ ์์์ ๋ํ๋
๋๋ค.
@GetMapping("/400")
public ResponseEntity<String> badRequest() {
log.info("[GET] - /400 - ํด๋ผ์ด์ธํธ ์์ฒญ์ด ์๋ชป๋จ์ ์๋ ค์ฃผ๋ ์ํ์ฝ๋์
๋๋ค.");
return ResponseEntity.badRequest().body("ํด๋ผ์ด์ธํธ ์์ฒญ์ด ์๋ชป๋จ์ ์๋ ค์ฃผ๋ ์ํ์ฝ๋์
๋๋ค.");
}
Java
๋ณต์ฌ
403 Forbidden
: ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญํ ๋ฆฌ์์ค์ ์ ๊ทผํ ๊ถํ์ด ์์์ ๋ํ๋
๋๋ค. ์๋ฒ๋ ์์ฒญ์ ์ดํดํ๊ณ ์์ง๋ง, ํด๋ผ์ด์ธํธ์๊ฒ ํด๋น ๋ฆฌ์์ค์ ์ ๊ทผํ ๊ถํ์ด ์๋ค๋ ๊ฒ์ ์๋ ค์ค๋๋ค.
@GetMapping("/403")
public ResponseEntity<String> forbidden() {
log.info("[GET] - /403 - ํด๋ผ์ด์ธํธ๊ฐ ์์ ์ ๊ทผ์ ๊ฑฐ๋ถ๋์์์ ์๋ ค์ฃผ๋ ์ํ์ฝ๋์
๋๋ค. (์ฃผ๋ก ๊ถํ์ด ์์ ๋, ์๋ตํ๋ ์ํ์ฝ๋์
๋๋ค.)");
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("ํด๋ผ์ด์ธํธ๊ฐ ์์ ์ ๊ทผ์ ๊ฑฐ๋ถ๋์์์ ์๋ ค์ฃผ๋ ์ํ์ฝ๋์
๋๋ค. (์ฃผ๋ก ๊ถํ์ด ์์ ๋, ์๋ตํ๋ ์ํ์ฝ๋์
๋๋ค.)");
}
Java
๋ณต์ฌ
404 Not Found
: ์์ฒญํ ๋ฆฌ์์ค๊ฐ ์๋ฒ์์ ์ฐพ์ ์ ์์์ ๋ํ๋
๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ ์๋ชป๋ URL์ ์์ฒญํ ๊ฒฝ์ฐ๋ ์์ฒญํ ๋ฆฌ์์ค๊ฐ ์ญ์ ๋์๊ฑฐ๋ ์ด๋๋์์ ๋ ๋ฐ์ํฉ๋๋ค.
@GetMapping("/404")
public ResponseEntity<String> notFound() {
log.info("[GET] - /404 - ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญํ ๋ฆฌ์์ค๊ฐ ์๋ฒ์ ์๊ฑฐ๋, ์์ฒญํ ๊ฒฝ๋ก๊ฐ ์กด์ฌํ์ง ์์ ๋ ์๋ตํ๋ ์ํ์ฝ๋ ์
๋๋ค.");
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญํ ๋ฆฌ์์ค๊ฐ ์๋ฒ์ ์๊ฑฐ๋, ์์ฒญํ ๊ฒฝ๋ก๊ฐ ์กด์ฌํ์ง ์์ ๋ ์๋ตํ๋ ์ํ์ฝ๋ ์
๋๋ค.");
}
Java
๋ณต์ฌ
500 Internal Server Error
: ์๋ฒ ๋ด๋ถ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ฌ ์์ฒญ์ ์ฒ๋ฆฌํ ์ ์์์ ๋ํ๋
๋๋ค.
@GetMapping("/500")
public ResponseEntity<String> internalServerError() {
log.info("[GET] - /500 - ์๋ฒ ์ธก์์ ์๋ฌ๋ ์์ธ๊ฐ ๋ฐ์ํ์ ๋ ์๋ตํ๋ ์ํ์ฝ๋ ์
๋๋ค.");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("์๋ฒ ์ธก์์ ์๋ฌ๋ ์์ธ๊ฐ ๋ฐ์ํ์ ๋ ์๋ตํ๋ ์ํ์ฝ๋ ์
๋๋ค.");
}
Java
๋ณต์ฌ
์ผ๋ฐ์ ์ผ๋ก, 400 ๋ฒ๋, 500 ๋ฒ๋ ์ํ์ฝ๋๋ ์ง์ ์๋ตํ์ง ์๊ณ ์์ธ ์ฒ๋ฆฌ๋ฅผ ํตํด ์ผ๊ด์ ์ธ ๋ฐฉ๋ฒ์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค.
๋ฆฌ๋ค์ด๋ ํธ
๋ฆฌ๋ค์ด๋ ํธ๋ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ๋ค๋ฅธ URL๋ก ์ ์กํ๋ ๊ธฐ๋ฅ์ ๋งํฉ๋๋ค. ์ด๋ ์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ๋ฐ์์ง๋ง, ํด๋น ๋ฆฌ์์ค๊ฐ ๋ค๋ฅธ ์์น์ ์๊ฑฐ๋ ์ด๋๋์์ ๋ ์ฌ์ฉ๋ฉ๋๋ค. ๋ฆฌ๋ค์ด๋ ํธ๋ ํด๋ผ์ด์ธํธ๊ฐ ์๋ ์์ฒญํ URL ๋์ ์ ์๋ก์ด URL๋ก ์ด๋ํ์ฌ ๋ฆฌ์์ค๋ฅผ ์ป์ ์ ์๋๋ก ๋์์ค๋๋ค. ์ด๋ฅผ ํตํด ์น ํ์ด์ง์ ๊ฒฝ๋ก๋ฅผ ๋ณ๊ฒฝํ๊ฑฐ๋, ํน์ ํ์ด์ง๋ก์ ๋ฆฌ๋ค์ด๋ ์
์ ์ค์ ํ ์ ์์ต๋๋ค.
ํ์ด์ง ์ด๋ ๋ฐฉ์
โข
forward
โข
redirect
์น ํ์ด์ง๋ฅผ ์ด๋ํ๋ ๋ฐฉ์์ 2๊ฐ์ง๋ก ๋๋์ด ๋ณผ ์ ์๋ค.
forward ๋ฐฉ์
forward : โ์ ๋ฌํ๋คโ
โข
์๋ฒ ๋ด๋ถ์์ ์์ฒญ ๊ฒฝ๋ก A ๊ฐ B ๋ก ์์ฒญ์ ์ ๋ฌํ๋ฉฐ ํ์ด์ง๋ก ์ด๋ํ๋ ๋ฐฉ์
โข
ํน์ง
โฆ
์๋์ ์์ฒญ ์ ๋ณด(request) ๋ฐ ์๋ต ์ ๋ณด(response)๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉ
โฆ
ํด๋ผ์ด์ธํธ๋ ์ด๋ํ ํ์ด์ง B ๋ฅผ ์๋ต ๋ฐ์ง๋ง, ์ฃผ์ ํ์์ค์ ์์ฒญ URL ์ ๊ทธ๋๋ก์
โฆ
์กฐํ(์ฝ๊ธฐ) ์์ฒญ์ ํ๋ ๊ฒฝ์ฐ์ ์ฃผ๋ก ์ฌ์ฉ
redirect ๋ฐฉ์
redirect : โ๋ค์ ์ง์ํ๋คโ
โข
์๋ฒ๊ฐ ์์ฒญ ๊ฒฝ๋ก A ๋ก ์์ฒญ์ ๋ฐ์ ํ, ํด๋ผ์ด์ธํธ์๊ฒ B ๋ก ๋ค์ ์์ฒญํ๋ผ๊ณ ์ง์ํ๋ฉฐ ํ์ด์ง๋ฅผ ์ด๋ํ๋ ๋ฐฉ์
โข
ํน์ง
โฆ
ํด๋ผ์ด์ธํธ๊ฐ ์๋์ ์์ฒญ๊ณผ ๋ฌ๋ฆฌ ์์ ํ ๋ค๋ฅธ ์๋ก์ด ์์ฒญ์ ํ์ฌ, ๊ธฐ์กด์ ์์ฒญ ์ ๋ณด๋ ์ดํ์ ์์ฒญ์์๋ ์ฌ์ฉํ ์ ์์
โฆ
์ด๋ํ ํ๋ฉด์์ ์ฃผ์ ํ์์ค์ URL ์ด A ์์ B ๋ก ๋ณํ๋จ
โฆ
๋ฑ๋ก, ์์ , ์ญ์ ์์ฒญ ์์ ์ฃผ๋ก ์ฌ์ฉ
์ผ๋ฐ์ ์ผ๋ก ๊ฒ์๊ธ ๋ฑ๋ก, ์์ , ์ญ์ ์ฒ๋ฆฌ ํ, ๊ฒ์๊ธ ๋ชฉ๋ก์ผ๋ก ํ์ด์ง๋ฅผ ์ด๋์ํค๊ธฐ ์ํด์ ๋ฆฌ๋ค์ด๋ ์
์ ํ๋ค.
๊ฒ์๊ธ ์ฐ๊ธฐ ์ฒ๋ฆฌ
๊ฒ์๊ธ ๋ชฉ๋ก (redierct)
/**
* ๊ฒ์๊ธ ์ฐ๊ธฐ ์ฒ๋ฆฌ
* [POST]
* /board/insert
* model : โ
* @param board
* @return
* @throws Exception
*/
@PostMapping(value="/insert")
public String insertPro(@ModelAttribute Board board) throws Exception {
// @ModelAttribute : ๋ชจ๋ธ์ ์๋์ผ๋ก ๋ฑ๋กํด์ฃผ๋ ์ด๋
ธํ
์ด์
// ๋ฐ์ดํฐ ์ฒ๋ฆฌ
int result = new Random().nextInt(2);
// ๊ฒ์๊ธ ์ฐ๊ธฐ ์คํจ โก ๊ฒ์๊ธ ์ฐ๊ธฐ ํ๋ฉด
if( result == 0 ) return "redirect:/board/insert";
// ๋ทฐ ํ์ด์ง ์ง์
return "redirect:/board/list";
}
Java
๋ณต์ฌ
๊ฒ์๊ธ ์์ ์ฒ๋ฆฌ
๊ฒ์๊ธ ๋ชฉ๋ก (redierct)
/**
* ๊ฒ์๊ธ ์์ ์ฒ๋ฆฌ
* [POST]
* /board/update
* model : board
* @param board
* @return
* @throws Exception
*/
@PostMapping(value="/update")
public String updatePro(Board board) throws Exception {
// ๋ฐ์ดํฐ ์ฒ๋ฆฌ
int result = new Random().nextInt(2);
int boardNo = board.getBoardNo();
// ๊ฒ์๊ธ ์์ ์คํจ โก ๊ฒ์๊ธ ์์ ํ๋ฉด
if( result == 0 ) return "redirect:/board/update?boardNo=" + boardNo;
// ๋ทฐ ํ์ด์ง ์ง์
return "redirect:/board/list";
}
Java
๋ณต์ฌ
๊ฒ์๊ธ ์ญ์ ์ฒ๋ฆฌ
๊ฒ์๊ธ ๋ชฉ๋ก (redierct)
/**
* ๊ฒ์๊ธ ์ญ์ ์ฒ๋ฆฌ
* [POST]
* /board/delete
* model : โ
* @param boardNo
* @return
* @throws Exception
*/
@PostMapping(value="/delete")
public String deletePro(int boardNo) throws Exception {
// ๋ฐ์ดํฐ ์ฒ๋ฆฌ
int result = new Random().nextInt(2);
// ๊ฒ์๊ธ ์ญ์ ์คํจ โก ๊ฒ์๊ธ ์์ ํ๋ฉด
if( result == 0 ) return "redirect:/board/update?boardNo=" + boardNo;
// ๋ทฐ ํ์ด์ง ์ง์
return "redirect:/board/list";
}
Java
๋ณต์ฌ
์ด๋ฏธ์ง ์๋ต (์ธ๋ค์ผ)
์ด๋ฏธ์ง ์๋ต ํค๋
โข
ContentType : image/*
๋ฐ์ดํฐ๊ฐ ์ด๋ฏธ์ง๋ก ์๋ต๋๋ ค๋ฉด Content-Type ์๋ต ํค๋์ ๊ฐ์ image/*์ ํํ ์ง์ ํด์ผํฉ๋๋ค.
์ผ๋ฐ์ ์ผ๋ก ์ด๋ฏธ์ง๋ฅผ HTTP ์๋ต์ผ๋ก ๋ฐํํ ๋ Content-Type ํค๋๋ image/*์ ํํ๋ฅผ ์ทจํ๊ฒ ๋ฉ๋๋ค. ํ์ง๋ง ์ ํํ Content-Type ํค๋๋ ํด๋น ์ด๋ฏธ์ง ์ ํ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋๋ค. ์ด๋ฏธ์ง ํฌ๋งท์ ๋ฐ๋ผ ์ ์ ํ Content-Type์ ์ค์ ํด์ผ ํฉ๋๋ค.
โข
JPEG ์ด๋ฏธ์ง์ Content-Type: image/jpeg
โข
PNG ์ด๋ฏธ์ง์ Content-Type: image/png
โข
GIF ์ด๋ฏธ์ง์ Content-Type: image/gif
โข
WEBP ์ด๋ฏธ์ง์ Content-Type: image/webp
์ด๋ฏธ์ง ์๋ต ๋ฐฉ๋ฒ
โข
ResponseEntity<byte[]> ์๋ต ํ์
์ผ๋ก ์๋ตํ๊ธฐ
โข
HttpServletResponse, FileCopyUtils ๊ฐ์ฒด๋ฅผ ์ด์ฉํ์ฌ ์๋ตํ๊ธฐ
ResponseEntity<byte[]> ์๋ต ํ์ ์ผ๋ก ์๋ตํ๊ธฐ
ResponseEntity<byte[]>
/**
* ๐ ResponseEntity<byte[]>
* @return
* @throws IOException
*/
@GetMapping("/img")
public ResponseEntity<byte[]> thumbnailImg() throws IOException {
log.info("[GET] - /img");
// ์ด๋ฏธ์ง ํ์ผ์ ์ฝ์ด์ด
ClassPathResource imgFile = new ClassPathResource("sample.png");
byte[] bytes = Files.readAllBytes(imgFile.getFile().toPath());
// ์ด๋ฏธ์ง ํ์ผ์ ์ฝ์ด์ ์๋ต
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
}
Java
๋ณต์ฌ
HttpServletResponse, FileCopyUtils ๊ฐ์ฒด๋ฅผ ์ด์ฉํ์ฌ ์๋ตํ๊ธฐ
HttpServletResponse, FileCopyUtils
โข
Controller - showImg()
/**
* ์ด๋ฏธ์ง ์ธ๋ค์ผ
* @param filePath
* @param response
* @throws Exception
*/
@GetMapping("/img")
public void showImg(String filePath
,HttpServletResponse response ) throws Exception {
log.info("filePath : " + filePath);
File file = new File(filePath);
FileInputStream fis = new FileInputStream(file);
ServletOutputStream sos = response.getOutputStream();
FileCopyUtils.copy(fis, sos);
// filePath : C:/KHM/upload/[UID]_๊ฐ์์ง.png
// ์ด๋ฏธ์ง ์ปจํ
ํธ ํ์
ํ์ธ ( .jpg, .png, .gif, ... )
String ext = filePath.substring( filePath.lastIndexOf(".") + 1 ); // ํ์ฅ์
MediaType mType = MediaUtil.getMediaType(ext);
// ์ด๋ฏธ์ง ํ์
์ด ์๋ ๊ฒฝ์ฐ
if( mType == null ) {
return;
}
log.info("mType : " + mType);
response.setContentType( mType.toString() );
}
Java
๋ณต์ฌ
โข
MediaUtil.java
/**
* ํ์ฅ์๋ก ์ปจํ
ํธํ์
๋งคํ
* @author h
*
*/
public class MediaUtil {
private static Map<String, MediaType> mediaType;
static {
mediaType = new HashMap<String, MediaType>();
mediaType.put("JPG", MediaType.IMAGE_JPEG);
mediaType.put("JPEG", MediaType.IMAGE_JPEG);
mediaType.put("GIF", MediaType.IMAGE_GIF);
mediaType.put("PNG", MediaType.IMAGE_PNG);
mediaType.put("WEBP", MediaType.parseMediaType("img/webp") ); // MediaType.IMAGE_WEBP ์์๋ ์กด์ฌํ์ง ์์
}
// ํ์ฅ์๋ก ์ปจํ
ํธํ์
์ ํ์ธํ๋ ๋ฉ์๋
public static MediaType getMediaType(String ext) {
return mediaType.get(ext.toUpperCase());
}
}
Java
๋ณต์ฌ
HttpServletResponse
HTTP ์๋ต์ ํด๋ผ์ด์ธํธ์๊ฒ ๋ณด๋ด๊ธฐ ์ํ HTTP ์๋ธ๋ฆฟ ์๋ต์ ๋ํ๋
๋๋ค. ์ด ๊ฐ์ฒด๋ ์๋ธ๋ฆฟ์์ ํด๋ผ์ด์ธํธ๋ก ์ ์ก๋๋ ์๋ต์ ์ ์ดํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
1.
HTTP ์๋ต ์ค์ : HTTP ์๋ต์ ์์ฑ ์ค์ . ์๋ฅผ ๋ค์ด, ์ฝํ
์ธ ์ ํ(Content-Type), ์บ์ ์ ์ด, ์๋ต ์ฝ๋ ๋ฐ ๋ฉ์์ง ๋ฑ์ ์ค์ ํ ์ ์์ต๋๋ค.
2.
์๋ต ํค๋ ์ค์ : HTTP ์๋ต์ ํค๋ ์ค์ . setHeader() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ํน์ ํค๋ ๊ฐ์ ์ค์ ํ ์ ์์ต๋๋ค.
3.
์ฟ ํค ์ค์ : ํด๋ผ์ด์ธํธ๋ก ์ฟ ํค๋ฅผ ์ ์กํ๊ธฐ ์ํด addCookie() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
โข
์ฃผ์ ๋ฉ์๋
๋ฉ์๋ | ์ค๋ช
|
setContentType(String type) | ์๋ต์ ์ฝํ
์ธ ์ ํ์ ์ค์ ํฉ๋๋ค. |
setStatus(int sc) | ์๋ต ์ฝ๋๋ฅผ ์ค์ ํฉ๋๋ค. |
setHeader(String name, String value) | ์ง์ ๋ ํค๋ ๊ฐ์ ์ค์ ํฉ๋๋ค. |
addCookie(Cookie cookie) | ์ฟ ํค๋ฅผ ์๋ต์ ์ถ๊ฐํฉ๋๋ค. |
FileCopyUtils
Spring ํ๋ ์์ํฌ์์ ํ์ผ ๋ณต์ฌ์ ์ฌ์ฉ๋๋ ์ ํธ๋ฆฌํฐ ํด๋์ค์
๋๋ค. ์ด ํด๋์ค๋ ์คํธ๋ฆผ ๋๋ ๋ฆฌ์์ค์์ ํ์ผ์ ์ฝ๊ณ ์ฐ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
โข
์ฃผ์ ๋ฉ์๋
๋ฉ์๋ | ์ค๋ช
|
copy() | ํ์ผ, ์คํธ๋ฆผ, ๋ฐ์ดํธ ๋ฐฐ์ด ๋ฑ ๊ฐ์ ๋ณต์ฌ ์์
์ ์ํํฉ๋๋ค. |
copy(byte[] in, byte[] out) | ์
๋ ฅ byte[]์์ ์ถ๋ ฅ byte[]๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณต์ฌํฉ๋๋ค. |
copy(InputStream in, OutputStream out) | InputStream์์ OutputStream์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณต์ฌํฉ๋๋ค. |
copy(Resource in, File out) | Resource์์ File๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณต์ฌํฉ๋๋ค. |
ํ์ผ ์๋ต (๋ค์ด๋ก๋)
ํ์ผ ๋ค์ด๋ก๋ ์๋ต ํค๋
โข
Content-Type : application/octet-stream
โข
Content-Disposition : form-data; name="attachment"; filename="sample.pngโ
ํ์ผ ๋ค์ด๋ก๋๋ฅผ ์ํด, Content-Type ์๋ต ํค๋์ ๊ฐ์ application/octet-stream ์ ํํ ์ง์ ํด์ผํฉ๋๋ค. Content-Disposition ์๋ต ํค๋์ ๊ฐ์ name="attachment"; filename="sample.pngโ ํํ๋ก ์ง์ ํด์ผํฉ๋๋ค.
ํ์ผ ๋ค์ด๋ก๋ ๊ตฌํ ๋ฐฉ๋ฒ
โข
ResponseEntity<byte[]> ์๋ต ํ์
์ผ๋ก ์๋ตํ๊ธฐ
โข
HttpServletResponse, FileCopyUtils ๊ฐ์ฒด๋ฅผ ์ด์ฉํ์ฌ ์๋ตํ๊ธฐ
ResponseEntity<byte[]>
โข
Content-Type : application/octet-stream
โข
Content-Disposition : form-data; name="attachment"; filename="sample.pngโ
/**
* ๐ ResponseEntity<byte[]>
* @return
* @throws IOException
*/
@GetMapping("/img")
public ResponseEntity<byte[]> thumbnailImg() throws IOException {
log.info("[GET] - /img");
// ์ด๋ฏธ์ง ํ์ผ์ ์ฝ์ด์ด
ClassPathResource imgFile = new ClassPathResource("sample.png");
byte[] bytes = Files.readAllBytes(imgFile.getFile().toPath());
// ์ด๋ฏธ์ง ํ์ผ์ ์ฝ์ด์ ์๋ต
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
}
Java
๋ณต์ฌ
HttpServletResponse, FileCopyUtils
/**
* ํ์ผ ๋ค์ด๋ก๋
* @param fileNo
* @param response
* @throws Exception
*/
@GetMapping("/{fileNo}")
public void fileDownload(@PathVariable("fileNo") int fileNo
,HttpServletResponse response) throws Exception {
// ํ์ผ ์กฐํ
Files file = fileService.read(fileNo);
// ํ์ผ์ด ์กด์ฌํ์ง ์์ผ๋ฉด,
if( file == null ) {
// ์๋ต ์ํ์ฝ๋ : 400, ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์๋ชป๋์์์ ๋ํ๋ด๋ ์ํ์ฝ๋
response.setStatus(response.SC_BAD_REQUEST);
return;
}
String fileName = file.getFileName(); // ํ์ผ ๋ช
String filePath = file.getFilePath(); // ํ์ผ ๊ฒฝ๋ก
// ํ์ผ ๋ค์ด๋ก๋๋ฅผ ์ํ ํค๋ ์ธํ
// - ContentType : application/octet-straem
// - Content-Disposition : attachment; fileanme="ํ์ผ๋ช
.ํ์ฅ์"
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// ํ์ผ ์
๋ ฅ
File downloadFile = new File(filePath);
FileInputStream fis = new FileInputStream(downloadFile);
ServletOutputStream sos = response.getOutputStream();
// ๋ค์ด๋ก๋
FileCopyUtils.copy(fis, sos);
}
Java
๋ณต์ฌ
API ๊ฐ๋ฐ ๋ฌธ์ํ ๋๊ตฌ
: API ๊ฐ๋ฐ ๋ฌธ์ํ ๋๊ตฌ๋ API ์๋ํฌ์ธํธ, ์์ฒญ, ์๋ต ๋ฐ ๊ด๋ จ ์ ๋ณด๋ฅผ ๋ฌธ์ํํ์ฌ ๊ฐ๋ฐ์๋ค์๊ฒ API ์ฌ์ฉ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ ์ํํธ์จ์ด ๋๊ตฌ์
๋๋ค.
์ข ๋ฅ
โข
Swagger
Swagger (OpenAPI)
REST API๋ฅผ ์ค๊ณ, ๊ตฌ์ถ, ๋ฌธ์ํ ๋ฐ ์ฌ์ฉํ๋ ๋ฐ ๋์์ด ๋ ์ ์๋ OpenAPI ์ฌ์์ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ถ๋ ์คํ ์์ค ๋๊ตฌ ์ธํธ์
๋๋ค.
https://swagger.io/docs/specification/about/
โข
API ์ค๊ณ, ๋น๋, ๋ฌธ์ํ ๋ฐ ํ
์คํธ๋ฅผ ์ํ ํตํฉ ํด.
โข
OpenAPI ํ์ค์ ์ค์ํ๋ฉฐ, RESTful API๋ฅผ ์ฝ๊ฒ ๋์์ธํ๊ณ ๊ด๋ฆฌํ ์ ์์.