스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술[스프링 MVC - 기본 기능]

윤현우·2023년 3월 10일
0
post-thumbnail

목차

  1. 요청 매핑
  2. 요청 매핑 - api 예시
  3. HTTP 요청 - 기본, 헤더 조회
  4. HTTP 요청 파라미터 - 쿼리 파라미터, HTML Form
  5. HTTP 요청 파라미터 - @ModelAttribute
  6. HTTP 요청 메시지 - 단순 텍스트
  7. HTTP 요청 메시지 - JSON
  8. HTTP 응답 - 정적 리소스, 뷰 템플릿
  9. HTTP 응답 - HTTP API, 메시지 바디에 직접 입력

1. 요청 매핑

package hello.springmvc.basic.requestmapping;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

@RestController
public class MappingController {
	
    private Logger log = LoggerFactory.getLogger(getClass());
 	
    /**
 	* 기본 요청
 	* 둘다 허용 /hello-basic, /hello-basic/
 	* HTTP 메서드 모두 허용 GET, HEAD, POST, PUT, PATCH, DELETE
 	*/
 	@RequestMapping("/hello-basic")
 	public String helloBasic() {
 		log.info("helloBasic");
 		return "ok";
 	}
}

매핑 정보

  • @Controller

    • @Controller는 반환 값이 String이면 뷰 이름으로 인식된다. 그래서 뷰를 찾고 뷰가 랜더링 된다.
    • @RestController는 반환 값으로 뷰를 찾는게 아니라, HTTP메시지 바디에 바로 입력한다.
    • 따라서 실행결과로 ok 메세지를 받을 수 있다. @ResponseBody와 관련이 있는데, 뒤에서 더 자세히 설명한다.
  • @RequestMapping("/hello-basic")

    • /hello-basic URL 호출이 오면 이 메서드가 실행 되도록 매핑한다.

2. 요청 매핑 - API 예시

회원 관리를 HTTP API로 만든다 생각하고 매핑을 어떻게 하는지 알아보자.

package hello.springmvc.basic.requestmapping;

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

@RestController
@RequestMapping("/mapping/users")
public class MappingClassController {
	
    /**
 	* GET /mapping/users
 	*/
 	@GetMapping
 	public String users() {
 		return "get users";
 	}
 
 	/**
 	* POST /mapping/users
 	*/
 	@PostMapping
 	public String addUser() {
 		return "post user";
 	}
 
 	/**
 	* GET /mapping/users/{userId}
 	*/
 	@GetMapping("/{userId}")
 	public String findUser(@PathVariable String userId) {
 		return "get userId=" + userId;
 	}
 
 	/**
 	* PATCH /mapping/users/{userId}
 	*/
 	@PatchMapping("/{userId}")
 	public String updateUser(@PathVariable String userId) {
 		return "update userId=" + userId;
 	}
 
 	/**
 	* DELETE /mapping/users/{userId}
 	*/
 	@DeleteMapping("/{userId}")
 	public String deleteUser(@PathVariable String userId) {
 		return "delete userId=" + userId;
 	}
}

@RestController로 그냥 String을 반환해서 간단하게 테스트 해본 것이다.


3. HTTP 요청 - 기본, 헤더 조회

애노테이션 기반의 스프링 컨트롤러는 다양한 파라미터를 지원한다.

이번 시간에는 HTTP 헤더 정보를 조회하는 방법을 알아보자.

package hello.springmvc.basic.request;


import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

@RestController
@Slf4j
public class RequestHeaderController {
    @RequestMapping("/headers")
    public String headers(HttpServletRequest request,
                          HttpServletResponse response,
                          HttpMethod httpMethod,
                          Locale locale,
                          @RequestHeader MultiValueMap<String, String> headerMap,
                          @RequestHeader("host") String host,
                          @CookieValue(value="myCookie", required = false)String cookie) {

        log.info("request={}", request);
        log.info("response={}", response);
        log.info("httpMethod={}", httpMethod);
        log.info("locale={}", locale);
        log.info("headerMap={}", headerMap);
        log.info("header host={}", host);
        log.info("myCookie={}", cookie);

        return "ok";
    }
}
  • HttpMethod: HTTP 메서드를 조회한다.

  • Locale: Locale 정보를 조회한다.

  • @RequestHeader MMultiValueMap<String, String> headerMap: 모든 HTTP 헤더를 MultiValueMap 형식으로 조회한다.

  • @RequestHeader("host") String host: 특정 HTTP 헤더를 조회한다.

  • @CookieValue(value = "myCookie", required = false) String cookie: 특정 쿠키를 조회한다.


4. HTTP 요청 파라미터 - 쿼리 파라미터, HTML Form

📕 클라이언트에서 서버로 요청 데이터를 전달 할때 주로 사용하는 3가지 방법

  1. GET - 쿼리 파라미터
  • /url?username=hello&age=20
  • 메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달
  • ex) 검색, 필터, 페이징등에서 많이 사용
  1. POST - HTML Form
  • content-type: appplication/x-www-form-urlencoded
  • 메시지 바디에 쿼리 파라미터 형식으로 전달
  • ex) 회원 가입, 상품 주문, HTML Form 사용
  1. HTTP message body에 데이터를 직접 담아서 요청
  • HTTP API에서 주로 사용, JSON, XML, TEXT
  • 데이터 형식은 주로 JSON 사용
  • POST, PUT, PATCH

1. GET - 쿼리 파라미터

예시
http://localhost:8080/request-param?username=hello&age=20

