#1 HTTP ์์ฒญ ๋งคํ๊ณผ ๊ธฐ๋ณธ ๋ก๊น
by JiwonDev# ๊ฐ๋จํ Logging (@Slf4j)
์น ์๋ฒ์์๋ System.out.println์ผ๋ก ๋ก๊ทธ๋ฅผ ์ฐ๊ธฐ์๋ ๋ฌด๋ฆฌ๊ฐ ์๋ค. ์คํ๋ง๋ถํธ์ ํฌํจ๋ ๋ก๊น ๋ผ์ด๋ธ๋ฌ๋ฆฌ (slf4j)๋ฅผ ๊ฐ๋จํ๊ฒ๋ง ๋ฐฐ์๋ณด์. ์ฐธ๊ณ ๋ก slf4j๋ Logback, Log4J, Log4J2 ๋ฑ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํตํฉํด์ ์ฌ์ฉํ ์ ์๋๋ก ๋ง๋ ์ธํฐํ์ด์ค์ด๋ค. ์คํ๋ง ํ๋ ์์ํฌ์์๋ Logback์ ๊ธฐ๋ณธ์ผ๋ก ์ง์ํ๊ณ ์๋ค.
- SLF4J (์ธํฐํ์ด์ค) - http://www.slf4j.org
- Logback (๊ตฌํ์ฒด) - http://logback.qos.ch
(์ฐธ๊ณ ) @Controller์ @RestController์ ์ฐจ์ด
@Controller ๋ ๋ฐํ ๊ฐ์ด String ์ด๋ฉด ๋ทฐ ์ด๋ฆ์ผ๋ก ์ธ์๋๋ค. ๊ทธ๋์ ๋ทฐ๋ฅผ ์ฐพ๊ณ ๋ทฐ๊ฐ ๋๋๋ง ๋๋ค.
@RestController ๋ ๋ฐํ ๊ฐ์ผ๋ก ๋ทฐ๋ฅผ ์ฐพ๋ ๊ฒ์ด ์๋๋ผ, HTTP ๋ฉ์์ง ๋ฐ๋์ ๋ฐ๋ก ์ ๋ ฅํ๋ค.
์ด๋ REST API์ ์ฃผ๋ก ์ฌ์ฉ๋๋ฉฐ @ResponseBody ์ ๊ด๋ จ์ด ์๋๋ฐ, ๋์ค์ ์ถ๊ฐ๋ก ์ค๋ช ํ๋๋ก ํ๊ฒ ๋ค.
// @Controller ๋ฐํ ๊ฐ์ View ์ด๋ฆ์ผ๋ก ์ทจ๊ธํ๊ณ , ํด๋น View ๋ฅผ ์ฐพ์ ๋ฐํ๋๋ค.
@RestController // ๋ฐํ ๊ฐ์ ๋ฌธ์์ด ๊ทธ๋๋ก ์ ๋ฌํ๋ค. ๋ณดํต REST API์ ์ฌ์ฉ๋๋ค.
public class LogTestController {
private final Logger log = LoggerFactory.getLogger(getClass());
// ๋ค๋ฅธ ํด๋์ค๋ฅผ Logger ์ ๋ฑ๋กํ๊ณ ์ถ์ ๊ฒฝ์ฐ ์๋์ ๊ฐ์ด ํ๋ฉด ๋๋ค.
// private static final Logger log = LoggerFactory.getLogger(Xxx.class)
@RequestMapping("/log-test")
public String logTest() {
String name = "Spring";
// ๋ก๊ทธ ๋ ๋ฒจ์ ์ง์ ํ ์ ์๋ค.
// TRACE > DEBUG > INFO(๊ธฐ๋ณธ ๊ฐ) > WARN > ERROR
log.trace("lv 1์ถ์ log={}", name);
log.debug("lv 2๋๋ฒ๊ทธ log={}", name);
log.info(" lv 3์ ๋ณด log={}", name);
log.warn(" lv 4๊ฒฝ๊ณ log={}", name);
log.error("lv 5์๋ฌ log={}", name);
// ์ฐธ๊ณ ๋ก ์๋์ ๊ฐ์ด String ๋ง์
์ฐ์ฐ์ ์ฌ์ฉํ๋ฉด ์๋๋ค.
// ์ด๋ JAVA์ String ์ฐ์ฐ๊ณผ ๊ด๋ จ์ด ์๋ค. ์คํธ๋ง ๋ง์
์ ๊ฐ์ฒด๊ฐ ๋ก๋ฉ ๋ ๋ ๋ฏธ๋ฆฌ ์คํ๋์ด ์ต์ ํ๋๋ค.
// ์ฆ ๋ก๊ทธ๋ฅผ ์ฌ์ฉํ์ง ์์๋ a+b ๊ณ์ฐ ๋ก์ง์ด ์คํ๋๋ฉฐ ๋ฆฌ์์ค๋ฅผ ๋ญ๋นํ๊ธฐ ๋๋ฌธ์ด๋ค.
// log.debug("String concat log=" + name);
return "ok";
}
}
์ฐธ๊ณ ๋ก lombok์ ์๋ @Slf4j ๋ฅผ ์ฌ์ฉํ๋ฉด Logger๋ฅผ ๋ฑ๋กํ๋ ์ฝ๋๋ฅผ ์๋ตํ ์ ์๋ค.
@Slf4j
@RestController
public class LogTestController {
// Logger ์์ฑ์ฝ๋ ํ์์์. lombok์ด ์์ฑ
@RequestMapping("/log-test")
public String logTest() {...}
}
2021-08-11 07:14:16.825 WARN 23784 --- [nio-8080-exec-1] hello.myClass : ๊ฒฝ๊ณ log=Spring
2021-08-11 07:14:16.825 ์ข
๋ฅ ํ๋ก์ธ์คID --- [์ค๋ ๋ ์ด๋ฆ] Controller ํด๋์ค : ๋ฉ์์ง
์ฐธ๊ณ ๋ก ์ค์ ํ ๋ก๊ทธ๋ ๋ฒจ (debug, info)๋ ์ค์ ์ ํตํด ํน์ ๋ก๊ทธ ๋ ๋ฒจ๋ง ์จ๊ธฐ๊ฑฐ๋ ๋ณด์ด๊ฒ ํ ์ ์๋ค. ๋น์ฐํ ๊ฑฐ์ง๋ง ๋๋ฒ๊น ํ ๋ ํ์ํ ์ ๋ณด๋ฅผ ์ด์ ์๋ฒ์ ๋์ฐ๋ฉด ์์ฒญ์ ๋ฐ๋ผ ์์ฒญ๋ ๋์ ์ธ๋ชจ์๋ ๋ก๊ทธ๊ฐ ์ถ๋ ฅ๋จ์ ์ ์ํ์.
# resources/application.yaml
# ์ ์ฒด ๋ก๊ทธ๋ ๋ฒจ
logging.level.root = info
# ํน์ ํจํค์ง๋ง ์ ์ฉ
logging.level.hello.package = debug
@ ์ฝ์์ ์ฐ๋ ๊ฑฐ๋ ๋ญ๊ฐ ๋ค๋ฅด์ฃ ?
- ์ฐ๋ ๋ ์ ๋ณด, ํด๋์ค ์ด๋ฆ ๊ฐ์ ๋ถ๊ฐ ์ ๋ณด๋ฅผ ํจ๊ป ๋ณผ ์ ์๊ณ , ์ถ๋ ฅ ๋ชจ์์ ์กฐ์ ํ ์ ์๋ค.
- ๋ก๊ทธ ๋ ๋ฒจ์ ์ง์ ํด ์ด์์๋ฒ์์๋ ์ถ๋ ฅํ์ง ์๋ ๋ฑ ๋ก๊ทธ๋ฅผ ์ํฉ์ ๋ง๊ฒ ์กฐ์ ํ ์ ์๋ค.
- ์์คํ ์์ ์ฝ์์๋ง ์ถ๋ ฅํ๋ ๊ฒ์ด ์๋๋ผ, ํ์ผ์ด๋ ๋คํธ์ํฌ ๋ฑ, ๋ก๊ทธ๋ฅผ ๋ณ๋์ ์์น์ ๋จ๊ธธ ์ ์๋ค.
- ํนํ ํ์ผ๋ก ๋จ๊ธธ ๋๋ ์ผ๋ณ, ํน์ ์ฉ๋์ ๋ฐ๋ผ ๋ก๊ทธ๋ฅผ ๋ถํ ํ๋ ๊ฒ๋ ๊ฐ๋ฅํ๋ค.
- ์ฑ๋ฅ๋ ์ผ๋ฐ System.out๋ณด๋ค ์์ญ ๋ฐฐ๋ ์ข๋ค. (๋ด๋ถ ๋ฒํผ๋ง, ๋ฉํฐ ์ฐ๋ ๋ ๋ฑ๋ฑ)
๋ก๊น ๊ธฐ๋ฅ์ ๊ฐ๋จํ๊ฒ ์ค๋ช ํ์ง๋ง, ๊น๊ฒ ๋ค์ด๊ฐ๋ฉด ์ด๊ฒ๋ ๊ณต๋ถํ ๋ด์ฉ์ด ๋ง๋ค. ์ผ๋จ์ ์ด ์ ๋๋ง ์๊ณ ๋์ด๊ฐ๋๋ก ํ์.
# ์์ฒญ ๋งคํํ๊ธฐ (@Controller)
์์ฒญ์ด ์์ ๋ ์ด๋ค ์คํ๋ง ๋น(์๋ธ๋ฆฟ ์ญํ )์ด ์คํ๋์ด์ผ ํ๋๊ฐ?
- @Controller ๋ ๋ฐํ ๊ฐ์ด String ์ด๋ฉด ๋ทฐ ์ด๋ฆ์ผ๋ก ์ธ์๋๋ค. ๊ทธ๋์ ๋ทฐ๋ฅผ ์ฐพ๊ณ ๋ทฐ๊ฐ ๋๋๋ง ๋๋ค.
- @RestController ๋ ๋ฐํ ๊ฐ์ผ๋ก ๋ทฐ๋ฅผ ์ฐพ๋ ๊ฒ์ด ์๋๋ผ, HTTP ๋ฉ์์ง ๋ฐ๋์ ๋ฐ๋ก ์ ๋ ฅํ๋ค.
์ฐ๋ฆฌ๋ ๋ง๋ค์ด๋ View(HTML ๋๋ ํ ํ๋ฆฟ)๊ฐ ์์ผ๋ฏ๋ก, @RestContoller๋ฅผ ํตํด ๋งคํ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์.
์ฐธ๊ณ ๋ก jiwon.com/hello ์ jiwon.com/hello/ ๋ HTTP์์ผ๋ก ๋ค๋ฅธ ์์ฒญ์ด์ง๋ง, ์คํ๋ง์ ๊ฐ์ ์์ฒญ์ผ๋ก ๋งคํํ๋ค.
@Slf4j
@RestController
public class MappingController {
// ์ฌ๋ฌ ๊ฐ๋ฅผ ๋งคํ ํ๊ณ ์ถ๋ค๋ฉด ({"/hello1" , "/hello2"})
@RequestMapping("/hello-basic")
public String helloBasic() {
log.info("helloBasic");
return "ok";
}
}
์์ ๊ฐ์ด HTTP Method๋ฅผ ์ง์ ํ์ง ์์ผ๋ฉด ๋ชจ๋ ์์ฒญ(GET, HEAD, POST..)๋ฅผ ๋ค ๋ฐ์๋ค์ธ๋ค. ์๋์ ๊ฐ์ด ์ง์ ํด์ฃผ์.
@RequestMapping("/mapping-get-v1", method = RequestMethod.GET)
public String mappingGetV1() {
log.info("mappingGetV1");
return "ok";
}
์ข ๋ ์ง๊ด์ ์ผ๋ก ์ฌ์ฉํ๊ธฐ ์ํด์ ์คํ๋ง์์๋ ์ถ์ฝํ(@GetMapping, @PostMapping)๋ ์ ๊ณตํ๋ค. ๋์์ ์์ ๊ฐ๋ค.
@GetMapping("/mapping-get-v2")
public String mappingGetV1() {
log.info("mappingGetV1");
return "ok";
}
์ฐธ๊ณ ๋ก ์๋ชป๋ ๋ฉ์๋๋ก ์์ฒญํ๋ ๊ฒฝ์ฐ ์คํ๋ง์์ JSON ํ์์ผ๋ก ์ค๋ฅ๋ฅผ ๋ฐํํ๋๋ฐ, ์ด๋ RestContoller๋ฅผ ์ฌ์ฉํด์ ๊ทธ๋ ๋ค. ์ด๋ ๋์ค์ ์์ธ์ฒ๋ฆฌ๋ฅผ ๋ฐฐ์ฐ๋ฉฐ ์๊ฒ ๋๋ ์ผ๋จ ๋์ด๊ฐ๋๋ก ํ์.
@ PathVariable, ๊ฒฝ๋ก ๋ณ์
์์ฒญ ๋งคํ์ ๋ณ์๋ฅผ ํตํด ์ง์ ํ ์ ์๋ค. ์ง์ ํ๊ณ ์ถ์ ๋ณ์ ์์ @PathVariable("~")์ ์ ์ผ๋ฉด ๋๋ค. ์๋ ์๋ ํ๋ผ๋ฏธํฐ( a.com/hello?userId=3)๋ฅผ ๋ง์ด์ฌ์ฉํ๋๋ฐ, ์ต๊ทผ์ API๋ ์ด๋ ๊ฒ ์๋ณ์๋ฅผ ๋ฃ๋ ์คํ์ผ์ ๋ ์ ํธํ๋ค.
# ์ฟผ๋ฆฌ ํ๋ผ๋ฉํ
http://a.com/mapping?users=userA&orders=100
# http://a.com/mapping/users/{userId}/orders/{orderId}
http://a.com/mapping/users/userA/orders/100
@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable("userId") String data) {
log.info("mappingPath userId={}", data); // {userId}์ data๊ฐ ๋ค์ด๊ฐ๋ค.
return "ok";
}
// ์ฐธ๊ณ ๋ก {~}์ ๊ฐ์ ์ด๋ฆ์ ๋ณ์๋ฅผ ์ฌ์ฉํ๋ฉด, ์๋ตํด์ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable userId) {
log.info("mappingPath userId={}", data);
return "ok";
}
@ ํ๋ผ๋ฉํ ์กฐ๊ฑด ๋งคํ
์์ @PathVariable ๋๋ฌธ์ ์ ์ฌ์ฉํ์ง๋ ์์ง๋ง, ํน์ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๊ฐ ์์ ๋๋ง ์คํ๋๋๋ก ๋งคํํ ์ ์๋ค.
/**
* ํ๋ผ๋ฏธํฐ๋ก ์ถ๊ฐ ๋งคํ
* params="mode",
* params="!mode" (์ฃผ์ด์ง ๊ฐ์ด mode๊ฐ ์๋๋๋ง)
* params="mode=debug"
* params="mode!=debug" (mode=debug๊ฐ ์๋๋๋ง)
* params = {"mode=debug","data=good"}
*/
@GetMapping(value = "/mapping-param", params = "mode=debug")
public String mappingParam() {
log.info("mappingParam");
return "ok";
}
@ ๋ฏธ๋์ด ํ์ ์กฐ๊ฑด ๋งคํ
consumes ="~" ์ด์ฉํด์ HTTP ํค๋๋ฅผ ํ์ธํด ํน์ ๋ฐ์ดํฐ์ ํ์ ๋ง ๋ฐ๋๋ก ๋ง๋ค์๋ ์๋ค.
content-type์ด๋ผ๊ณ ์ ์ง ์๊ณ ์ปจ์์ ์ฌ์ฉํ๋ ์ด์ ๋ ์๋ฒ์์ ์ฌ์ฉํ๋(consumes) ๋ฐ์ดํฐ์ ์์ฐ(produces)ํ๋ ๋ฐ์ดํฐ ํ์ ์ ๋ฐ๋ก ์ง์ ํ๊ธฐ ์ํจ์ด๋ค.
/**
* Content-Type ํค๋ ๊ธฐ๋ฐ ์ถ๊ฐ ๋งคํ Media Type
* consumes = "text/plain"
* consumes ="!application/json" (Json์ด ์๋ ๋ฐ์ดํฐ๋ง ํ์ฉ)
* consumes = {"text/plain", "application/*"}
* consumes = MediaType.TEXT_PLAIN_VALUE (์์ ์ฌ์ฉ)
*/
@PostMapping(value = "/mapping-consume", consumes = "application/json")
public String mappingConsumes() {
log.info("mappingConsumes");
return "ok";
}
// ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ Accept ํค๋์ ๋น๊ตํด์ ๋์ํ๋ค. ๋ง์ฝ ๋ค๋ฅด๋ค๋ฉด 406 ์ค๋ฅ์ฝ๋๋ฅผ ๋ฐํํ๋ค.
@PostMapping(value = "/mapping-produce", produces = "text/html")
public String mappingProduces() {
log.info("mappingProduces");
return "ok";
}
'๐ฑ Spring Framework > Spring MVC' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Thymeleaf#2 Spring๊ณผ HTML Form ์ฒ๋ฆฌ (0) | 2021.08.28 |
---|---|
Thymeleaf#1 ๊ธฐ๋ณธ๊ธฐ๋ฅ (0) | 2021.08.28 |
#2 HTTP API ์์ฒญ ๋งคํ, ํค๋ ์กฐํ (0) | 2021.08.11 |
# HTTP ๋ฐ์ดํฐ ์ ์ก/์๋ต (0) | 2021.08.11 |
# Spring MVC๋ฅผ ๋ฐฐ์ฐ๊ธฐ ์ ์ (0) | 2021.08.11 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev