프레임워크(Framework)/Spring

[Spring MVC] HTTP 요청 매핑(HTTP Request Mapping) 관련 어노테이션 정리

잇트루 2022. 11. 11. 22:34
반응형
본 내용은 온라인 강의 사이트 인프런의 김영한 님의 강의 내용이 포함되어 있습니다.
'스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술'
 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -

www.inflearn.com

 

@RequestMapping

클라이언트 요청에 정보를 어떤 Controller가 처리할지를 매핑하기 위한 어노테이션이다.

@RequestMapping에 URL을 포함하여 해당 Controller 클래스에 명시하여 사용한다.

웹 브라우저에서 해당 URL이 호출되면 Controller 내부의 메서드가 호출된다.

@RequestMapping("/members")
public class MemberController {
		...
}

 

@Controller

스프링이 자동으로 스프링 빈으로 등록한다. @Controller 어노테이션 내부에 @Component 어노테이션이 포함되어 있어 컴포넌트 스캔의 대싱이 되기 때문이다.

Spring MVC에서 어노테이션 기반 컨트롤러로 인식하게 된다.

@Controller
public class MemberController {
		...
}

 

@RestController

스프링이 자동으로 스프링 빈으로 등록한다. @RestController 어노테이션 내부에 @Component 어노테이션이 포함되어 있어 컴포넌트 스캔의 대싱이 되기 때문이다.

Spring MVC에서 어노테이션 기반 컨트롤러로 인식하게 된다.

@RestController
@RequestMapping("/members")
public class MemberController {

}

@RestController는 @Controller과 차이점이 있다.

  • @Controller는 반환 값이 String이면 뷰 이름으로 인식된다. 따라서 뷰를 찾고 뷰가 랜더링 된다.
  • @RestController는 반환 값으로 뷰를 찾는 것이 아닌, HTTP 메시지 바디에 바로 입력한다. 따라서 실행 결과로 ok 메시지를 받을 수 있다. @ResponseBody와 관련이 있다.

 

@RequestMapping과 @Controller

스프링 빈 중에서 @RequestMapping이 있으면, 핸들러 매핑 조회할 때, RequestMappingHandlerMapping이 실행된다.

RequestMappingHandlerMapping은 스프링 빈 중에서 @RequestMapping 또는 @Controller가 클래스 레벨에 붙어 있는 경우에 매핑 정보로 인식하게 된다.

@Controller
@RequestMapping("/members")
public class MemberController {

}

@Componet를 통해 스프링 빈으로 등록하고, @RequestMapping을 통해 매핑 정보로 인식하게 된다.

@Controller 어노테이션 내부에는 @Component가 포함되어 있다.

 

@RequestMapping과 HTTP 메서드

@RequestMapping은 URL만 매칭 하는 것이 아닌, HTTP 메서드도 함께 구분할 수 있다.

예를 들어, URL이 /new-form이고, HTTP 메서드가 GET인 경우를 모두 만족해야 한다면 다음과 같이 작성해야 한다.

@RequestMapping(value = "/new-form", method = RequestMethod.GET)
public String newForm() {

}

@RequestMapping에 method 속성으로 HTTP 메서드를 지정하지 않으면, HTTP 메서드와 무관하게 GET, HEAD, POST, PUT, PATCH, DELETE 등 모든 HTTP 메서드 호출이 가능하다.

 

@RequestMapping(value = "/hello-basic", method = RequestMethod.GET)

@RestController
public class MappingController {

    @RequestMapping(value = "/hello-basic", method = RequestMethod.GET)
    public String helloBasic() {

        return "ok";

    }
}

만약 위 코드를 실행한 뒤, POST 요청을 하게 되면 스프링 MVC는 HTTP 405 상태 코드(Method Not Allowed)를 반환한다.

 

Postman으로 테스트

 

편리한 매핑 어노테이션

하지만, @RequestMapping 어노테이션을 각각의 매핑 메서드로 제한하는 어노테이션으로 사용하여 편리하게 이용할 수 있다.

@GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping

@GetMapping("/mapping-get")
public String mappingGet() {
    return "ok";
}

@PostMapping("/mapping-post")
public String mappingPost() {
    return "ok";
}

@PutMapping("/mapping-put")
public String mappingPut() {
    return "ok";
}

@DeleteMapping("/mapping-delete")
public String mappingDelete() {
    return "ok";
}

@PatchMapping("/mapping-patch")
public String mappingPatch() {
    return "ok";
}

 

@RequestMapping 다중 경로

또한, @RequestMapping은 url을 배열로 사용하여 다중 설정이 가능하다.

@RestController
public class MappingController {

    private Logger log = LoggerFactory.getLogger(getClass());

	// 다중 설정
    @RequestMapping({"/hello-basic", "/hello-go"})
    public String helloBasic() {
        log.info("helloBasic");

        return "ok";
    }
}

위 코드의 경우 실행을 하게 되면 웹 브라우저에서 아래와 같이 두 가지 경로에서 확인이 가능하다.

