yeon's blog

[Spring] HTTP 요청 매핑 및 API 예시 본문

Spring/Spring 개념

[Spring] HTTP 요청 매핑 및 API 예시

yeonii 2024. 1. 14. 12:55

HTTP 요청 매핑 관련 애노테이션을 정리해보자 ‼️

 

요청 매핑

@RequestMapping

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

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

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

@RequestMapping("/mapping/users")
public class MappingClassController {
		...
}

 

웹 브라우저에서 `http://localhost:8080/mapping/users` URL이 호출되면

→ MappingClassController 내부의 메서드가 호출된다는 것이다.

 

@Controller

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

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

@Controller
public class MappingClassController {
		...
}

 

@RestController

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

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

@RestController
public class MappingClassController {
		...
}

 

 

위의 두 애노테이션은 차이점이 존재한다 ‼️

  • @Controller: 반환 값이 String이면 뷰 이름으로 인식 → 뷰를 찾고 뷰가 렌더링 됨
  • @RestController: 반환 값으로 뷰를 찾는 것이 아니라, HTTP 메시지 바디에 바로 입력

@RequestMapping과 @Controller

스프링 빈 중에서 @RequestMapping이 있으면 핸들러 매핑을 조회할 때 RequestMappingHandlerMapping이 실행된다.RequestMappingHandlerMapping은 스프링빈 중에서 클래스 레벨에 @RequestMapping 또는 @Controller가 붙어있는경우 매핑 정보로 인식한다.

@Controller
public class MappingClassController {
		...
}

 

HTTP 메서드 매핑

@RequestMapping은 URL뿐만 아니라, HTTP 메서드도 함께 설정할 수 있다.

ex. GET 메서드를 이용해야 하는 경우 다음과 같이 작성하면 된다.

/**
 * method 특정 HTTP 메서드 요청만 허용
 * GET, POST, PUT, PATCH, DELETE 
 * */
@RequestMapping(value = "/mapping-get-v1", method = RequestMethod.GET)
public String mappingGetV1() {
    log.info("mappingGetV1");
    return "ok";
}

 

주석에 써있는 것처럼 GET 뿐만 아니라 POST, PUT, PATCH, DELETE 모두 가능하다.

위와 같이 method = RequestMethod.GET을 이용할 수도 있지만, 더욱 편리하게 사용할 수 있도록 현재는 축약해서 사용한다.

 

HTTP 메서드 매핑 축약

@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(경로 변수) 사용

/**
 * PathVariable 사용
 * 변수명이 같으면 생략 가능
 * @PathVariable("userId") String userId -> @PathVariable String userId
 */
@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable("userId") String data) {
    log.info("mappingPath userId={}", data);
    return "ok";
}

 

만약, 변수명이 경로명과 같으면 @PathVariable의 속성은 생략이 가능하다.

/**
 * PathVariable 사용
 * 변수명이 같으면 생략 가능
 * @PathVariable("userId") String userId -> @PathVariable String userId
 */
@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable String userId) {
    log.info("mappingPath userId={}", data);
    return "ok";
}

 

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

 

특정 파라미터 조건 매핑

/**
 * 파라미터로 추가 매핑
 * params="mode",
 * params="!mode"
 * params="mode=debug"
 * params="mode!=debug" (! = )
 * params = {"mode=debug","data=good"} */
@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";
}

 

미디어 타입 조건 매핑

Consume

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

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

/**
 * Content-Type 헤더 기반 추가 매핑 Media Type * consumes="application/json"
 * consumes="!application/json"
 * consumes="application/*"
 * consumes="*\/*"
 * MediaType.APPLICATION_JSON_VALUE
 */
@PostMapping(value = "/mapping-consume", consumes = MediaType.APPLICATION_JSON_VALUE)
public String mappingConsumes() {
    log.info("mappingConsumes");
    return "ok";
}

HTTP 요청의 Content-Type 헤더를 기반으로 미디어 타입으로 매핑한다.

만약 맞지 않으면 HTTP 415 상태코드(Unsupported Media Type)을 반환한다.

 

Accept, produce

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

/**
 * Accept 헤더 기반 Media Type * produces = "text/html"
 * produces = "!text/html" * produces = "text/*"
 * produces = "*\/*"
 */
@PostMapping(value = "/mapping-produce", produces = MediaType.TEXT_HTML_VALUE)
public String mappingProduces() {
    log.info("mappingProduces");
    return "ok";
}

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

만약 맞지 않으면 HTTP 406 상태코드(Not Acceptable)을 반환한다.


요청  매핑 - API 예시

회원 관리 API

회원 목록 조회: GET   `/users`
회원 등록: POST        `/users`
회원 조회: GET           `/users/{userId}`
회원 수정: PATCH      `/users/{userId}`
회원 삭제: DELETE    `/users/{userId}`

 

 

MappingClassController 전체코드

package hello.springmvc.basic.requestmapping;

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/mapping/users")
public class MappingClassController {

    @GetMapping
    public String users() {
        return "get users";
    }

    @PostMapping
    public String addUser() {
        return "post users";
    }

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