@RequestMapping("/request-param-v1")
public void requestParamV1(HttpServletRequest request, HttpServletResponse  response) throws IOException {
	String username = request.getParameter("username");
 	int age = Integer.parseInt(request.getParameter("age"));
 	log.info("username={}, age={}", username, age);
 	response.getWriter().write("ok");
}

http://localhost:8080/request-param-v1?username=hello&age=20 실행시

HttpServletRequest에서 해당 파라미터를 가져올 수 있다.

2. HTML Form

HTML Form으로 데이터를 전송할 시 메시지 바디에 쿼리 파라미터 형식으로 보내짐

@ResponseBody
@RequestMapping("/request-param-v2")
public String requestParamV2(@RequestParam("username") String memberName, @RequestParam("age") int memberAge) {
    log.info("username={}, age={}", memberName, memberAge);

    return "ok";
}
  • @RequestParam: 파라미터 이름으로 바인딩

  • request.getParameter("username")과 같다.


5. HTTP 요청 파라미터 - @ModelAttribute

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

보통 다음과 같이 코드를 작성할 것이다.

@RequestParam String username;
@RequestParam int age;
HelloData data = new HelloData();
data.setUsername(username);
data.setAge(age);

스프링은 이 과정을 완전히 자동화해주는 @ModelAttribute 기능을 제공한다.

HelloData(DTO)

DTO라고 생각하는 클래스를 작성한다.

package hello.springmvc.basic;

import lombok.Data;

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

데이터를 쿼리 파라미터 형식으로 받을 때 사용한다.

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

@ModelAttribute
@ModelAttribute를 사용하면 HelloData 객체가 생성되고, 요청 파라미터의 값도 모두 들어가 있다.

스프링 MVC는 @ModelAttribute가 있으면 다음을 실행한다.

  • HelloData 객체를 생성한다.
  • 요청 파라미터의 이름으로 HelloData 객체의 프로퍼티를 찾는다. 그리고 해당 프로퍼티의 setter를 호출해 파라미터의 값으로 입력(바인딩)한다.
  • ex) 파라미터 이름이 username이면 setUsername() 메서드를 찾아 호출하면서 값을 입력한다.

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

  • HTTP message body에 데이터를 직접 담아서 요청
    • HTTP API에서 주로 사용, JSON, XML, TEXT
    • 데이터 형식은 주로 JSON 사용
    • POST, PUT, PATCH

요청 파라미터와 다르게, HTTP 메시지 바디를 통해 데이터가 직접 넘어오는 경우는 @RequestParam, @ModelAttribute 를 사용할 수 없다. (물론 HTML Form 형식으로 전달되는 경우는 요청 파라미터로 인정된다.)

HTTP 메시지 바디에 TEXT를 보낼일은 별로 없다.

InputStream을 사용해서 직접 읽을 수 있다.

@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(Reader): HTTP 요청 메시지 바디의 내용을 직접 조회
 * OutputStream(Writer): HTTP 응답 메시지의 바디에 직접 결과 출력
 */
@PostMapping("/request-body-string-v2")
public void requestBodyStringV2(InputStream inputStream, Writer responseWriter) throws IOException {
	String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
 	log.info("messageBody={}", messageBody);
 	
    responseWriter.write("ok");
}

스프링 MVC는 다음 파라미터를 지원한다.

  • InputStream(Reader): HTTP 요청 메시지 바디의 내용을 직접 조회
  • OutputStream(Writer): HTTP 응답 메시지의 바디에 직접 결과 출력

7. HTTP 요청 메시지 - JSON

이번에는 HTTP API에서 주로 사용하는 JSON 데이터 형식을 조회해보자.

/**
 * @RequestBody
 * HttpMessageConverter 사용 -> StringHttpMessageConverter 적용
 *
 * @ResponseBody
 * - 모든 메서드에 @ResponseBody 적용
 * - 메시지 바디 정보 직접 반환(view 조회X)
 * - HttpMessageConverter 사용 -> StringHttpMessageConverter 적용
 */
@ResponseBody
@PostMapping("/request-body-json-v2")
public String requestBodyJsonV2(@RequestBody String messageBody) throws IOException {
	private ObjectMapper objectMapper = new ObjectMapper();

	HelloData data = objectMapper.readValue(messageBody, HelloData.class);
 	log.info("username={}, age={}", data.getUsername(), data.getAge());
 	
    return "ok";
}

private ObjectMapper objectMapper = new ObjectMapper();

문자로된 JSON 데이터를 Jackson 라이브러리인 objectMapper를 사용해 자바 객체로 변환한다.

문자로 변환하고 다시 Json으로 변환하는 과정이 불편하다.

@ModelAttribute처럼 한번에 객체로 변환할 수는 없을까?

/**
 * @RequestBody 생략 불가능(@ModelAttribute 가 적용되어 버림)
 * HttpMessageConverter 사용 -> MappingJackson2HttpMessageConverter (content-type: application/json)
 *
 */
@ResponseBody
@PostMapping("/request-body-json-v3")
public String requestBodyJsonV3(@RequestBody HelloData data) {
	log.info("username={}, age={}", data.getUsername(), data.getAge());
 	return "ok";
}

@RequestBody 객체 파라미터

  • @RequestBody HelloData data
  • @RequestBody에 직접 만든 객체를 지정할 수 있다.

References(참고자료)
https://www.inflearn.com/

profile
개발자가 되는 그날까지

0개의 댓글