Burninghering's Blog
article thumbnail
Published 2022. 6. 1. 03:18
Validation Spring

위와 같은 코드에서는, 

인자가 3개밖에 없으니 코드가 짧지만

인자가 늘어나면 늘어날수록 코드(validation)가 길어지고 정상적인 로직을 짜는데 문제가 생길 수 있다. 

또 잘못 작성하면 에러가 난다.

 

Validation은 변경되면 안된다!

 

그리고 잘 처리하기 위해 스프링에서 일관되게 제공하기 위해

어노테이션으로 제공한다

 

변수에다가 붙이면 된다

 

요청을 받을 것이기 때문에

cotroller 패키지 만들고 ValidationApplication.java만듦

package com.example.validation.controller;


import com.example.validation.dto.User;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class ApiController {

    @PostMapping("/user")
    public Object user(@RequestBody User user){
        System.out.println(user);
        return user;
    }
}

 

dto의 User도 만듦

package com.example.validation.dto;

public class User {
    private String name;
    private int age;
    private String email;
    private String phoneNumber;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                ", phoneNumber='" + phoneNumber + '\'' +
                '}';
    }
}

 

email과 phoneNumber에 이상한 형식이 들어가도 정상적인 Response 200이 나온다..

 

ApiController의 내용을 바꿔보자

package com.example.validation.controller;


import com.example.validation.dto.User;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class ApiController {

    @PostMapping("/user")
    public ResponseEntity user(@RequestBody User user) {
        if (user.getAge() >= 90) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(user);
        }
        return ResponseEntity.ok(user);
    }
}

100살 보내니까 에러가 난다!

 

하지만 방금처럼 코드를 짜면,

인자가 늘어날때마다 코드가 길어지니까 

Validation이 꼭 필요한 것이다.

 

User.java

import javax.validation.constraints.Email;

public class User {
    private String name;
    private int age;

    @Email //<--어노테이션 붙여줌
    private String email;
    private String phoneNumber;

 

User 내에 있는 변수에 Valid 어노테이션을 붙였으니,

아래 코드의 User에도 @Valid를 붙여줘야 한다. 

package com.example.validation.controller;


import com.example.validation.dto.User;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

@RestController
@RequestMapping("/api")
public class ApiController {

    @PostMapping("/user")
    public ResponseEntity user(@Valid @RequestBody User user) {
        if (user.getAge() >= 90) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(user);
        }
        return ResponseEntity.ok(user);
    }
}

@Valid가 붙은 객체는 그 안으로 들어가서 어노테이션(@Email)이 붙었는지 안 붙었는지 검사하기 때문

 

 

제대로 다시 보내면 성공!

 

 

 

핸드폰 번호에 대시(-)를 넣거나 안넣을 수도 있으니,

정규식을 활용해보자

"^\\d{2,3}-\\d{3,4}-\\d{4}$"

 

package com.example.validation.dto;

import javax.validation.constraints.Email;
import javax.validation.constraints.Pattern;

public class User {
    private String name;
    private int age;

    @Email
    private String email;

    @Pattern(regexp="^\\d{2,3}-\\d{3,4}-\\d{4}$")
    private String phoneNumber;

검색을 통해 다양한 정규식으로 통제해보자!

 

 

 

지금처럼 body를 보내면 바로 error가 나는 것이 아니라,

Valid에 오류가 나면 bindingResult라는 곳으로 값을 보내줄 수 있다.

bindingResult라는 객체를 통해 새로운 변환값을 받을 수 있다.

bindingResult가 없다면 예외처리로 가능!(아직 안배움)

package com.example.validation.controller;


import com.example.validation.dto.User;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

@RestController
@RequestMapping("/api")
public class ApiController {

    @PostMapping("/user")
    public ResponseEntity user(@Valid @RequestBody User user, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            StringBuilder sb = new StringBuilder();
            bindingResult.getAllErrors().forEach(objectError -> {
                FieldError field = (FieldError) objectError; //형변환
                String message = objectError.getDefaultMessage(); //오류 메시지도 가져오자

                System.out.println("field : " + field.getField());
                System.out.println(message);
            });
        }
        return ResponseEntity.ok(user);
    }
}

message의 양식을 바꿔보자

package com.example.validation.dto;

import javax.validation.constraints.Email;
import javax.validation.constraints.Pattern;

public class User {
    private String name;
    private int age;

    @Email
    private String email;

    @Pattern(regexp="^\\d{2,3}-\\d{3,4}-\\d{4}$", message="핸드폰 번호의 양식과 맞지 않습니다. 01x-xxx(x)-xxxx")
    private String phoneNumber;

 

메세지를 바로 추가시키는 방법

package com.example.validation.controller;


import com.example.validation.dto.User;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

@RestController
@RequestMapping("/api")
public class ApiController {

    @PostMapping("/user")
    public ResponseEntity user(@Valid @RequestBody User user, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            StringBuilder sb = new StringBuilder();
            bindingResult.getAllErrors().forEach(objectError -> {
                FieldError field = (FieldError) objectError; //형변환
                String message = objectError.getDefaultMessage(); //오류 메시지도 가져오자

                System.out.println("field : " + field.getField());
                System.out.println(message);

                sb.append("field : "+field.getField());
                sb.append("message : "+message);
            });
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(sb.toString());
        }
        return ResponseEntity.ok(user);
    }
}

 

이 API를 사용하는 사람이

응답만 보더라도 휴대폰 번호에 틀린 값을 잘못 넣었다는 것을 알 수 있다.

 

package com.example.validation.controller;


import com.example.validation.dto.User;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

@RestController
@RequestMapping("/api")
public class ApiController {

    @PostMapping("/user")
    public ResponseEntity user(@Valid @RequestBody User user, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            StringBuilder sb = new StringBuilder();
            bindingResult.getAllErrors().forEach(objectError -> {
                FieldError field = (FieldError) objectError; //형변환
                String message = objectError.getDefaultMessage(); //오류 메시지도 가져오자

                System.out.println("field : " + field.getField());
                System.out.println(message);

                sb.append("field : "+field.getField());
                sb.append("message : "+message);
            });
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(sb.toString());
        }

        //위에서 검증이 아주 잘 되었다면
        //실질적으로 여기에 Logic을 짜면 된다 

        return ResponseEntity.ok(user);
    }
}

 

여러가지 넣어봤다

package com.example.validation.dto;

import javax.validation.constraints.*;

public class User {
    @NotBlank
    private String name;

    @Max(value=90, message="valid 어노테이션에는 어느 곳에나 메세지를 넣을 수 있습니다")
    private int age;

 

컨트롤러 단에서 Validation을 사용하는 방법을 알아보았다!

변수 위에 annotation을 붙여주고, 

컨트롤러에서 객체를 검사하고 싶은 부분에는 @Valid를 붙여주면 된다~

profile

Burninghering's Blog

@개발자 김혜린

안녕하세요! 반갑습니다.