Back-end/Spring

[Spring] RESTful Service 기능 확장

shoney9254 2022. 11. 6. 14:21
반응형

Validation

 

Controller에는 아래와 같이 @Valid 어노테이션 사용해야함

@PostMapping("/users") // 체크하는 순서는 Post인지 먼저 체크하고, uri를 체크해서 이쪽으로 오게됨
public ResponseEntity createUser(**@Valid** @RequestBody User user) { //오브젝트 형식의 데이터를 전달하려면 @RequestBody가 필요함
    User savedUser = service.save(user);

    URI location = ServletUriComponentsBuilder.fromCurrentRequest()
            .path("/{id}")
            .buildAndExpand(savedUser.getId())
            .toUri();

    return ResponseEntity.created(location).build();
}

User.java 도메인은 아래와 같이 사이즈와 과거만 사용할 수 있도록 어노테이션 붙여야함

@Size(min=2)
private String name;

@Past //과거만 사용가능
private Date joinDate;

위와 같이 설정을 해놓고, 커스텀한 익셉션에다가 내용을 추가해야한다.

ResponseEntityExceptionHandler 를 상속 받아서 사용하고 있는 커스템 익셉션핸들러를 수정해줘야한다.

ResponseEntityExceptionHandler 클래스를 들어가보면, handleMethodArgumentNotValid 추상클래스의 메서드를 재정의 해줘야한다. 해당 메서드는 오버라이드를 해서 사용하는 것이기 때문에 @Override 어노테이션을 사용해야한다.

CustomizedResponseEntityExceptionHandler.java

@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
    ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(),
            ex.getMessage(), ex.getBindingResult().toString());
    return new ResponseEntity(exceptionResponse, HttpStatus.BAD_REQUEST);
}

위와 같이 ResponseEntityExceptionHandler의 handleMethodArgumentNotValid 메서드를 재정의 해주면, 도메인에서 Validation 정의 해준 어노테이션에 어떤것이 잘못됐는지 Response에 표현하게 된다.

 

Internationalization (다국어 처리)

메인 소스에다가 아래와 같이 작성한다. LocaleResolver 사용

야믈파일에 아래와 같이 spring - messages - basename을 지정한다.

메세지라는 프로퍼티 파일을 생성한다.

각자의 파일에다가

해당 언어에 맞게 greeting.message를 추가해 준다.

 

XML format으로 반환하기

잘돌아가는 api의 key에 Accept = application/xml 로 입력했을 때, Status가 406 으로 오는 것을 확인할 수 있다. 4xx대는 클라이언트가 잘못했을 경우에 나오는 에러이다.

xml로도 받을 수 있도록 설정해보도록 하자.

pom.xml 들어가서 아래와 같이 dependency를 추가해보도록 하자.

<dependency>
   <groupId>com.fasterxml.jackson.dataformat</groupId>
   <artifactId>jackson-dataformat-xml</artifactId>
   <scope>2.10.2</scope>
</dependency>

그러면 아래와 같이 xml로 받을 수 있게 변경된다.

 

Filtering

중요한 정보들이 들어가있는 것들을 보이지 않도록 하게 하는 것이다. (주민번호, 고객정보 등)

 

1. @JsonIgnore

도메인에 @JsonIgnore를 추가해서 조회가 안되도록 할 수 있다.

@Data
@AllArgsConstructor
public class User {
    //lombok으로 프로퍼티만 만들어도 됨
    private Integer id;

    @Size(min=2, message = "Name은 2글자 이상 입력해 주세요.")
    private String name;

    @Past //과거만 사용가능
    private Date joinDate;

    @JsonIgnore
    private String password;

    @JsonIgnore
    private String ssn;
}

 

2. @JsonIgnoreProperties

@JsonIgnoreProperties 어노테이션을 도메인 클래스에다가 지정해서도 사용할 수 있다.

@Data
@AllArgsConstructor
@JsonIgnoreProperties(value = {"password"})
public class User {
    //lombok으로 프로퍼티만 만들어도 됨
    private Integer id;

    @Size(min=2, message = "Name은 2글자 이상 입력해 주세요.")
    private String name;

    @Past //과거만 사용가능
    private Date joinDate;

    private String password;

    private String ssn;
}

 

3. admin Controller를 만들어서 사용해보자

1) @JsonFilter("UserInfo")

@JsonFilter("UserInfo") 어노테이션을 도메인에다가 사용한다.

기존의 Controller를 앞에 admin을 붙여서 관리자만 들어갈 수 있도록 변경했다. 그리고 @RequestMapping어노테이션을 사용해서 컨트롤러에서 매핑 되어있는 uri앞에 모두 “/admin”이 붙도록 설정할 수 있다.

 

2) 사용자 1명 조회 하는 법

한명의 유저를 얻어내는 컨트롤러 메서드를 수정해보자.

반환되는 값은 MappingJacksonValue 로 변경하고, 아래와 같이 필터로 보고싶은 변수들의 명을 작성해보자.

@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;
}

 

3. 전체 사용자 조회하는 법

@GetMapping("/users")
public MappingJacksonValue retrieveAllUsers() {
    List<User> users = service.findAll();
    SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter
            .filterOutAllExcept("id", "name", "joinDate", "ssn");

    FilterProvider filters = new SimpleFilterProvider().addFilter("UserInfo",filter);

    MappingJacksonValue mapping = new MappingJacksonValue(users);
    mapping.setFilters(filters);

    return mapping;
}

 

Version 관리

1) URI 를 통한 버전관리

도메인이 버전이 변경되면서, 아이디를 조회하는 항목이 하나 더 추가되는 상황을 만들어보자.

먼저, 도메인 버전 2를 만들자

UserV2.java

@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonFilter("UserInfoV2")
public class UserV2 extends User{
   private String grade;
}

기존의 유저를 상속받아서 그레이드라는 항목이 추가하면 된다.

그리고 아래와 같이 기존의 조회하던 user/{id} 앞에 /v2를 추가해서 URI로 분기를 타게 만들면 된다.

또한 BeanUtils.copyPropertise를 사용해서 객체를 옮기는 작업을 하고, 새롭게 추가된 그레이드만 직접 넣어주면 된다.

 

AdminUserController.java

@GetMapping("/v2/users/{id}")
public MappingJacksonValue retrieveUser2(@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;
}

 

2) Request Parameter와 Header를 이용한 버전관리

2-1) 파라를 통해 버전관리

아래와 같이 getmapping 안에 version을 넣어서 사용한다.

포스트맨에서 물음표를 사용해서 버전 분기를 탈 수 있다.

2-2) 헤더를 통해 버전관리

헤더에다가 버전을 작성해서 사용하면된다.

아래와 같이 결과가 나온다.

2-3) produces 을 사용하는 방법

역시나 헤더에 값을 입력해서 사용하면 아래와 같이 정상 작동되는 것을 확인할 수 있다.

버전관리의 몇가지 옵션을 위와 깉이 알아봤다.

헤더에 넣어서 사용하는 것은 일반 브라우저에서 실행이 안되기 때문에 포스트맨과 같은 프로그램을 이용해서 사용하면 된다.

 

반응형