MVC 기능 1

강한친구·2022년 4월 26일
0

Spring

목록 보기
13/27

요청매핑

요청매핑이란, HTTP Request가 왔을때, 어떠한 Controller가 mapping 되어야하는지 나타내는 기술이다. 단순히 URL로만 처리하는게 아니라 다양한 기술이 있다.

RequestMapping

    @RequestMapping({"/hello-basic", "/hello-go"})
    public String helloBasic() {
        log.info("Hello Basic");
        return "ok";
    }

가장 기본적인 컨트롤러 매핑이다. URL경로를 템플릿화 할 수 있다.

Get, Post... etc

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

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

이런식으로 어노테이션을 사용하면 GET, POST로 메서드가 왔을때만 돌리게 설정할 수 있다.

미디어타입, 데이터타입 지정

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

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

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

이런식으로 데이터, 미디어 타입을 따로 지정해줄수도 있다.

예시

URL 매핑 예시

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

위와 같은 API가 있다고 하자. 이를 매핑하는 예시는 다음과 같다.

@RestController // 컨트롤러 등록 
@RequestMapping("/mapping/users") // 공통 주소 매핑 
public class MappingClassController {
    @GetMapping
    public String users() {
        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;
    }
}

HTTP 관련 정보 받기

HTTP Header 받기

HTTP 요청 파라미터

클라이언트에서 서버로 요청 데이터를 전달할 때는 3가지 방법을 사용한다.

GET - 쿼리 파라미터

  • /url?username=hello&age=20
  • 메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달

예) 검색, 필터, 페이징등에서 많이 사용하는 방식

POST - HTML Form

  • content-type: application/x-www-form-urlencoded
    메시지 바디에 쿼리 파리미터 형식으로 전달 username=hello&age=20

예) 회원 가입, 상품 주문, HTML Form 사용

HTTP message body에 데이터를 직접 담아서 요청

  • HTTP API에서 주로 사용, JSON, XML, TEXT
    데이터 형식은 주로 JSON 사용

POST, PUT, PATCH

스프링으로 요청 파라미터 조회

requestParamV1

 public void requestParamV1(HttpServletRequest request, HttpServletResponse response)

아주 기본적인 방식이다

2022-04-26 17:34:47.096  INFO 11672 --- [nio-8080-exec-1] h.s.b.request.RequestParamController     : username=hello, age=20
<form action="/request-param-v1" method="post">

html 정적 페이지에서 입력값을 url로 포스트방식을 이용해서 넘겨주면

2022-04-26 17:38:25.409  INFO 23780 --- [nio-8080-exec-6] h.s.b.request.RequestParamController     : username=ㅁㄴㅇ, age=12

제대로 넘어오는것을 볼 수 있다.

v2

@ResponseBody
@RequestMapping("/request-param-v2")
    public String requestParamV2(
            @RequestParam("username") String memberName, @RequestParam("age") int memberAge)

RequestParam으로 getParam을 바로 실행하고 구현하는 방식이다.

@ResponseBody : View 조회를 무시하고, HTTP message body에 직접 해당 내용 입력하기 위해 존재한다. 없으면 에러가 발생한다.

v3

HTTP 파라미터 이름이 변수 이름과 같으면 RequestParam(name="xx") 생략 가능하다.

ResponseBody
    @RequestMapping("/request-param-v3")
    public String requestParamV3(
            @RequestParam String username, @RequestParam int memberAge)

v4

요청 파라미터와 동일하면 @RequestParam도 생략가능하다.

