suyeonme
[Spring] Controller의 요청/응답 관련 애노테이션 본문
Controller와 관련있는 자주 사용할 것 같은 애노테이션을 정리했다.
@RequestMapping
Controller에서 들어온 http request를 method와 매핑(mapping)하게 위해 사용한다.
- @RequestMapping(value = "URI", method = RequestMethod.GET)
- @RequestMapping({ "/members", "member_list" })와 같이 복수개의 URL을 등록할 수 있다.
- method를 지정하지 않으면 모든 요청에 대해서 호출된다.
@RestController
public class MemberController {
@RequestMapping(value = "/member", method = RequestMethod.GET)
public String getMember(...) {}
@RequestMapping(value = "/member", method = RequestMethod.POST)
public String postMember(...) {}
@RequestMapping(value = "/member", method = RequestMethod.PUT)
public String putMember(...) {}
@RequestMapping(value = "/member", method = RequestMethod.DELETE)
public String deleteMember(...) {}
}
@GetMapping, @PostMapping, @PutMapping, @DeleteMapping
위처럼 작성해도 문제 없지만, 아래와 같이 더 간결하게 작성할 수 있다.
공통된 URI를 RequestMapping의 value로 작성하고, 각 method별로 @GetMapping과 같이 작성한다.
- @GetMapping의 경우 내부적으로는 @RequestMapping(method = RequestMethod.GET)으로, 즉 @RequestMapping의 method별로 작성이 되어있다.
@RestController
@RequestMapping(value = "/member")
public class MemberController {
@GetMapping()
public String getMember(...) {}
@PostMapping()
public String postMember(...) {}
@PutMapping()
public String putMember(...) {}
@DeleteMapping()
public String deleteMember(...) {}
}
Params, Headers
params나 headers를 사용하여 쿼리 파라미터 및 특정 헤더를 포함한 URL에 있는 경우에만 API를 호출할 수 있다.
- params="mode"
- params="!mode"
- params="mode=debug"
- params="mode!=debug"
- params={"mode=debug","data=good"}
// /members?mode=debug 정상호출
// /members 호출되지 않음
@GetMapping(value = "/members", params = "mode=debug")
public String getMember(...) {}
@GetMapping(value = "/members", headers = "mode=debug")
public String getMember(...) {}
Consumes, Produces
consumes는 요청 Header의 Content-type을 매핑이 된다.
- consumes="text/plain"
- consumes={"text/plain", "application/*"}
- consumes=MediaType.TEXT_PLAIN_VALUE
produces는 요청 Header의 Accept의 Content-Type과 매핑이 된다. 맞지 않으면 406 상태코드를 반환한다.
@PostMapping(value = "/members/create", consumes = "application/json")
public String createMember(...) {}
// Header의 Accept가 "text/html"인 경우 정상적으로 동작.
@PostMapping(value = "/members/create", produces = "text/html")
public String createMember(...) {}
@RestController
@Controller와 @ResponseBody를 함께 적용하는 어노테이션이다. 반환값으로 뷰 템플릿을 사용하지 않고 HTTP 메세지 바디에 값을 바로 입력한다. 즉 Rest API르 만들 때 사용하는 컨트롤러이다.
- @Controller의 경우, 반환값이 String 타입이면 View의 이름으로 인식되어 View를 찾은 뒤 View를 렌더링한다.
- 클래스 레벨이 @ResponseBody를 적용하면 클래스의 모든 메소드에 적용된다.
@RestController
public class MemberController {
@GetMapping("/members")
public String getMember() {
return "ok";
}
}
// 위와 동일
@Controller
@ResponseBody
public class MemberController {
@GetMapping("/members")
public String getMember() {
return "ok";
}
}
@JsonProperty, @JsonNaming
보편적으로 클라이언트에서는 snake case(e.g. phone_number)를 사용하고 서버에서는 camel case(e.g phoneNumber)를 사용한다. 이 때 클라이언트에서 보낸 JSON의 key와 서버의 entity key와 일치하지 않을 수 있다. 이 때 @JsonProperty를 사용하여 key를 매핑(mapping)할 수 있다.
해당 어노테이션을 사용하기 위해서는 com.fasterxml.jackson.core 패키지(Jackson)를 dependency에 추가해야한다.
- @JsonProperty: 객체를 JSON 형식으로 변환할 때 Key의 이름을 매핑(mapping)한다.
- @JsonNaming: 클래스의 전체 field에 대해서 key의 이름을 매핑(mapping)한다.
// JSON 데이터
{
phone_number: "010-000-0000",
name: "Suyeon"
}
// Entity
@Data
public class Member {
@JsonProperty("phone_number")
private string phoneNumber;
private String name;
}
// Controller
@RestController
@RequestMapping("/member")
public class MemberController {
public void post postMember(@RequestBody Member member) {
System.out.println(member);
}
}
위와 같이 @JsonProperty를 사용하여 field를 매핑할 수 있지만, 매핑이 필요한 field가 많은 경우에는 일일히 설정하는 것은 매우 번거롭다. 이러한 경우 @JsonNaming를 클래스에 붙여서 전체 필드에 적용할 수 있다.
// Entity
@Data
@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class)
public class Member {
private string phoneNumber;
private String name;
}
@RequestBody, @ResponseBody
클라이언트에서 POST 형식으로 데이터를 메세지 Body 에 넣어서 보내거나(content-type: application/json) JSON데이터 또는 스트링등을 Response Body에 담아서 클라이언트로 보낼 때 사용한다.
- @RequestBody: Request의 body를 자바객체로 변환한다.
- @ResponseBody: 자바 객체를 Response의 body로 변환한다. @RestController와 동일한 기능이다.
- 헤더 정보 조회는 HttpEntity 또는 @RequestHeader를 사용한다.
- @RequestBody는 생략할 수 없다. (default값인 @ModelAttribute가 적용됨)
http 메세지 컨버터
내부적으로 http 메세지 컨버터가 메세지 바디를 변환한다.
- @RequestBody: JSON요청 -> HTTP 메세지 컨버터 -> 객체
- @ResponseBody: 객체 -> HTTP 메세지 컨버터 -> JSON응답
@Controller
public class MemberController {
@PostMapping("/member")
@ResponseBody
public Member createMember(@RequestBody Member member) {
return member;
}
}
HttpEntity
Http header, body 정보를 조회한다. 응답에도 사용할 수 있다. @RequestBody, @ResponseBody로 대체할 수 있다.
- POST 형식의 메세지 바디의 정보를 조회하는 경우 사용한다.
- RequestEntity: http method, url 정보가 추가되며 요청에 사용한다. (httpEntity 상속)
- ResponseEntity: http 상태 코드를 설정할 수 있으며 응답에 사용한다. (httpEntity 상속)
@PostMapping("/request-body-string")
public HttpEntity<String> requestBodyString(HttpEntity<String> httpEntity) throws IOException {
String messageBody = httpEntity.getBody();
log.info("messageBody={}", messageBody);
return new HttpEntity<>("ok");
}
@PathVariable
Rest API에서 URI의 변수를 핸들링할 수 있다. @PathVariable을 사용하여 매칭되는 값을 편하게 조회할 수 있다.
예를 들어, URI가 http://localhost:8080/api/user/1인 경우 변수는 1에 해당된다.
@RestController
public class MemberController {
@GetMapping("/member/{name}")
public String findByName(@PathVariable("name") String name) {
log.info("name={}", name);
return "Name: " + name;
}
@GetMapping("/member/{id}/{name}")
public String findByNameAndId(@PathVariable("id") String id, @PathVariable("name") String name) {
return "ID: " + id + ", name: " + name;
}
}
위 코드처럼 path variable과 변수명이 동일한 경우 아래와 같이 간단하게 작성할 수 있다.
@RestController
public class MemberController {
@GetMapping("/member/{name}")
public String findByName(@PathVariable String name) {
log.info("name={}", name);
return "Name: " + name;
}
}
@RequestParam
Request Parameter 조회 및 핸들링하는 경우에 사용한다.
- GET 방식의 쿼리 파라미터
- POST 방식의 HTML Form
HTTP 쿼리 파라미터 이름이 변수명과 동일한 경우 @RequestParam String memberName와 같이 간략하게 사용할 수 있다.
Required
default값이 true이며 해당 파라미터가 포함되지 않은 경우 상태코드 400을 반환한다. false로 설정시 해당 파라미터를 필수로 포함하지 않아도 된다.
@Controller
public class RequestParamController {
@ResponseBody
@RequestMapping("/request-param")
public String requestParam(
@RequestParam(required = false) String memberName // @RequestParam("memberName") String memberName
@RequestParam int memberAge) {
return "ok";
}
}
// @RequestParam("username") String memberName
// @RequestParam("age") int memberAge
DefaultValue
쿼리 파라미터가 포함되지 않은 경우 기본값을 지정한다. 쿼리 파라미터가 빈문자인 경우(e.g. /members?username=)에도 적용된다.
@Controller
public class RequestParamController {
@ResponseBody
@RequestMapping("/request-param")
public String requestParam(@RequestParam(required = true, defaultValue = "suyeon") String memberName) {
return "ok";
}
}
Map, MultiValueMap
모든 쿼리 파라미터를 조회하고 싶은 경우, Map을 사용하면 된다.
@Controller
public class RequestParamController {
@ResponseBody
@RequestMapping("/request-param")
public String requestParam(@RequestParam Map<String, Object> paramMap) {
log.info("username={}, age={}", paramMap.get("username"), paramMap.get("age"));
return "ok";
}
}
@ModelAttribute
객체를 생성하고 요청 파라미터의 이름으로 해당 객체의 프로퍼티를 찾는다. 그리고 프로퍼티의 setter를 호출하여 파라미터의 값을 객체에 추가한다. 쿼리 파라미터의 값과 객체 프로퍼티의 타입이 다르면 BindException이 발생한다.
Request Parameter 조회 및 핸들링하는 경우에 사용한다.
- GET 방식의 쿼리 파라미터
- POST 방식의 HTML Form
@Data // 롬복의 어노테이션
public class HelloData {
private String username;
private int age;
}
@Controller
public class RequestParamController {
@ResponseBody
@RequestMapping("/model-attribute")
public String requestParam(@ModelAttribute HelloData helloData) {
return "ok";
}
}
@ModalAttibute를 사용하지 않는다면 아래와 같이 직접 객체를 생성한 뒤 값을 추가해야한다.
@Controller
public class RequestParamController {
@ResponseBody
@RequestMapping("/model-attribute")
public String requestParam(@RequestParam String username, @RequestParam int age) {
HelloData helloData = new HelloData();
helloData.setUsername(username);
helloData.setAge(age);
return "ok";
}
}
@ResponseEntity
응답 상태코드를 반환한다.
- HttpStatus
@GetMapping
public ResponseEntity<User> getUsers() {
//...
return new ResponseEntity<User>(user, HttpStatus.OK);
}
'프로그래밍👩🏻💻 > Spring' 카테고리의 다른 글
[Spring Boot] 로그(Log) (0) | 2022.11.08 |
---|---|
[Spring] Bean Scope 종류 (0) | 2022.06.05 |
[Spring] Dependency Injection(DI), Dependency Lookup(DL)이란? (0) | 2022.06.05 |
[Spring] Spring Bean, Ioc란? (0) | 2022.06.05 |
[Spring] Lombok 라이브러리란? (0) | 2022.05.23 |