* 인프런의 Spring Boot를 이용한 RESTful Web Services 개발 강의를 듣고 정리한 내용입니다.
섹션 3에서 다루는 것
- Validation
- Internationalization
- XML format으로 반환하기
- Filtering
- Version 관리
유효성 체크를 위한 Validation API 사용
사용자 입력값의 유효성을 체크하려면 어떤 코드를 추가해야 하는지 배울 수 있다.
User.java 파일 변경 내용
package com.example.demo.user;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Date;
@Data
@AllArgsConstructor
public class User {
private Integer id;
@Size(min=2, message = "Name은 2글자 이상 입력해 주세요.")
private String name;
@Past
private Date joinDate;
}
name에 최소 글자 수와 message를 추가했다.
CustomizedResponseEntityExceptionHandler.java 파일 추가 내용
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatusCode status,
WebRequest request) {
ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(),
"Validation Failed", ex.getBildingResult().toString());
return this.handleExceptionInternal(ex, (Object)null, headers, status, request);
}
@Override 어노테이션으로 handleMethodArgumentNotValid 함수를 재정의했다.
UserController.java 파일 변경 내용
@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
User savedUser = service.save(user);
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
.path("/id")
.buildAndExpand(savedUser.getId())
.toUri();
return ResponseEntity.created(location).build();
}
@Valid 라는 어노테이션을 @RequestBody 앞에 추가시켜준다.
다국어 처리를 위한 Internationalization 구현 방법
DemoApplication.java 파일 추가 내용
@Bean
Public LocaleResolver localeResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(Locale.KOREA);
return localeResolver;
}
application.yml 파일 추가 내용
spring:
messages:
basename:messages
resources 경로 아래에 messages.properties 파일 추가
greeting.message=안녕하세요
messages_fr.properties 파일 내용
greeting.message=Bonjour
messages_en.properties 파일 내용
greeting.message=Hello
HelloWorldController.java 파일 추가 내용
@Autowired
private MessageSource messageSource;
@GetMapping(path = "/hello-world-internationalized")
public String helloWorldInternationalized(
@RequestHeader(name="Accept Language", required=false) Locale locale) {
return messageSource.getMessage("greeting.message",null, locale);
}
이렇게 위의 파일들을 각각 생성 및 수정 후 Postman에서 hello-world-internationalized 경로로 접속한 후 요청 Headers에 Accept-Language 를 추가하여 VALUE에 en, fr 등으로 변경하면 Hello와 Bonjour가 출력되는 것을 확인 가능하다.
Response 데이터 형식 변환 - XML format
pom.xml 파일 내용 추가
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.10.2</version>
</dependency>
위의 내용을 추가한 후 Postman으로 application/xml 형식으로 send를 하면 오류나지 않고 출력에 성공하는 것을 확인할 수 있다.
Response 데이터 제어를 위한 Filtering
User.java 추가 내용
@JsonIgnoreProperties(value={"password"})
private String password;
private String ssn;
어노테이션 @JsonIgnoreProperties 는 클래스 정의 전에 작성해주고 password와 ssn은 클래스 내부에 작성한다.
UserDaoService.java 파일 수정 내용
static {
users.add(new User(1,"Kenneth", new Date(), "pass1", "701010-1111111"));
users.add(new User(2,"One", new Date(),"pass2", "801010-2222222"));
users.add(new User(3,"Two", new Date(),"pass3", "901010-1111111"));
}
새로 추가한 password와 ssn 값을 추가했다.
그 결과 Postman으로 보면 /users 경로에서 password 값은 보이지 않고 id, name, joinDate, ssn 4가지 값만 모든 사용자에 대해 출력되는 것을 알 수 있다.
프로그래밍으로 제어하는 Filtering 방법 - 개별 사용자 조회
AdminUserController.java 파일 내용
package com.example.demo.user;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/admin")
public class AdminUserController {
private UserDaoService service;
//의존성 주입
//스프링에서 빈을 의존성 주입으로 관리한다.
public AdminUserController(UserDaoService service) {
this.service = service;
}
@GetMapping("/users")
public List<User> retrieveAllUsers() {
return service.findAll();
}
@GetMapping("/users/{id}")
public MappingJacksonValue retrieveUser(@PathVariable int id) {
User user = service.findOne(id);
if (user == null) {
throw new UserNotFoundException(String.format("ID[%s] not found", id));
}
SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter
.filterOutAllExcept("id","name","joinDate","ssn");
FilterProvider filters = new SimpleFilterProvider().addFilter("UserInfo", filter)
MappingJacksonValue mapping = new MappingJacksonValue(user);
mapping.setFilters(filters);
return mapping;
}
}
User.java 파일 수정 및 추가 내용
//@JsonIgnoreProperties(value={"password"})
@JsonFilter("UserInfo")
어노테이션 @JsonFilter를 추가해준다. UserInfo로 지정해준다.
AdminUserController.java 파일에서 addFilter로 추가해주고 setFilters 등 필요한 내용을 추가한다.
Postman으로 /admin/users/1 경로에 접속하면 id, name, joinDate, ssn 4가지 정보가 잘 출력되는 것을 확인할 수 있다.
프로그래밍으로 제어하는 Filtering 방법 - 전체 사용자 조회
AdminUserController.java 파일 수정 내용
@GetMapping("/users")
public MappingJacksonValue retrieveAllUsers() {
List<User> users = service.findAll();
SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter
.filterOutAllExcept("id","name","joinDate","password");
FilterProvider filters = new SimpleFilterProvider().addFilter("UserInfo", filter)
MappingJacksonValue mapping = new MappingJacksonValue(users);
mapping.setFilters(filters);
return mapping;
}
전체 사용자를 조회하는 부분에 filtering 하는 코드를 추가했다.
Postman으로 /admin/users 경로에 접속하면 전체 사용자의 id, name, joinDate, password 값을 확인 가능하다.
URI를 이용한 REST API Version 관리
UserV2.java 파일 내용
package com.example.demo.user;
import com.fasterxml.jackson.annotation.JsonFilter;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
//@JsonIgnoreProperties(value={"password"})
@JsonFilter("UserInfoV2")
public class UserV2 extends User {
private String grade;
}
AdminUserController.java 파일 추가 및 수정 내용
@GetMapping("v1/users/{id}")
public MappingJacksonValue retrieveUserV1(@PathVariable int id) {
User user = service.findOne(id);
if (user == null) {
throw new UserNotFoundException(String.format("ID[%s] not found", id));
}
SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter
.filterOutAllExcept("id","name","joinDate","ssn");
FilterProvider filters = new SimpleFilterProvider().addFilter("UserInfo", filter)
MappingJacksonValue mapping = new MappingJacksonValue(user);
mapping.setFilters(filters);
return mapping;
}
@GetMapping("v2/users/{id}")
public MappingJacksonValue retrieveUserV2(@PathVariable int id) {
User user = service.findOne(id);
if (user == null) {
throw new UserNotFoundException(String.format("ID[%s] not found", id));
}
// User -> User2
UserV2 userV2 = new UserV2();
BeanUtils.copyProperties(user, userV2);
userV2.setGrade("VIP");
SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter
.filterOutAllExcept("id","name","joinDate","grade");
FilterProvider filters = new SimpleFilterProvider().addFilter("UserInfoV2", filter);
MappingJacksonValue mapping = new MappingJacksonValue(userV2);
mapping.setFilters(filters);
return mapping;
}
User.java 파일 추가 내용
@NoArgsConstructor
이렇게 3개의 파일을 추가 및 수정해주면 v1 버전과 v2 버전의 사용자 개별 조회에서 차이가 발생하게 된다.
Postman으로 /admin/v2/users/1 경로로 send를 보내면 Grade가 VIP라고 출력해주는 것을 알 수 있다.
Request Parameter와 Header를 이용한 API Version 관리
AdminUserController.java 수정 내용
// @GetMapping("v1/users/{id}")
@GetMapping(value = "/users/{id}", params = "version=1")
// @GetMapping("v2/users/{id}")
@GetMapping(value = "/users/{id}", params = "version=2")
value에 경로를 그대로 두고 params에 버전 정보를 적어준다.
그 후 Postman으로 /admin/users/1/?version=2 로 테스트해보면 grade가 "VIP"로 나온다.
다음으로 Header를 이용한 API Version 관리이다.
AdminUserController.java 수정 내용
// @GetMapping(value = "/users/{id}", params = "version=1")
@GetMapping(value = "/users/{id}", headers="X-API-VERSION=1")
// @GetMapping(value = "/users/{id}", params = "version=2")
@GetMapping(value = "/users/{id}", headers="X-API-VERSION=2")
headers 정보를 추가해준다.
그 후 Postman으로 headers에 X-API-VERSION 값을 1이나 2로 넣어서 테스트해보면 버전 별로 잘 나온다.
Media Type으로 Version 관리하기
AdminUserController.java 수정 내용
// @GetMapping(value = "/users/{id}", headers="X-API-VERSION=1")
@GetMapping(value="/users/{id}", produces = "application/vnd.company.appv1+json")
// @GetMapping(value = "/users/{id}", headers="X-API-VERSION=2")
@GetMapping(value="/users/{id}", produces = "application/vnd.company.appv2+json")
produces 정보를 추가해준다.
그 후 Postman으로 Accept에 application/vnd.company.appv2+json 값을 넣어서 테스트해보면 v2 버전으로 잘 나오는 것을 알 수 있다.
'Programming > Spring boot' 카테고리의 다른 글
RESTful Web Service (0) | 2023.05.25 |
---|---|
섹션 4. Spring Boot API 사용 (0) | 2023.05.18 |
섹션 1. Spring Boot로 개발하는 RESTful Service (0) | 2023.05.16 |
Spring Boot RESTful Web Services - Web Service & Web Application (0) | 2023.05.16 |
인텔리제이(IntelliJ IDEA)로 스프링 부트(Spring Boot) 시작하기 (0) | 2022.05.06 |