[Spring] MVC - 1 복습 총 정리 下

bin1225·2023년 1월 31일
0

Spring

목록 보기
15/15
post-thumbnail

6. 스프링 MVC 기본 기능

요청 매핑

  • 기본 형태
@RequestMapping(value = "/mapping/v1, method = RequestMethod.GET)
public String mappingV1(){
	...
}
  • Http method 매핑 축약
    보통 이 방법을 사용한다.
@GetMapping(value = "/mapping/v1") //Get, Post, Put, Delete, Patch
public String mappingV1(){
	...
}

경로변수 (Path Variable) 사용

@GetMapping(value = "/mapping/v1/{userId}") //Get, Post, Put, Delete, Patch
public String mappingV1(@PathVariable("userId") String data){
	...
}
  • { }안에 변수명을 넣고 @PathVariable 어노테이션을 이용해 값을 읽을 수 있다.
    -> 이것도 다 어댑터가 알맞게 작동하기 때문이다.
    ("userId")를 생략하면 변수명과 비교해 값을 저장한다. 이 경우는 data.

다중 Path Variable

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

조건 매핑

다양한 조건을 걸어 매핑을 할 수도 있다.

특정 파라미터 조건 매핑

@GetMapping(value = "/mapping-param", params = "mode=debug")

파라미터 조건 매핑은 잘 사용하지 않는 편이다.

헤더 조건 매핑

@GetMapping(value = "/mapping-param", headers = "mode=debug")

미디어 타입 조건 매핑

@PostMapping(value = "/mapping-consume", consumes = "application/json")

@PostMapping(value = "/mapping-produce", produces = "text/html")
  • consumes : 클라이언트가 서버에게 보내는 데이터 타입을 명시한다.
  • produces : 서버가 클라이언트에게 반환하는 데이터 타입을 명시한다.

HTTP 요청 조회

기본, 헤더 조회

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
 )
  • @RequestHeader MultiValueMap<String, String> headerMap, : 모든 header 정보를 MultiValueMap 형식으로 조회한다.
    -> 하나의 key에 여러개의 값을 받을 수 있다. valueList
  • @CookieValue(value = "myCookie", required = false) String cookie : 특정 쿠키를 조회한다.
    - 필수 값 여부: required
    - 기본 값: defaultValue

쿼리 파라미터, HTML Form 조회

public String requestParamV2(
 @RequestParam("username") String memberName,
 @RequestParam("age") int memberAge) {
 	...
}

기존 서블릿에서는 request.getXXX 후 타입변환 및 변수에 저장하는 방식이었는데,
Spring은 이 과정을 자동화해준다.

  • HTTP 파라미터 이름이 변수 이름과 같으면 @RequestParam(name="xx") 생략 가능 -> 생략시 required = false 적용
  • String , int , Integer 등의 단순 타입이면 @RequestParam 도 생략 가능

    너무 많이 생략하는 것은 과할 수 있다. 적당히 생략하여 코드를 명확하게.

파라미터 필수 여부 및 기본값

public String requestParamDefault(
 @RequestParam(required = true, defaultValue = "guest") String username,
 @RequestParam(required = false, defaultValue = "-1") int age) {
 	...
}

required = false 이고 값이 들어오지 않으면 null 값이 저장된다.
-> 기본형(ex int) 에는 null값이 저장 불가능하므로, Integer를 사용하거나 기본값을 지정해준다.

Map, MultiValueMap

public String requestParamMap(@RequestParam Map<String, Object> paramMap) {
 	log.info("username={}, age={}", paramMap.get("username"),
	paramMap.get("age"));
	return "ok";
}

Map 자료구조를 이용해 Parameter를 받을 수 있다.

  • 파라미터의 값이 1개가 확실하다면 Map, 아니면 MultiValueMap을 사용

HTTP 요청 파라미터 - @ModelAttribute

일반적으로는 요청 파라미터를 받아서, 필요한 객체에 값을 넣어 사용한다.
하지만 스프링은 이 과정을 자동화해주는 @ModelAttribute 기능을 제공한다.

이것도 어댑터의 효능이지 않을까

@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@ModelAttribute HelloData helloData) {
 	...
}

이렇게 @ModelAttribute를 클래스명 앞에 붙이면, 해당 프로퍼티의 setter를 호출하여, 값을 알아서 주입해준다.

  • @RequestParam 과 마찬가지로 @ModelAttribute도 생략 가능하다.
    하지만 적당히 생략할 것.
    생략시 기본타입 -> @RequestParam 나머지 -> @ModelAttribute 적용

프로퍼티

객체에 getUsername() , setUsername() 메서드가 있으면, 이 객체는 username 이라는 프로퍼티를 가지고 있다.
username 프로퍼티의 값을 변경하면 setUsername() 이 호출되고, 조회하면 getUsername() 이호출된다.

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

1. request.getInputStream();

ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
  • inputStream을 바로 파라미터로 받는 것도 지원한다.

2. HttpEntity

public HttpEntity<String> requestBodyStringV3(HttpEntity<String> httpEntity) {
 	String messageBody = httpEntity.getBody();
 	log.info("messageBody={}", messageBody);
	return new HttpEntity<>("ok");
}

