<목차>
1. HTTP 요청 데이터
-Client에서 Server로 Data를 전달하는 방법
2. Spring 요청 데이터
-@RequestParam
-@ModelAttribute
-HTTP Message Body(요청)
-TEXT
-HttpEntity
-@RequestBody, @ResponseBody
-JSON
-HTTPMessageConverter
3. Spring 응답 데이터
-Server에서 Client로 Data를 전달하는 방법
-정적 리소스
-View Template
-HTTP Message Body(응답)
4. CRUD 실습
Client에서 Server로 Data를 전달하는 방법
-크게 세가지 방법으로 나뉜다.
1. Query Parameter
2. HTTP Form Data
3. HTTP Request Body
1. GET + Query Parameter(=Query String)
-URL의 쿼리 파라미터를 사용하여 데이터를 전달하는 방법
http://localhost:8080/request-params?key1=value&key2=value2
-HttpServletRequest 사용
@Slf4j
@Controller
public class RequestParamController {
@GetMapping("/request-params")
public void params(
HttpServletRequest request,
HttpServletResponse response
) throws IOException {
String key1Value = request.getParameter("key1");
String key2Value = request.getParameter("key2");
log.info("key1Value={}, key2Value={}", key1Value, key2Value);
response.getWriter().write("success");
}
}
-response.getWriter().write()
- HttpServletResponse를 사용해서 응답값을 직접 다룰 수 있다.
- @Controller 지만 @ResponseBody를 함께 사용한 것과 같다.
-postman 요청
-Log 출력결과
2. POST + HTML Form(x-www-form-urlencoded)
-HTTP Request Body에 쿼리 파라미터 형태로 전달하는 방법
-HTTP Request
POST /form-data
content-type: application/x-www-form-urlencoded
key1=value1&key2=value2
-HttpServletRequest 사용
@Slf4j
@Controller
public class RequestBodyController {
@PostMapping("/form-data")
public void requestBody(
HttpServletRequest request,
HttpServletResponse response
) throws IOException {
String key1Value = request.getParameter("key1");
String key2Value = request.getParameter("key2");
log.info("key1Value={}, key2Value={}", key1Value, key2Value);
response.getWriter().write("success");
}
}
-postman
-Log 출력
+ HttpServletRequest.getParameter("key");를 사용하면
Query Parameter, HTML Form Data 두가지 경우 모두 데이터 형식(key = value)가 같기 때문에 해당 값에 접근할 수 있다.
3. HTTP Request Body
-데이터(JSON, TEXT, XML 등)를 직접 HTTP Message Body에 담아서 전달한다.
-주로 @RestController에서 사용하며, 대부분 JSON 형식으로 데이터를 전달한다.
- POST, PUT, PATCH Method에서 사용한다.
- GET, DELETE Method는 Body에 데이터를 담는 것을 권장하지 않는다.
-HttpServletRequest 사용
@Getter
@Setter
public class Board {
private String title;
private String content;
}
package com.example.springbasicannotation.controller;
import cohttp://m.example.springbasicannotation.entity.Board;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.PostMapping;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@Slf4j
@Controller
public class RequestBodyController {
// JSON을 객체로 변환해주는 Jackson 라이브러리
private ObjectMapper objectMapper = new ObjectMapper();
@PostMapping("/request-body")
public void requestBody(
HttpServletRequest request,
HttpServletResponse response
) throws IOException {
ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
log.info("messageBody={}", messageBody);
Board board = objectMapper.readValue(messageBody, Board.clss);
log.info("board.getTitle()={}, board.getContent()={}", board.getTitle(), board.getContent());
response.getWriter().write("success");
}
}
-Postman
-출력결과
+JSON을 Java 객체로 변환하려면 Jackson과 같은 라이브러리를 사용해야 한다.
-Spring Boot는 기본적으로 Jackson 라이브러리의 ObjectMapper를 제공하며, starter-web에 포함되어 있다.
@RequestParam
-URL에서 파라미터 값과 이름을 함께 전달하는 방식으로 주로 HTTP 통신 Method 중 GET 방식의 통신을 할 때 많이 사용한다.
-@Requestparam을 사용하면 요청 파라미터 값에 아주 쉽고 간편하게 접근(Parameter Binding)할 수 있다.
-? 뒤에 오는 URL
- Query String
- Query Parameter
- Request Param
-예시코드
@Slf4j
@Controller
public class RequestParamControllerV2 {
@ResponseBody
@GetMapping("/v1/request-param")
public String requestParamV1 (
@RequestParam("name") String userName,
@RequestParam("age") int userAge
) {
// logic
log.info("name={}", userName);
log.info("age={}", userAge);
return "success";
}
}
1. @Controller + @ResponseBody
-View를 찾는 것이 아니라 ResponseBody에 응답을 작성한다.(=@RestController)
2. @RequestParam
-파라미터 이름으로 바인딩한다.
3. @RequestParam("속성값")
-속성값이 파라미터 이름으로 매핑된다.
-Postman
-출력결과
-"속성값"과 변수명이 같으면 생략이 가능하다
ex. @RequestParam("name") String name
// GET http://localhost:8080/v2/request-param?name=sparta&age=100
@ResponseBody
@GetMapping("/v2/request-param")
public String requestParamV2 (
@RequestParam String name,
@RequestParam int age
) {
// logic
log.info("name={}", name);
log.info("age={}", age);
return "success";
}
*@RequestParam 사용법
1. 어노테이션, 속성값 모두 생략
-@RequestParam은 생략이 가능하다.
// GET http://localhost:8080/v3/request-param?name=sparta&age=100
@ResponseBody
@GetMapping("/v3/request-param")
public String requestParamV3 (
String name,
int age
) {
// logic
log.info("name={}", name);
log.info("age={}", age);
return "success";
}
-생략하면 @RequestParam(required=false) 필수 여부 속성이 default로 설정된다.
-단, 요청 파라미터와 이름이 완전히 같아야 한다.
-단순 타입(int, String, Integer 등)이어야 한다.
+위의 방식은 권장하지 않는다.
-명시적으로 표시되어 있지 않으면 팀의 협의가 있지 않는 경우 다른 개발자들에게 혼동을 주게 된다.
-최소 @RequestParam String name 속성값 생략 형태를 쓰면된다.
2. required 속성 설정
-파라미터의 필수 값을 설정한다.
-API 스펙을 규정할 때 사용한다.
@ResponseBody
@GetMapping("/v4/request-param")
public String requestParam (
@RequestParam(required = true) String name, // 필수
@RequestParam(required = false) int age // 필수가 아님
) {
// logic
log.info("name={}", name);
log.info("age={}", age);
return "success";
}
-@RequestParam을 사용하면 기본 Default 값은 True 이다.
-True로 설정된 파라미터 값이 요청에 존재하지 않으면 400 BadRequest(클라이언트 측 에러)
-Exception이 발생하지 않는 경우
ex) http://localhost:8080/v4/request-param?name=sparta&age=100
-Exception이 발생하는 경우
ex) http://localhost:8080/v4/request-param?age=100
ex) http://localhost:8080/v4/request-param
-required = false 설정이 되어 있으면 해당 파라미터는 없어도 된다.
주의) http://localhost:8080/v4/request-param?name=sparta 요청한다면?
-500 Error가 발생한다.
-int Type에는 null을 넣을 수 없다. 0이라도 들어가야 한다.
--따라서 보통 null을 허용하는 Integer로 사용하거나 default 옵션을 사용한다.
@ResponseBody
@GetMapping("/v4/request-param")
public String requestParam (
@RequestParam(required = true) String name, // 필수
@RequestParam(required = false) Integer age
) {
// logic
log.info("name={}", name);
log.info("age={}", age);
return "success";
}
-파라미터 Key 값만 있고 Value가 없는 경우
http://localhost:8080/request-param?name=
-null과 빈 문자열 ""은 다르다.
--위 형태는 빈 문자열 ""로 인식한다, True지만 통과가 되어 버린다. 주의!
3. default 속성 적용
-파라미터의 기본 값을 설정한다.
@ResponseBody
@GetMapping("/v5/request-param")
public String requestParam (
@RequestParam(required = true, defaultValue = "sparta") String name,
@RequestParam(required = false, defaultValue = "1") int age
) {
// logic
log.info("name={}", name);
log.info("age={}", age);
return "success"
}
-name Parameter의 값이 없으면 기본적으로 "sparta"로 설정한다.
ex) http://localhost:8080/v5/request-param?age=100
-age Parameter의 값이 없으면 기본적으로 1으로 설정한다.
ex) http://localhost:8080/v5/request-param?name=jy
ex) http://localhost:8080/v5/request-param
-주의) defaultValue 속성을 설정하게 되면 "" 빈 문자열의 경우에도 기본 값이 설정된다.
ex)http://localhost:8080/v5/request-param?name&age
4. Map 사용
-Parameter를 Map 형태로 조회가 가능하다.
@ResponseBody
@GetMapping("/v6/request-param")
public String requestParamV6(
@RequestParam Map<String, String> map
) {
// logic
log.info("name={}", map.get("name"));
log.info("age={}", map.get("age"));
return "success";
}
-Map 형태(key=value)로 조회가 가능하다.
ex)http://localhost:8080/v6/request-param?name=sparta&age=100
-MultiValueMap 형태(key=[value1, value2])로 조회가 가능하다.
@ResponseBody
@GetMapping("/v6/request-param")
public String requestParamV6(
@RequestParam MultiValueMap<String, String> map
) {
// logic
log.info("name={}", map.get("name"));
log.info("age={}", map.get("age"));
return "success";
}
ex) http://localhost:8080/v6/request-param?name=sparta&name=jy&name=student&age=100
-파라미터 Map의 Value가 1개인 경우에는 Map / 여러개인 경우 MultiValueMap을 사용한다.
-대부분의 파라미터 값은 한개만 존재한다.
@ModelAttribute
-요청 파라미터를 받아 필요한 Object로 바인딩 해준다.
-주로 HTML 폼에서 전송된 데이터를 바인딩하고 HTTP Method POST인 경우 사용된다.
1. 기존코드
-@Data는 @Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructer를 자동으로 설정해주는 역할을 한다.
ex) http://localhost:8080/v1/tutor + x-www-form-urlencoded
@Data
public class Tutor {
private String name;
private int age;
}
@Controller
public class ModelAttributeController {
@ResponseBody
@PostMapping("/v1/tutor")
public String requestParamV1(
@RequestParam String name,
@RequestParam int age
) {
Tutor tutor = new Tutor();
tutor.setName(name);
tutor.setAge(age);
return "tutor name = " + name + " age = " + age;
}
}
-@RequestParam의 Mapping을 사용하게 되면 위와 같은 객체를 생성하는 코드가 포함된다.
-@ModelAttribute는 해당 과정을 자동화한다.
-Postman
POST /v1/tutor
content-type: application/x-www-form-urlencoded
name=wonuk&age=100
2. @ModelAttribute 적용
ex) http://localhost:8080/v2/tutor + x-www-form-urlencoded
@ResponseBody
@PostMapping("/v2/tutor")
public String modelAttributeV2(
@ModelAttribute Tutor tutor
) {
String name = tutor.getName();
int age = tutor.getAge();
return "tutor name = " + name + " age = " + age;
}
-Postman
POST /v2/tutor
content-type: application/x-www-form-urlencoded
name=wonuk&age=100
*@ModelAttribute 동작 순서
- 파라미터에 @ModelAttribute가 있으면 파라미터인 Tutor 객체를 생성한다.
- 요청 파라미터 이름으로 객체 필드의 Setter를 호출해서 바인딩한다.
- 파라미터 이름이 name이면 setName(value); 메서드를 호출한다.
- 파라미터 이름과 필드 이름이 반드시 같아야 한다.
*@Data의 Setter가 없다면?
@Getter
public class Tutor {
private String name;
private int age;
}
-객체 필드에 값이 set 되지 않는다.
*파라미터의 타입이 다른 경우
-만약 요청 파라미터 age에 int가 아닌 String이 전달된다면?
ex)http://localhost:8080/v2/tutor + x-www-form-urlencoded
POST /v2/tutor
content-type: application/x-www-form-urlencoded
name=wonuk&age=nbcamp
-BindException 발생
-이런 경우 때문에 Validation(검증)이 필요하다.
3. @ModelAttribute 생략
-@ModelAttribute와 @RequestParam은 모두 생략이 가능하다.
ex) http://localhost:8080/v3/tutor + x-www-form-urlencoded
POST /v3/tutor
content-type: application/x-www-form-urlencoded
name=wonuk&age=100
@ResponseBody
@PostMapping("/v3/tutor")
public String modelAttributeV3(Tutor tutor) {
String name = tutor.getName();
int age = tutor.getAge();
return "tutor name = " + name + " age = " + age;
}
-Spring에서 @RequestParam 이나 @ModelAttribute가 생략되면 String, int, Integer와 같은 기본 타입은 @RequestParam과 Mapping한다.
@ResponseBody
@PostMapping("/v4/tutor")
public String requestParamV2(
String name,
int age
) {
return "tutor name = " + name + " age = " + age;
}
-나머지 경우들(객체)은 모두 @ModelAttribute와 Mapping 한다.
HTTP Message Body(요청)
-@RequestParam, @ModelAttribute는 Get + Query Parameter와 Post HTML Form Data를 바인딩 하는 방법이다.
-아래 방법들은 HTTP Message Body에 직접적으로 Data가 전달 되는 경우이다. = Requst Body의 Data를 바인딩 하는 방법.
-REST API에서 주로 사용하는 방식이다.
-HTTP Method POST, PUT, PATCH에서 주로 사용한다.
-GET은 Request Body가 존재할 수는 있지만 권장하지 않는다.
-JSON, XML, TEXT 등을 데이터 형식으로 사용한다.
*HTTP Message 구조
*HTTP Request, Response 예시
-Server에서 Request로 전달받은 Data를 처리하기 위해서 바인딩 해야한다.
ex) JSON -> Object
TEXT
-HTTP Request Body 에 Data가 전송되는 경우 HttpMessageConverter를 통해 바인딩 된다.
-요즘은 RestfulAPI를 주로 사용하고 있어서 대부분의 경우 JSON 형식으로 통신한다.
1. HttpServletRequest 예시
-request.getInputStream();
@Slf4j
@Controller
public class RequestBodyStringController {
@PostMapping("/v1/request-body-text")
public void requestBodyTextV1(
HttpServletRequest request,
HttpServletResponse response
) throws IOException {
ServletInputStream inputStream = request.getInputStream();
String bodyText = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
response.getWriter().write("response = " + bodyText);
}
}
*Postman
-Request → Body → raw → Text
*Request Header Content-Type : text/plain
2. I/O 예시
-InputStream(읽기) 파라미터 지원
- HTTP Request Body Data 직접 조회
-OutputStream(쓰기) 파라미터 지원
- HTTP Response Body 직접 결과 출력
@PostMapping("/v2/request-body-text")
public void requestBodyTextV2(
InputStream inputStream,
Writer responseWriter
) throws IOException {
String body = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
responseWriter.write("response = " + bodyText);
}
-Postman
3. HttpEntity 예시
-HttpMessageConverter 사용
-HttpEntity를 사용하면 HttpMessageConverter를 사용한다.
@PostMapping("/v3/request-body-text")
public HttpEntity<String> requestBodyTextV3(HttpEntity<String> httpEntity) {
// HttpMessageConverter가 동작해서 아래 코드가 동작하게됨
String body = httpEntity.getBody();
return new HttpEntity<>("response = " + body); // 매개변수 = Body Message
}
-Postman
-Spring의 HttpMessageConverter 덕분에 간편하게 Request Data에 접근할 수 있다.
- HttpEntity를 사용하면 HttpMessageConverter가 동작하여 자동으로 매핑된다.
- 요청 뿐만이 아닌 응답까지 HttpEntity 하나만으로 사용이 가능해진다.
-Converter 는 어떤 무언가를 다른 무언가로 바꿔주는(convert) 장치를 말한다.
HttpEntity
-HttpEntity : HTTP Header, Body 정보를 편리하게 조회할 수 있도록 만들어준다.
*HttpEntity 역할
- Http Request Body Message를 직접 조회한다.
- Request 뿐만 아니라 Response도 사용할 수 있도록 만들어준다.
- Response Header 또한 사용할 수 있다.
- Request Parameter를 조회하는 기능들과는 아무 관계가 없다.
- View를 반환하지 않는다.
*HttpEntity를 상속 받은 객체
-RequestEntity<>
- HTTP Request Method, URL 정보가 추가 되어있다.
-ResponseEntity<>
- HTTP Response 상태 코드 설정이 가능하다.
-코드예시
@Controller
public class RequestBodyStringController {
@PostMapping("/v4/request-body-text")
public HttpEntity<String> requestBodyTextV4(RequestEntity<String> httpEntity) {
// HttpMessageConverter가 동작해서 아래 코드가 동작하게됨
String body = httpEntity.getBody();
// url, method 사용 가능
return new ResponseEntity<>("response = " + body, HttpStatus.CREATED); // Body Data, 상태코드
}
}
-Postman
-위 방법을 적용해도 불편하다면 Data를 HttpEntity에서 꺼내서 사용해야한다.
-Spring은 Http RequestBody Message를 읽어서 String이나 Object로 자동으로 변환해준다. (-> HttpMessageConverter 사용)
@RequestBody, @ResponseBody
-Spring에서 @RequestBody, @ResponseBody 어노테이션을 사용하면 각각 Request, Response 객체의 Body에 편하게 접근하여 사용할 수 있다.
-코드 예시
@Controller // @RestController = @Controller + @ResponseBody
public class RequestBodyStringController {
@ResponseBody
@PostMapping("/v5/request-body-text")
public String requestBodyTextV5(
@RequestBody String body,
@RequestHeader HttpHeaders headers
) {
// HttpMessageConverter가 동작해서 아래 코드가 동작하게됨
String bodyMessage = body;
return "request header = " + headers + " response body = " + bodyMessage;
}
}
-Postman
- @RequestBody
- 요청 메세지 Body Data를 쉽게 조회할 수 있다.
- @RequestHeader
- 요청 헤더 정보 조회
- @ResponseBody
- 응답 메세지 바디에 값을 쉽게 담아서 전달할 수 있도록 해준다.
- View가 아닌 데이터를 반환한다.
*요약정리
- 요청 파라미터, HTML Form Data에 접근하는 경우
- @RequestParam, @ModelAttribute를 사용한다.
- Http Message Body에 접근하는 경우
- @RequestBody를 사용한다.(JSON, XML, TEXT)
JSON
-JSON은 @RestController에서 가장 많이 사용되는 데이터 형식이다.
-현재 대부분의 API는 Request, Response 모두 JSON 형태로 통신한다.
-JSON 형태로 Data를 전송할 때는 Request Header의 content-type이 꼭 application/json이어야 한다.
1. HttpServletRequest 사용
@Data
public class Tutor {
private String name;
private int age;
}
@RestController
public class JsonController {
private ObjectMapper objectMapper = new ObjectMapper();
@PostMapping("/v1/request-body-json")
public void requestBodyJsonV1(
HttpServletRequest request,
HttpServletResponse response
) throws IOException {
// request body message를 Read
ServletInputStream inputStream = request.getInputStream();
// UTF-8 형식의 String으로 변환한다.
String requestBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
// String requestBody를 ObjectMapper를 사용하여 변환 "{\"name\":\"wonuk\", \"age\":10}"
Tutor tutor = objectMapper.readValue(requestBody, Tutor.class);
// 응답
response.getWriter().write("tutor" + tutor);
}
}
*Postman
- Content-Type 헤더 확인 : application/json
-HttpServletRequest를 사용하여 HTTP Message Body 데이터를 Read 하여 문자로 변환한다.
-문자로 만들어진 JSON을 jackson 라이브러리의 objectMapper를 사용하여 Object로 변환
2. @RequestBody 사용
@RestController
public class JsonController {
private ObjectMapper objectMapper = new ObjectMapper();
@PostMapping("/v2/request-body-json")
public String requesBodytJsonV2(@RequestBody String requestBody) throws IOException {
Tutor tutor = objectMapper.readValue(requestBody, Tutor.class);
return "tutor.getName() = " + tutor.getName() + "tutor.getAge() = " + tutor.getAge();
}
}
-Postman
-@RequestBody를 사용하여 HTTP Request Body의 Data에 접근한다.
3. ObjectMapper 제거
@RestController
public class JsonController {
@PostMapping("/v3/request-body-json")
public String requestBodyJsonV3(@RequestBody Tutor tutor) {
Tutor requestBodyTutor = tutor;
return "tutor = " + requestBodyTutor;
}
}
-Postman
-위 Controller가 동작하는 이유는?
*@RequestBody
-@RequestBody 어노테이션을 사용하면 Object를 Mapping 할 수 있다.
-HttpEntity<>, @RequstBody를 사용하면 HTTPMessageConverter가 Request Body의 Data를 개발자가 원하는 String이나 Object로 변환해준다.
-JSON to Object의 Mapping 또한 가능하다.
-MappingJackson2HttpMessageConverter의 역할
-쉽게 설명하면 HTTP Message Converter가 ObjectMapper를 대신 실행한다.
4. @RequestBody는 생략할 수 없다.
-@RequestParam, @ModelAttribute는 생략이 가능하다.
@Slf4j
@RestController
public class JsonController {
@PostMapping("/v4/request-body-json")
public String requestBodyJsonV4(Tutor tutor) { // @RequestBody 생략시 @ModelAttribute가 된다.
Tutor requestBodyTutor = tutor;
return "tutor.getName() = " + requestBodyTutor.getName() + " tutor.getAge() = " + requestBodyTutor.getAge();
}
}
-Postman
-생략하면 @ModelAttribute가 된다.
- 요청 파라미터를 처리하도록 설정된다.
-Request Header의 contentType은 꼭 application/json이여야 한다.
- 위 설정 정보를 기반으로 MessageConverter가 실행된다.
5. HttpEntity 사용
@RestController
public class JsonController {
@PostMapping("/v5/request-body-json")
public String requestBodyJsonV5(
HttpEntity<Tutor> httpEntity
) {
// 값을 꺼내서 사용해야한다!
Tutor tutor = httpEntity.getBody();
return "tutor.getName() = " + tutor.getName() + " tutor.getAge() = " + tutor.getAge();
}
}
-Postman
-HttpEntity<Tutor>
- Generic Type으로 Tutor가 지정되어 있기 때문에 해당 Class로 반환된다.
6. @ResponseBody
@Controller
public class JsonController {
@ResponseBody // @RestController = @Controller + @ResponseBody
@PostMapping("/v6/request-body-json")
public Tutor requestJson(@RequestBody Tutor tutor) {
return tutor;
}
}
-Postman
-View를 조회하지 않고 ResponseBody에 Data를 입력해서 직접 반환한다.
-요청 뿐만이 아니라 응답에도 HttpMessageConverter가 동작한다.
- MappingJackson2HttpMessageConverter 적용
- 응답 객체인 Tutor가 JSON으로 변환되어 반환된다.
-HttpEntity를 사용해도 된다.
*정리
- 요청 데이터는 @RequestBody를 사용해서 바인딩하면 된다.
- @RequestBody는 생략이 불가능하다.
- @ModelAttribute가 적용되기 때문
- HttpMessageConverter가 요청 응답 데이터를 모두 변환할 수 있다.
- JSON은 MappingJackson2HttpMessageConverter를 사용한다.
- Request Header의 Content-Type은 application/json 이어야 한다.
- Header로 어떤 Converter가 동작할지 판별한다.
HTTPMessageConverter
-Spring Framework에서 HTTP 요청과 응답을 변환하는 인터페이스이다.
-클라이언트와 서버 간에 데이터를 주고 받을 때, 요청 데이처를 자바 객체로 변환하거나 자바 객체를 응답 데이터로 변환하는 역할을 수행한다.
-MappingJackson2HttpMessageConverter 는 JSON을 처리하는 대표적인 HTTPMessageConverter의 구현체이다.
*HttpMessageConverter의 역할
-데이터를 Object로 변환한다.
-대표적으로 JSON을 변환한다.
-@RequestBody
- 요청 데이터 + Request Header를 참고하여 Object로 변환한다.
- HTTP Request Body(JSON Data) -> Converter(jackson) -> Object
- Request Header -> Content-Type:application/json(전달할 데이터 형식)
-@ResponseBody
- 응답 데이터 + Accept Header를 참고하여 원하는 데이터 형식으로 변환한다.
- Object -> Converter(jackson) -> HTTP Response Body(JSON Data)
- Request Header -> Accept: application/json(허용할 데이터 형식)
Server에서 Client로 Data를 전달하는 방법
1. 정적 리소스
2. View Template
3. HTTP Message Body
1. 정적 리소스
-정적인 HTML, CSS, JS, Image 등을 변경 없이 그대로 반환한다.
2. View Template
-SSR(Server Side Rendering)을 사용할 때 View가 반환된다.
3. HTTP Message Body
-응답 데이터를 직접 Message Body에 담아 반환한다.
정적 리소스
-웹 애플리케이션에서 변하지 않는 파일들을 의미
-HTML, CSS, JS, 이미지 파일들(JPG, PNG, GIF) 등이 정적 리소스에 해당한다.
*Spring Boot의 정적 리소스 경로
-이 경로들에 정적 리소스가 존재하면 서버에서 별도의 처리 없이 파일 그대로 반환된다.
- /static
- /public
- /META-INF/resources
- src/main/resources
- /static
*Spring Boot Directory 구조
-src/main/resources/static/hello/world.html 디렉토리 구조라면 http://localhost:8080/hello/world.html URL로 리소스에 접근이 가능하다.
-/static 대신 /public 혹은 /META-INF/resources도 사용가능하다.
View Template
-Spring에서는 Thymeleaf, JSP와 같은 템플릿 엔진을 사용해 View Template을 작성할 수 있다.
-View Template은 서버에서 데이터를 받아 이를 HTML 구조에 맞게 삽입한 후 최종적으로 클라이언트에게 전송되는 HTML 문서로 변환하여 사용자에게 동적으로 생성된 웹 페이지를 제공한다.
*View Template
-View Template은 Model을 참고하여 HTML 등이 동적으로 만들어지고 Client에 응답된다.
-Spring Boot는 기본적으로 View Template 경로(src/main/resources/templates)를 설정한다.
-build.gradle에 Thymeleaf 의존성을 추가하면 ThymeleafViewResolver와 필요한 Spring Bean들이 자동으로 등록된다.
*기본 설정 예시
-아래 내용을 자동으로 Spring Boot가 등록해준다.
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html // or jsp
1. @Controller의 응답으로 String을 반환하는 경우
-@ResponseBody가 없으면 View Resolver가 실행되며 View를 찾고 Rendering 한다.
@Controller
public class ViewTemplateController {
@RequestMapping("/response-view")
public String responseView(Model model) {
// key, value
model.addAttribute("data", "sparta");
return "thymeleaf-view";
}
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Hello</title>
</head>
<body>
<h1>Thymeleaf</h1>
<h2 th:text="${data}"></h2>
</body>
</html>
ex) http://localhost:8080/response-view
-@ResponseBody가 있으면 HTTP Message Body에 return 문자열 값이 입력된다.
@Controller
public class ViewController {
@ResponseBody // @RestController = @Controller + @ResponseBody
@RequestMapping("/response-body")
public String responseBody() {
return "thymeleaf-view";
}
}
-postman
2. 반환 타입이 void인 경우
-잘 사용하지 않는다.
-@Controller + (@ResponseBody, HttpServletResponse, OutputStream)과 같은 HTTP Message Body를 처리하는 파라미터가 없으면 RequestMapping URL을 참고하여 View Name으로 사용한다.
@Controller
public class ViewTemplateController {
// thymeleaf-view.html 과 Mapping된다.
@RequestMapping("/thymeleaf-view")
public void responseViewV2(Model model) {
model.addAttribute("data", "sparta");
}
}
-예시와 같은 경우에는 viewTemplate(viewName)을 RequestMapping URL 주소로 찾는다.
HTTP Message Body(응답)
-REST API를 만드는 경우 Server에서 Client로 HTML을 전달하는 방식이 아닌 HTTP Message Body에 직접 Data를 JSON 형식으로 담아 전달한다.
-정적 HTML, View Template 또한 HTTP Message Body에 담겨서 전달된다.
-Response의 경우 정적 HTML, View Template을 거치지 않고 직접 HTTP Response Message를 만들어 전달하는 경우를 말한다.
*HTTP Message Body
1. HttpServletResponse 사용
@Controller
public class ResponseBodyController {
@GetMapping("/v1/response-body")
public void responseBodyV1(
HttpServletResponse response
) throws IOException {
response.getWriter().write("data");
}
}
-postman
-Response Body에 data라는 문자열이 입력되어 응답된다.
-기존 Servlet을 다룰 때 코드와 형태가 같다.
2. ResponseEntity<> 사용
@GetMapping("/v2/response-body")
public ResponseEntity<String> responseBodyV2() {
return new ResponseEntity<>("data", HttpStatus.OK);
}
-postman
-Response Body에 data라는 문자열과 HttpStatus.OK에 해당하는 상태 코드를 반환한다.
-ResponseEntity는 HttpEntity를 상속받았다.
-HttpEntity는 HTTP Message의 Header, Body 모두 가지고 있다.
3. @ResponseBody(TEXT, JSON) 사용
@Data
@NoArgsConstructor // 기본 생성자
@AllArgsConstructor // 전체 필드를 인자로 가진 생성자
public class Tutor {
private String name;
private int age;
}
// TEXT 데이터 통신
@ResponseBody
@GetMapping("/v3/response-body-text")
public String responseBodyText() {
return "data"; // HTTP Message Body에 "data"
}
-postman
// JSON 데이터 통신
@ResponseBody
@GetMapping("/v3/response-body-json")
public Tutor responseBodyJson() {
Tutor tutor = new Tutor("wonuk", 100);
return tutor; // HTTP Message Body에 Tutor Object -> JSON
}
-postman
-View를 사용하는 것이 아닌 HTTP Message Converter를 통해 HTTP Message Body를 직접 입력할 수 있다.(=ResponseEntity)
-@ResponseStatus를 사용하여 상태 코드를 지정할 수 있다.
@ResponseStatus(HttpStatus.OK)
@ResponseBody
@GetMapping("/v4/response-body")
public Tutor responseBodyV4() {
Tutor tutor = new Tutor("wonuk", 100);
return tutor;
}
-postman
-단, 응답코드를 조건에 따라서 동적으로 변경할 수는 없다.
ex) 1번의 경우 OK, 2번의 경우 Created
4. ResponseEntity<Object>(JSON)
@ResponseBody
@GetMapping("/v5/response-body")
public ResponseEntity<Tutor> responseBody() {
Tutor tutor = new Tutor("wonuk", 100);
return new ResponseEntity<>(tutor, HttpStatus.OK);
}
-postman
-ResponseEntity<> 두번째 파라미터에 Enum을 사용하여 상태 코드를 바꿀 수 있다.
-HTTP Message Converter를 통하여 JSON 형태로 변환되어 반환된다.
-동적으로 응답 코드를 변경할 수 있다.
@ResponseBody
@GetMapping("/v5/response-body")
public ResponseEntity<Tutor> responseBody() {
Tutor tutor = new Tutor("wonuk", 100);
if (조건) {
return new ResponseEntity<>(tutor, HttpStatus.OK);
} else {
return new ResponseEntity<>(tutor, HttpStatus.BAD_REQUEST);
}
}
-HttpEntity를 상속 받았다.
'내배캠 > Spring' 카테고리의 다른 글
[내일배움캠프/백엔드] JPA 심화 강의 내용 정리 (1) | 2024.12.12 |
---|---|
[내일배움캠프/백엔드] 심화 Spring 1주차 강의 (0) | 2024.11.27 |
[내일배움캠프/백엔드] 기초 Spring 4주차 강의 (0) | 2024.11.06 |
[내일배움캠프/백엔드] 기초 Spring 3주차 강의 (1) | 2024.11.05 |
[내일배움캠프/백엔드] 기초 Spring 2주차 강의 (3) | 2024.11.04 |