@ResponseBody
    @RequestMapping("/request-param-v4")
    public String requestParamV4(String username, int age) {

필수, 기본 파라미터 설정

@ResponseBody
    @RequestMapping("/request-param-required")
    public String requestParamRequired(
            @RequestParam(required = true) String username, @RequestParam(required = false) Integer age)
@ResponseBody
    @RequestMapping("/request-param-default")
    public String requestParamDefault(
            @RequestParam(required = true, defaultValue = "guest") String username, @RequestParam(required = false, defaultValue = "-1") int age)

이렇게 필수, 기본 파라미터를 지정해줄 수도 있다.

Map으로 받기

@ResponseBody
    @RequestMapping("/request-param-map")
    public String requestParamMap(@RequestParam Map<String, Object> paramMap)

파라미터의 값이 1개가 확실하다면 Map 을 사용해도 되지만, 그렇지 않다면 MultiValueMap 을 사용해야한다.

?userIds=id1&userIds=id2

이런 케이스의 경우 MultiMap를 사용해서 해결 할 수 있다.
다만 이렇게 두개를 쓰는 경우는 별로 없다.

모델 Attribute

실제 개발을 하면 요청 파라미터를 받아서 필요한 객체를 만들고 그 객체에 값을 넣어주어야 한다.

HelloData

@Data
public class HelloData {
    private String Username;
    private int age;
}

롬복을 이용해서 username, age를 가지는 HelloData를 만들어준다.

V1

	@ResponseBody
    @RequestMapping("/model-attribute-v1")
    public String modelAttributeV1(@ModelAttribute HelloData helloData) {
        log.info("username={}, age={}", helloData.getUsername(),
                helloData.getAge());
        return "ok";
    }

가장 기본적인 형태의 모델 어트리뷰트이다. set, get을 통해 데이터를 가지고온다.

V2

@modelAttribute는 생략이 가능하다.

	@ResponseBody
    @RequestMapping("/model-attribute-v2")
    public String modelAttributeV2(HelloData helloData)

스프링은 이러한 생략ㅇ르 할 때, 다음과 같은 규칙을 적용한다.

  • String , int , Integer 같은 단순 타입 = @RequestParam

  • 나머지 = @ModelAttribute (argument resolver 로 지정해둔 타입 외)

HTTP 요청메시지 - 단순텍스트

HTTP API에서 주로 사용, JSON, XML, TEXT 이고, 데이터 형식은 주로 JSON 사용한다. 메서드로는 POST, PUT, PATCH을 사용한다.

요청 파라미터와 다르게, HTTP 메시지 바디를 통해 데이터가 직접 데이터가 넘어오는 경우는 @RequestParam , @ModelAttribute 를 사용할 수 없다.

V1

@PostMapping("/request-body-string-v1")
    public void requestBodyString(HttpServletRequest request, HttpServletResponse response) throws IOException {
        ServletInputStream inputStream = request.getInputStream();
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

        log.info("messageBody={}", messageBody);

        response.getWriter().write("ok");
    }

가장 기본적인 방식이다. InputStream으로 Text/html 형식의 Body의 Message를 읽고, 이를 출력한다.

V2

public void requestBodyStringV2(InputStream inputStream, Writer responseWriter) throws IOException

이렇게 필요한 인자만 받아서 쓸 수 있다.

V3

Message Convertor를 써서 이를 아예 안쓰고 사용할 수 있다.

@PostMapping("/request-body-string-v3")
    public HttpEntity<String> requestBodyStringV2(HttpEntity<String> httpEntity) throws IOException {
        String messageBody = httpEntity.getBody();
        log.info("messageBody={}", messageBody);
        return new HttpEntity<>("ok");
    }

HttpEntity

HTTP 헤더와 바디정보를 직접 조회할 수 있는 스프링 내장 기능이다. 이는 요청 파라미터와 아무런 관계가 없다.

요청파라미터

  • GET의 Query Stream
  • POST의 HTML Form xxx

@RequestBody

public HttpEntity<String> requestBodyStringV2(@RequestBody String messageBody) throws IOException

request의 body를 바로 읽어들이는 코드이다.

정리

요청 파라미터 vs HTTP 메시지 바디

  • 요청 파라미터를 조회하는 기능: @RequestParam , @ModelAttribute
  • HTTP 메시지 바디를 직접 조회하는 기능: @RequestBody

HTTP 요청메시지 - JSON

V1

기본적인 형태는

private ObjectMapper objectMapper = new ObjectMapper();

를 이용해서 response 받은 json data를 Hellodata에 넣어주는 방식이다.

V2

ublic String requestBodyJsonV2(@RequestBody String messageBody)

V2에서는 @RequestBody를 사용한다

V3

	@ResponseBody
    @PostMapping("/request-body-json-v3")
    public String requestBodyJsonV3(@RequestBody HelloData data) {
        log.info("username={}, age={}", data.getUsername(), data.getAge());
        return "ok";
    }

객체를 파라미터로 넘겨서 RequestBody에 직접 만든 객체를 지정해 줄 수 있다.

HttpMessageConvertor가 json인것을 파악하고, 알아서 V2의 코드를 실행해서 HelloData에 넣어주는것이다.

Acthung

만약 @ResquestBody를 생략하면, 규칙에 의거해서 modelAttribute가 적용이 되어서 요청 파라미터를 꺼내려 시도하고, 메시지 바디를 꺼내지 못하게 된다.

V4

HttpEntity를 사용하는 방식이다.

	@ResponseBody
    @PostMapping("/request-body-json-v4")
    public String requestBodyJsonV4(HttpEntity<HelloData> httpEntity)

V5

	@ResponseBody
    @PostMapping("/request-body-json-v5")
    public HelloData requestBodyJsonV5(@RequestBody HelloData data) {
        log.info("username={}, age={}", data.getUsername(), data.getAge());
        return data;
    }

HttpConvertor가 Json을 객체로 만들었다가, 다시 반환할 때 객체를 Json형식으로 만들어서 반환한다.

0개의 댓글