스프링부트 다양한 기능 1. Spring Boot Validation

min seung moon·2021년 6월 28일
0

Spring

목록 보기
32/50

1. Spring Boot Validation

01. Validation

  • Validation이란 프로그래밍에 있어서 가장 필요한 부분이다, 특히 Java에서는 null 값에 대해서 접근 하려고 할 때 null pointer exception이 발생함으로, 이러한 부분을 방지하기 위해서 미리 검증을 하는 과정을 Validation이라고 한다
    • 단순 예시
    public void run(String account, Spring pw, int age) {
    	if(account == null || pw == null) {
      	return;
      }
      if(age == 0) {
      	return;
      }
      // 정상로직
    }

02. Validation 주의 사항

    1. 검증해야 할 값이 많은 경우 코드의 길이가 길어 진다
    1. 구현에 따라서 달라 질 수 있지만 Service Logic과의 분리가 필요하다
    1. 흩어져 있는 경우 어디에서 검증을 하는지 알기 어려우며, 재사용의 한계가 있다
    1. 구현에 따라 달라 질 수 있지만, 검증 Logic이 변경되는 경우 테스트 코드 등 참조하는 클래스에서 Logic이 변경되어야 하는 부분이 발생 할 수 있다

03. Validation 관련 어노테이션

2. 프로젝트 테스트

  • Spring Initalizr -> validation
  • Package : controller, dto
  • Class : ApiController, User

01. Validation 등록 및 사용법

  • 1. gradle dependencies
    • implementation("org.springframework.boot:spring-boot-starter-validation")
  • 2. bean validation spec
  • 3. gradle dependencies
    • "^\d{2,3}-\d{3,4}-\d{4}$"

-2. dependencies 추가

  • implementation("org.springframework.boot:spring-boot-starter-validation")

02. Validation 적용 전 코드

  • controller / ApiController.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 User user(@RequestBody User user) {
        System.out.println(user);
        return user;
    }
}
  • dto / User.java
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 + '\'' +
                '}';
    }
}
  • Test

03. Validation 적용(하드 코딩) 후 코드

  • controller / ApiController.java
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) {
        System.out.println(user);

        if(user.getAge() >= 90) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(user);
        }

        return ResponseEntity.ok(user);
    }
}


04. Validation 적용(어노테이션) 후 코드

-1. @Email

  • dto / User.java
    • @Email
      • 이메일 형식 validation annotation
package com.example.validation.dto;

import javax.validation.constraints.Email;

public class User {

    private String name;

    private int age;

    @Email
    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 + '\'' +
                '}';
    }
}

-2. @Valid

  • controller / ApiController.java
    • @Valid
      • @Valid가 있으면 해당 객체 내부의 Validation Annotation을 확인하고 적용
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 {

    // @Valid가 있으면 객체 내부의 Validation Annotation을 확인하고 적용
    @PostMapping("/user")
    public ResponseEntity user(@Valid @RequestBody User user) {
        System.out.println(user);

        if(user.getAge() >= 90) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(user);
        }

        return ResponseEntity.ok(user);
    }
}


  • dto/User.java
    • @Pattern(regexp = "^\d{2,3}-\d{3,4}-\d{4}$")
      • 휴대폰 번호 정규 표현식(000-0000-0000, 000-000-0000)
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;

    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 + '\'' +
                '}';
    }
}


-3. @NotBlank, @Max

  • dto / User.java
    • @NotBlank
      • 공백 불가능 어노테이션
    • @Max
      • 최고 값 적용 어노테이션
      • @Max(value = 90), 90 초과 안됨
    • @Pattern
      • @Pattern(regexp = "^\d{2,3}-\d{3,4}-\d{4}$", message = "핸드폰 번호의 양식과 맞지 않습니다. 01x-xxx(x)-xxxx")
      • message option으로 전송할 메시지 적용
    • @Email
package com.example.validation.dto;

import javax.validation.constraints.*;

public class User {

    @NotBlank
    private String name;

    @Max(value = 90)
    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;

    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 + '\'' +
                '}';
    }
}
  • controller / ApiController.java
    • ModelAttribute을 이용해 매개변수를 Bean에 binding 할 때, 발생한 오류 정보를 받기 위한 객체
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 {

    // @Valid가 있으면 객체 내부의 Validation Annotation을 확인하고 적용
    @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());
        }

        System.out.println(user);

        // logic

        return ResponseEntity.ok(user);
    }
}


profile
아직까지는 코린이!

0개의 댓글