Spring MVC는 HttpEntity를 지원한다.

  • HttpEntity : HTTP header, body 정보를 편리하게 조회
  • 응답시에도 사용되며, HttpEntity를 상속받은 RequestEntity, ResponseEntity 기능도 제공된다.

3. @RequestBody

public String requestBodyStringV4(@RequestBody String messageBody) {
	...
}

결론 .
요청 파라미터, html요청 조회 -> @RequestParam, @ModelAttribute
Http Body 메시지 직접 조회 -> @RequestBody

HTTP 요청 메시지 - JSON

기존 서블릿에서 했던 대로라면, messagebody를 읽어온 후, objectMapper를 통해 자바 객체로 변환했다.

하지만 Spring은 이것도 자동으로 해준다!

RequestBody

public String requestBodyJsonV3(@RequestBody HelloData data) {
	...
}

HttpEntity

public String requestBodyJsonV4(HttpEntity<HelloData> httpEntity) {
	 HelloData data = httpEntity.getBody();
}
  • HttpEntity , @RequestBody 를 사용하면 HTTP 메시지 컨버터가 HTTP 메시지 바디의 내용을 우리가 원하는 문자나 객체 등으로 변환해준다.

HTTP 응답

정적 리소스, 뷰 템플릿

  • 정적 리소스
    경로 : src/main/resources/static
    src/main/resources/static/basic/hello-form.html ->
    http://localhost:8080/basic/hello-form.html 해당 경로로 요청시, 정적 리소스를 제공한다.

  • 뷰 템플릿
    경로 :src/main.resources/templates

기본적으로 Controller에서 뷰의 논리 이름을 반환하면, Model에 담긴 데이터를 이용하여 템플릿엔진이 뷰를 렌더링 하고 반환한다.

 @RequestMapping("/response-view-v2")
 public String responseViewV2(Model model) {
 	model.addAttribute("data", "hello!!");
 	return "response/hello";
 }

controller에서 반환타입을 void로 해도, 요청 url을 참고하여 뷰를 찾지만 권장하지 않는다.

application properties에서 prefix, suffix를 설정할 수 있다. 기본적으로는 다음과 같이 설정돼있다.

spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

HTTP API, 메시지 바디

@ResponseBody어노테이션이 붙은 경우, 직접 Http 메시지 바디에 데이터를 담아서 전송한다.
1. HttpEntity - ResponseEntity
응답코드를 동적으로 설정할 수 있다.

public ResponseEntity<HelloData> responseBodyJsonV1() {
 	HelloData helloData = new HelloData();
 	helloData.setUsername("userA");
 	helloData.setAge(20);
 	return new ResponseEntity<>(helloData, HttpStatus.OK);
 }
  1. @ResponseBody
@ResponseStatus(HttpStatus.OK)
 @ResponseBody
 @GetMapping("/response-body-json-v2")
 public HelloData responseBodyJsonV2() {
	HelloData helloData = new HelloData();
 	helloData.setUsername("userA");
 	helloData.setAge(20);
 	return helloData;
 }

이 경우에도 @ResponseStatus를 이용해 Status를 설정할 수 있지만, 고정적이라는 한계가 있다.
Controller 대신RestController 어노테이션이 붙은 경우는 ResponseBody가 기본적으로 적용된다.

HTTP 메시지 컨버터

스프링 MVC는 다음의 경우에 HTTP 메시지 컨버터를 적용한다.

  • HTTP 요청: @RequestBody , HttpEntity(RequestEntity)
  • HTTP 응답: @ResponseBody ,HttpEntity(ResponseEntity)

메시지 컨버터는 대상 클래스 타입과 Http 미디어 타입을 체크해서 둘 다 만족하는 경우 사용여부를 결정한다.
1. ByteArrayHttpMessageConverter : byte[] 데이터를 처리한다.
클래스 타입: byte[] , 미디어타입 : */* ,
2. StringHttpMessageConverter : String 문자로 데이터를 처리한다.
클래스 타입: String , 미디어타입 : */*
3. MappingJackson2HttpMessageConverter : application/json
클래스 타입: 객체 또는 HashMap , 미디어타입 : application/json 관련

Spring을 이용하면, Controller에서 다양한 매개변수를 편리하게 받아 사용할 수 있는데, 이것을 가능하게 하는 것이 Argument Resolver다.
그리고 이 Argument Resolver에서 HttpMessageConverter를 호출하여 사용한다.

일단은 어노테이션 기반 Handler Adapter가 Argument Resolver를 사용한다고 이해했는데, 뭔가 내가 이해하고 있던 Adapter의 역할을 Arguement Resolver가 한다고 해서 조금 혼란스럽지만, 결국 둘이 같이 잘 해결하는 거니까 일단은 넘어간다..

스프링이 필요한 대부분의 기능을 제공하기 때문에 실제 기능을 확장할 일이 많지는 않다. 기능 확장은
WebMvcConfigurer 를 상속 받아서 스프링 빈으로 등록하면 된다. 실제 자주 사용하지는 않으니 실제 기능확장이 필요할 때 WebMvcConfigurer 를 검색해보자.

0개의 댓글