인프런 김영한 님의 스프링 강의이며, 섹션 6 - 스프링 MVC 기본 기능을 정리하는 시간이다.
자세한 설명이 궁금하면 수강을 권장한다.
스프링 MVC 기본 기능 -프로젝트 세팅
start.spring.io 에서 다음과 같이 세팅한다.
Project: Gradle Project
Language: Java Spring Boot: 2.4.x
Project Metadata
Group: hello
Artifact: springmvc
Name: springmvc
Package name: hello.springmvc
Packaging: Jar
Java: 11
Dependencies: Spring Web, Thymeleaf, Lombok
War가 아닌 Jar로 진행하는 이유는 JSP를 사용하지 않기 때문이다.
Jar를 사용하면 내장 서버(톰캣)을 사용하고, webapp 경로도 사용하지 않는다.
Jar는 내장 서버에 최적화된 기능이다.
War도 사용 가능하지만, 주로 외부 서버 배포하는 목적으로 사용한다.
스프링 MVC 기본 기능 - 로깅 간단히 알아보기
이전까지 System.out.print() 시스템 콘솔로 정보를 출력했지만, 이제는 별도의 로깅 라이브러리로 로그를 출력해보자.
로그 라이브러리도 내용이 끝이 없기 때문에 간단히 사용방법만 알고 넘어간다.
스프링 부트 라이브러리를 사용하면 기본적으로 로깅 라이브러리가 포함되어있다.
이제 코드를 작성해보자.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class LogTestController {
private final Logger log = LoggerFactory.getLogger(LogTestController.class);
@RequestMapping("/log-test")
public String logTest() {
String name = "spring";
log.info("name = " + name);
return "ok";
}
}
Logger와 LoogerFactory는 org.slf4j 패키지에 있는 걸 사용한다.
@Controller 대신 @RestController가 사용되었다. 차이점은 @Controller는 반환되는 값으로 뷰를 찾고 뷰가 렌더링 되지만
@RestController는 반환 값으로 HTTP 메시지 바디에 바로 입력해준다. @RequestBody와 관련 있지만 다음 시간에 배운다.
이제 해당 경로를 호출해보자
log.info 값이 찍힌걸 볼 수 있고, 뷰네임 대신 String 값으로 ok가 반환된 걸 볼 수 있다.
log 기능을 확인해보자.
@RequestMapping("/log-test")
public String logTest() {
String name = "spring";
log.trace("trace log={}", name);
log.debug("debug log={}", name);
log.info(" info log={}", name);
log.warn(" warn log={}", name);
log.error("error log={}", name);
return "ok";
}
trace와 debug가 찍히지 않았다.
로그 level은 trace, debug, info, warn, error 순서로 있으며 디폴트로 info로 지정되어있다.
바꾸려면 application.properties 에서 설정한다.
#hello.springmvc 패키지와 그 하위 로그 레벨 설정
logging.level.hello.springmvc=trace
그리고 처음에 log.info("name = " + name)로 사용했지만 그 다음부터는 log.info("name = {}", name)으로 사용했다.
그 이유는 ("name = " + name) 방식은 문자 더하기 연산이 발생하기 때문이고, name = {}은 연산이 일어나지 않는다.
즉, 연산이 일어나면 쓸모없는 리소스를 사용하기 때문에 log.info("name = {}", name)을 사용해야 한다.
전체 패키지에 로그 레벨을 설정할 수도 있다. debug로 변경하고 실행 보자.
# 전체 로그 레벨 설정 (기본 info)
logging.level.root=debug
#hello.springmvc 패키지와 그 하위 로그 레벨 설정, root보다 우선권이 높다.
logging.level.hello.springmvc=info
엄청난 DEBUG 로그가 출력된다. 스프링의 구성요소마다 로그가 세팅된 걸 알 수 있다.
로그를 사용할 때 클래스마다 아래의 코드를 선언해야 할까?
private final Logger log = LoggerFactory.getLogger(??.class);
이전과 마찬가지로 로그를 편안하게 사용할 수 있는 기능이 존재한다.
@Slf4j
@RestController
public class LogTestController {
// private final Logger log = LoggerFactory.getLogger(LogTestController.class);
...
}
@Slf4j 를 사용하면 된다.
로그의 장점
- 쓰레드 정보, 클래스 정보를 볼 수 있고 출력 모양을 조정할 수 있다.
- 로그 레벨 제어로 상황에 맞게 로그를 출력할 수 있다.
- System.out.println()은 시스템 콘솔에만 출력되지만 로그는 파일, 네트워크, 디비 등 별도의 위치에 남길 수 있고, 시간이나 용량에 따라 분할도 가능하다.
- 성능이 일반 System.out보다 좋기 때문에 실무에서 사용한다.
더 알아보려면
SLF4J, Logback을 검색하거나 아래의 주소에서 참고
스프링 MVC 기본 기능 - 요청 매핑
매핑 기능에 대해 알아보자.
간단한 컨트롤러를 하나 선언한다.
@Slf4j
@RestController
public class MappingController {
@RequestMapping("/hello-basic")
public String helloBasic() {
log.info("hello baisc");
return "ok";
}
}
localhost:8080/hello-basic을 호출하면 ok가 잘 반환된다.
매핑에는 여러 가지 기능이 존재한다. 그중 배열로 하나의 메서드를 실행하게 할 수 있다.
@RequestMapping({"/hello-basic", "/hello-go"})
public String helloBasic() {
log.info("hello baisc");
return "ok";
}
HTTP 메서드
매핑에 method 속성이 존재하는데, 없으면 GET, POST 무관하게 호출이 된다.
HTTP 메서드 매핑은 다음과 같다
@Slf4j
@RestController
public class MappingController {
...
// HTTP 매핑
@RequestMapping(value = "/mapping-get-v1", method = RequestMethod.GET)
public String mappingGetV1() {
log.info("mappingGetV1");
return "ok";
}
}
하지만 경로와 HTTP를 매핑도 반복되어 단축된 방법도 있다.
HTTP 매핑 메서드 축약
/**
* 편리한 축약 애노테이션 (코드보기) * @GetMapping
* @PostMapping
* @PutMapping
* @DeleteMapping
* @PatchMapping
*/
@GetMapping(value = "/mapping-get-v2")
public String mappingGetV2() {
log.info("mapping-get-v2");
return "ok";
}
해당 매핑 메서드 내부를 보면 RequestMethod.??를 볼 수 있다.
PathVariable(경로 변수) 사용
/**
* PathVariable 사용
* 변수명이 같으면 생략 가능
* @PathVariable("userId") String userId -> @PathVariable userId */
@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable("userId") String data) {
log.info("mappingPath userId={}", data);
return "ok";
}
경로를 값으로 이용한다.
localhost:8080/mapping/100
@PathVariable의 이름과 변수명이 같으면 생략할 수 있다.
@PathVariable("userId") String userId -> @PathVariable String userId
PathVariable 다중 사용
경로 변수를 다중으로 지정할 수 있다.
/**
* PathVariable 사용 다중
*/
@GetMapping("/mapping/users/{userId}/orders/{orderId}")
public String mappingPath(@PathVariable String userId, @PathVariable Long
orderId) {
log.info("mappingPath userId={}, orderId={}", userId, orderId);
return "ok";
}
위와 동일한 방법으로 호출하면 된다.
파라미터 추가 매핑
@GetMapping(value = "/mapping-param", params = "mode=debug")
public String mappingParam() {
log.info("mappingParam");
return "ok";
}
특정 파라미터와 값이 존재해야 해당 메서드가 호출이 된다.
지금은 잘 사용 안 하는 방식이라 한다.
특정 헤더로 추가 매핑
/**
* 특정 헤더로 추가 매핑
* headers="mode",
* headers="!mode"
* headers="mode=debug"
* headers="mode!=debug" (! = )
*/
@GetMapping(value = "/mapping-header", headers = "mode=debug")
public String mappingHeader() {
log.info("mappingHeader");
return "ok";
}
위와 같으며, 헤더로 넘어온 값으로 확인한다. 확인하려면 postman을 사용해야 한다.
Content-type 헤더 기반 추가 매핑
/**
* Content-Type 헤더 기반 추가 매핑 Media Type * consumes="application/json"
* consumes="!application/json"
* consumes="application/*"
* consumes="*\/*"
* MediaType.APPLICATION_JSON_VALUE */
@PostMapping(value = "/mapping-consume", consumes = "application/json")
public String mappingConsumes() {
log.info("mappingConsumes");
return "ok";
}
Accept 헤더 기반 Media Type
/**
* Accept 헤더 기반 Media Type
* produces = "text/html"
* produces = "!text/html" * produces = "text/*"
* produces = "*\/*"
*/
@PostMapping(value = "/mapping-produce", produces = "text/html")
public String mappingProduces() {
log.info("mappingProduces");
return "ok";
}
이것도 위와 같다.
스프링 MVC 기본 기능 - 요청 매핑, API 예시
경로 변수를 이용하여 어떻게 HTTP API를 만드는지 확인해보자.
회원관리 API를 간단히 만들어 본다.
@RestController
@RequestMapping("/mapping/users")
public class MappingClassController {
/**
* 회원 관리 API
* 회원 목록 조회: GET /users
* 회원 등록: POST /users
* 회원 조회: GET /users/{userId}
* 회원 수정: PATCH /users/{userId}
* 회원 삭제: DELETE /users/{userId}
*/
@GetMapping
public String user() {
return "get users";
};
@PostMapping
public String addUser() {
return "post user";
};
@GetMapping("/{userId}")
public String findUser(@PathVariable String userId) {
return "get userId = " + userId;
};
@PatchMapping("/{userId}")
public String updateUser(@PathVariable String userId) {
return "update userId = " + userId;
};
@DeleteMapping("/{userId}")
public String deleteUser(@PathVariable String userId) {
return "delete userId = " + userId;
};
}
postman을 이용하여 확인한다.
'교육 및 인강 > 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술' 카테고리의 다른 글
스프링 MVC 기본 기능, HTTP 요청 메시지 - 단순 텍스트, JSON (0) | 2021.07.20 |
---|---|
스프링 MVC 기본 기능, HTTP 요청 - 기본, 헤더 조회, 파라미터 (0) | 2021.07.20 |
스프링 MVC 이해 - 시작하기, 컨트롤러 통합, 실용적인 방식 (0) | 2021.07.19 |
스프링 MVC 이해 - 전체 구조, 핸들러 매핑과 핸들러 어댑터, 뷰 리졸버 (0) | 2021.07.13 |
MVC 프레임워크 만들기 - 실용적인 컨트롤러 (v4), 유연한 컨트롤러 (v5) (0) | 2021.07.13 |