http://localhost:8080/hello-basic

http://localhost:8080/hello-go

 

PathVariable(경로 변수) 사용

@RequsetMapping과 @GetMapping 등에는 method를 변수로 지정하여 사용이 가능하다.

@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable("userId") String id) {
    log.info("mappingPath userId={}", id);
    
    return "ok";
}

 

만약, 변수명이 경로명과 같으면 @PathVariable의 속성을 생략할 수 있다.

@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable String userId) {
    log.info("mappingPath userId={}", userId);
    
    return "ok";
}

 

http://localhost:8080/mapping/userA와 같이 경로 변수에 해당하는 경로에 변수에 알맞은 값을 입력하여 요청을 보낼 수 있다.

// 출력
2022-10-27 22:07:27.286  INFO 22228 --- [nio-8080-exec-2] h.s.b.requestmapping.MappingController   : mappingPath userId=userA

 

Postman을 통해 테스트가 가능하다.

 

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";
}

위 경우 http://localhost:8080/mapping/users/userA/orders/100와 같이 경로 변수를 다중으로 사용이 가능하다.

// 출력
2022-10-27 22:14:17.188  INFO 15756 --- [nio-8080-exec-3] h.s.b.requestmapping.MappingController   : mappingPath userId=userA, orderId=100

 

특정 파라미터 조건 매핑

@GetMapping(value = "/mapping-param", params = "mode=debug")
public String mappingParam() {
    log.info("mappingParam");
    return "ok";
}

위 코드와 같이 매핑 어노테이션 속성에 params =을 추가하여 특정 조건에 대한 매핑을 수행할 수 있다.

  • params = "mode=debug" : 파라미터에 mode=debug가 존재해야 호출이 된다.
  • 즉, 호출을 하기 위해서는 http://localhost:8080/mapping-param?mode=debug로 접속해야 한다.
  • http://localhost:8080/mapping-param로는 접속이 불가능하다.
  • params에는 “!mode”, “mode!=debug”, {”mode=debug”, “data=good”} 등과 같이 사용할 수 있다.
  • 하지만 실제로 사용하는 일은 거의 없다.

 

특정 헤더 조건 매핑

@GetMapping(value = "/mapping-header", headers = "mode=debug")
public String mappingHeader() {
    log.info("mappingHeader");
    return "ok";
}

위 코드와 같이 매핑 어노테이션 속성에 headers =을 추가하여 헤더 조건에 대한 매핑을 수행할 수 있다.

 

http://localhost:8080/mapping-header에 그냥 접속하면 404 상태 코드를 반환한다.

 

해당 경로에 접속하기 위해서는 아래 header 정보에 mode를 추가하여 값으로 debug로 지정해주어야 접속이 가능해진다.

특정 헤더 조건 역시, headers에는 “mode”, “!mode”, “mode≠debug 등과 같이 여러 방식의 조건을 사용할 수 있다.

 

미디어 타입 조건 매핑

consume

consumes를 통해 HTTP 요청 시 미디어 타입 조건도 매핑을 할 수 있다.

Content-Type에 따라 분리하여 매핑할 수 있다.

@PostMapping(value = "/mapping-consume", consumes = "application/json")
public String mappingConsumes() {
    log.info("mappingConsumes");
    return "ok";
}

위 코드의 경우 헤더의 Content-Type이 application/json인 경우에만 호출이 가능하다.

 

아래 이미지와 같이 헤더의 Content-Type이 조건에 맞지 않는 경우 415 상태 코드를 반환한다.

 

아래와 같이 Content-Type이 application/json인 경우에만 정상적으로 호출된다.

 

Accept, produce

헤더의 Accept 헤더를 기반의 미디어 타입으로 매핑한다.

@PostMapping(value = "/mapping-produce", produces = "text/html")
public String mappingProduces() {
    log.info("mappingProduces");
    return "ok";
}

 

만약, Accept 헤더가 일치하지 않으면 406 상태 코드를 반환한다.

 

다음과 같이 Accept가 text/html인 경우에 정상적으로 반환한다.

 

@RequestParam

스프링은 HTTP 요청 파라미터를 @RequestParam으로 받을 수 있다.

만약 요청 파라미터에 username과 age가 있다고 가정한다.

예전 방식

@RequestMapping("/save")
public ModelAndView save(HttpServletRequest request, HttpServletResponse response) {
    String username = request.getParameter("username");
    int age = Integer.parseInt(request.getParameter("age"));
		...
}

 

@RequestParam 사용

@PostMapping("/save")
public String save(@RequestParam("username") String username, @RequestParam("age") int age, Model model) {
		...
}

HttpServletRequest과 HttpServletResponse을 파라미터로 받아 요청을 변환하고, ModelAndView로 반환하기까지의 불편한 로직이 상당 부분 해소되었다.

또한, Model 파라미터를 통해 내부 로직에 편의 기능을 제공받을 수 있다.

반응형