1. 개요
스프링을 공부하면서, 컨트롤러 작성 시 여러 어노테이션들을 배우게 되었다. 각각의 특징들을 간단하게나마 모두 정리하면 좋을 것 같아, 해당 게시물에서 최대한 나열해 보려고 한다.
목차
@Controller
@RestController
@RequestMapping()
@GetMapping(), @PostMapping(), ...
@ResponseBody
@RequestParam()
@ModelAttribute
@PathVariable()
HttpEntity, ResponseEntity
@RequestBody
@ResponseStatus(HttpStatus.OK)
RedirectAttributes
etc
2. @Controller
@Controller
public class MyMVCController {
}
@Controller는 MVC 패턴의 컨트롤러를 만들고 싶은 경우 주로 사용된다. 해당 어노테이션이 붙은 class를 스프링은 자동으로 스프링 빈으로 등록해준다(내부에 @Component 존재). 또한, 스프링 MVC에서 어노테이션 기반 컨트롤러로 인식한다.
@RequestMapping("/return-string")
public String returnString() {
return "response/hi";
}
만일 반환 값이 String이면, 이를 View 이름으로 자동인식하게 된다. 따라서 뷰를 찾고, 해당 뷰가 렌더링된다.
3. @RestController
@RestController
public class MyRestController {
}
Resfull한 컨트롤러 제작 시 사용되며, 클래스 레벨에 사용한다. 이는 뒤에서 언급할 @ResponseBody를 모든 메서드에 붙이는 효과를 가지고 있다.
@RequestMapping("return-rest")
public String returnRest() {
return "ok";
}
이 경우 메서드가 String 값을 반환하면, @Controller와 다르게 HTTP 메시지 바디에 값을 바로 입력한다.
4. @RequestMapping()
핸들러 매핑, 핸들러 어댑터의 첫 번째 우선순위로 찾는 방법이다. 메서드 레벨에 사용되며, 컨트롤러로 인식된다. 핸들러 매핑, 핸들러 어댑터와 관련된 내용은 아래 링크를 참고 부탁한다.
@RequestMapping("/v1/save")
public String save() {
}
괄호 안의 URL이 호출되면, 해당 어노테이션이 달린 메서드가 호출된다. 이는 어노테이션 기반이므로, 메서드 이름을 자유롭게 작성할 수 있다는 장점을 지니고 있다.
@RequestMapping(value = "/save", method = RequestMethod.GET)
위와 같은 방식으로 HTTP 메서드를 구분할 수 있다. 하지만, 아래의 방법을 주로 사용한다.
1) @GetMapping(), @PostMapping(), ...
@RequestMapping() 대신에 해당 어노테이션을 사용하면, URL을 매핑함과 동시에 HTTP 메서드를 구분할 수 있다.
@GetMapping("v1/save")
@PostMapping("v1/save")
@PutMapping("v1/save")
@DeleteMapping("v1/save")
@PatchMapping("v1/save")
GET, POST, PUT, DELETE, PATCH 모두 해당하는 어노테이션이 준비되어 있다.
2) @ResponseBody
이를 사용하면 @Controller 클래스 안의 메서드들로 return type이 String일 때 그 값을 HTTP message body에 넣을 수 있다. 당연히, 이 경우 view는 사용되지 않는다.
@ResponseBody
@RequestMapping("/response-body-text")
public String responseBodyText() {
return "ok";
}
단순 메시지(text)를 HTTP 응답 message body에 넣고 싶은 경우, String 값을 return하면 된다.
@ResponseBody
@RequestMapping("/response-body-json")
public HelloData responseBodyText() {
HelloData data = new HelloData("hi");
return data;
}
객체를 json 형식으로 보내고 싶은 경우, 위와 같이 인스턴스를 만들어서 return하면 된다.
3) @RequestParam()
HTTP 요청 파라미터를 @RequestParam()으로 받을 수 있다. 이는 Get 쿼리 파라미터, POST Form 방식을 모두 지원한다.
@ResponseBody
@RequestMapping("/request-v1")
public String requestParamV1(
@RequestParam("username") String name
@RequestParam("age") int age) {
return "ok";
}
위와 같이 Controller 메서드의 파라미터 자리에 온다. 서블릿의 String name = request.getParameter("username")과 같은 코드라고 생각하면 된다. 서블릿 사용법은 아래 링크를 참고 부탁한다.
서블릿, HttpServletRequest, HttpServletResponse
@ResponseBody
@RequestMapping("/request-v2")
public String requestParamV2(
@RequestParam String username
@RequestParam int age) {
return "ok";
}
만일 변수 이름과 HTTP 파라미터의 이름이 같으면, 괄호 생략 가능하다.
@ResponseBody
@RequestMapping("/request-v3")
public String requestParamV3(
String username
int age) {
return "ok";
}
@RequestParam 어노테이션 자체를 생략할 수도 있다. 스프링은 String, int, Integer와 같은 타입은 생략시 @RequestParam 어노테이션을 자동으로 붙여준다. 하지만, 개인적으로는 굳이 생략 안하는 것이 좋은 것 같다.
- required =
@ResponseBody
@RequestMapping("/request-v4")
public String requestParamV4(@RequestParam(value = "username", required = false) String name) {
return "ok";
}
required = false를 통해 파라미터 필수 여부를 지정할 수 있다. default 값은 true이다. 이때, default가 true일 경우 파라미터 이름만 있고 값이 없더라도, 통과된다!
- /request-v3?username=
- null이 입력될 경우 주의사항
@RequestParam int age에 null 값이 들어온다면? null을 int에 넣는 것을 불가능하므로, 500 예외가 발생한다. 이때는 파라미터 타입을 Integer로 변경하거나, 아래 나올 defaultValue를 사용하자.
@ResponseBody
@RequestMapping("/request-v5")
public String requestParamV5(@RequestParam Integer age) {
return "ok";
}
파라미터 타입을 Integer로 변경하면, 해결할 수 있다.
- defaultValue =
@ResponseBody
@RequestMapping("/request-v6")
public String requestParamV6(@RequestParam(defaultValue = "-1") int age) {
return "ok";
}
파라미터에 값이 없을 경우, defaultValue에 들어가있는 값이 사용된다. 이때, 값이 없으면 기본값을 사용하면 되기 때문에 required = true는 의미가 없어진다. null이 입력되는 경우도 해결된다.
@ResponseBody
@RequestMapping("/request-v7")
public String requestParamV7(@RequestParam Map<String, Object> paramMap) {
return "ok";
}
파라미터를 Map으로 조회할 수 있다. 하지만 파라미터의 값이 2개 이상일 수도 있으므로, MultiValueMap을 사용하자.
4) @ModelAttribute
@ModelAttribute는 파라미터에서 객체에 자동으로 값을 넣어주는 어노테이션이다. 이를 사용하려면 요청 파라미터를 바인딩 받을 객체가 필요하다.
@Data
public class HelloData{
}
롬복의 @Data를 붙이면, @Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor를 자동으로 적용해준다.
@ResponseBody
@RequestMapping("/request-v8")
public String requestParamV8(@ModelAttribute HelloData helloData) {
return "ok";
}
스프링은 위 코드를 발견하면 다음과 같은 과정을 실행한다.
- HelloData 객체를 생성한다.
- 요청 파라미터 이름으로 HelloData의 값을 찾고, 해당 값의 setter를 호출해 파라미터의 값을 바인딩한다.
@ResponseBody
@RequestMapping("/request-v9")
public String requestParamV9(HelloData helloData) {
return "ok";
}
@ModelAttribute를 생략할 수도 있다. 스프링은 String, int , Integer와 같은 타입들이 아닌 나머지는 생략된 경우 @ModelAttribute를 붙여준다. 개인적으로는 굳이 생략 안하는 것이 좋은 것 같다.
5) @PathVariable()
@PathVariable은 리소스 경로에 식별자가 들어가 있는 경우, 조회할 수 있도록 도와준다.
@ResponseBody
@RequestMapping("/request-v10/{userId}")
public String requestParamV10(@PathVariable("userId") String data) {
return "ok";
}
만일 "/request-v10/hi" 라는 경로가 실행되면, data의 값은 "hi"가 될 것이다.
@ResponseBody
@RequestMapping("/request-v10/{userId}")
public String requestParamV10(@PathVariable String userId) {
return "ok";
}
@PathVariable의 이름과 파라미터의 이름이 같으면, 괄호 안의 값은 생략 가능하다.
6) HttpEntity, ResponseEntity
@ResponseBody
@RequestMapping("/request-v11")
public void requestParamV11(HttpEntity<String> httpEntity) {
}
HTTP header, body 정보를 편리하게 조회 할 수 있는 스프링 MVC에서 지원해주는 파라미터이다.
@ResponseBody
@RequestMapping("/request-v12")
public void requestParamV12(HttpEntity<String> httpEntity) {
String messageBody = httpEntity.getBody();
}
HTTP message body에서 단순 텍스트를 가지고 오고 싶다면, 위와 같이 사용하면 된다.
@ResponseBody
@RequestMapping("/request-v13")
public void requestParamV13(HttpEntity<HelloData> httpEntity) {
HelloData data = httpEntity.getBody();
}
HTTP message body가 JSON 데이터 형식이라면, 위와 같은 방법으로 바로 객체에 대입 가능하다.
@ResponseBody
@RequestMapping("/request-v14")
public HttpEntity<String> requestParamV14() {
return new HttpEntity<>("ok");
}
HttpEntity는 응답에도 사용이 가능하다. 그러면 message body 정보를 직접 반환하게 된다. 하지만, 보통 HTTP 응답시 상태코드와 함께 반환해야 하는 경우가 많다...
@ResponseBody
@RequestMapping("/request-v15")
public ResponseEntity<HelloData> requestParamV15() {
HelloData hellodata = new HelloData("hi");
return new ResponseEntity(helloData, HttpStatus.OK);
}
이때는 HttpEntity를 상속받은 ResponseEntity를 사용하자. ResponseEntity는 상태코드를 같이 받는다.
7) @RequestBody
@RequestBody는 HTTP message body 정보를 편리하게 조회할 수 있도록 도와준다. 만일 헤더 정보가 필요하다면, 위에서 언급한 HttpEntity 혹은 아래서 잠깐 소개할 @RequestHeader를 사용하자. 당연히 view는 사용되지 않는다.
@ResponseBody
@RequestMapping("/request-v16")
public String requestParamV16(@RequestBody String messageBody) {
log.info("messageBody={}", messageBody);
return "ok";
}
HTTP message body가 단순 텍스트로 이루어져 있다면, 위처럼 파라미터를 적으면 된다.
@ResponseBody
@RequestMapping("/request-v17")
public String requestParamV17(@RequestBody HelloData helloData) {
log.info("username={}", helloData.getUsername());
return "ok";
}
HTTP message body가 JSON 데이터 형식이라면, 위처럼 적으면 된다. 그러면 helloData 객체에 자동으로 값이 바인딩 되어 들어간다.
이때, @RequestBody는 생략하면 안된다!! 생략시 스프링에서는 @ModelAttribute로 생각하고 진행할 것이다.
8) @ResponseStatus(HttpStatus.OK)
메서드 레벨에 붙일 수 있는 어노테이션이며, 응답 코드를 설정할 수 있다. @ResponseBody 혹은 HttpEntity<>로 객체를 응답할때 추가로 사용하면 된다.
하지만 동적으로 변경할 수 없으므로(어노테이션이기 때문) 되도록이면 ResponseEntity를 사용하자
9) RedirectAttributes
PRG(Post Redirect Get) 패턴과 같은 곳에서 view 렌더링시 redirect 하고 싶은 경우에 사용한다.
@RequestMapping("/request-v18")
public String requestParamV18(@ModelAttribute Item item, RedirectAttributes redirectAttributes) {
Item savedItem = itemRepository.save(item);
redirectAttributes.addAttribute("itemId", savedItem.getId);
redirectAttributes.addAttribute("status", true);
return "redirect:/basic/items/{itemId}";
}
실제로 작동시, redirect 주소는 /basic/items/3?status=true 이렇게 나올 것이다. 이는 URL 인코딩, pathVariable, 쿼리 파라미터 모두를 처리해준다.
물론 return "redirect:/basic/items" + item.getId() 해도 작동은 되지만, URL 인코딩이 되지 않아 위험하다.
10) 기타
(1) Locale locale
파라미터에 들어가는 값으로, ko_KR와 같은 Locale 정보를 조회한다.
(2) @RequestHeader MultiValueMap<String, String> headerMap
HTTP 요청 메시지 헤더들을 조회하고 싶을때 사용하며, 헤더가 여러개 있을 수 있어 key 중복을 허용하는 MultiValueMap을 사용한다. headerMap.get() 사용시, List<String>을 반환한다.
(3) @RequestHeader("host") String host
특정 HTTP 헤더를 조회한다. 필수 값 여부 조절하고 싶으면 required, 기본 값 설정하고 싶으면 defaultValue 설정하자.
(4) @CookieValue(value = "myCookie", required = false) String cookie
특정 쿠키를 조회한다. 마찬가지로 필수 값 여부 조절하고 싶으면 required, 기본 값 설정하고 싶으면 defaultValue 설정하자.
위 내용은 김영한 님의 인프런 강의 "스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술"의 내용과 강의자료를 토대로 작성된 게시글입니다.
강의 링크:
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard
'Web > spring study' 카테고리의 다른 글
[Spring] 메시지, 국제화 (0) | 2024.01.18 |
---|---|
[Thymeleaf] Thymeleaf(타임리프)의 특징과 기본 표현식, 태그 속성 (0) | 2023.06.07 |
[Spring] 스프링 MVC 패턴에서 Controller가 Model에 정보 저장하는 방법 정리 (0) | 2023.05.25 |
[Spring] MVC 패턴, 스프링 MVC 구조 이해 (0) | 2023.05.24 |
[Spring] SLF4J 로깅 간단한 정리 (0) | 2023.05.24 |
댓글