๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๋ฐฑ์—”๋“œ/spring&springboot

[๋‚ด์ผ๋ฐฐ์›€์บ ํ”„_Spring Boot ์ˆ™๋ จ์ฃผ์ฐจ] ๋ฐ์ดํ„ฐ ๊ฒ€์ฆํ•˜๊ธฐ(Validation)

by alswlfl 2026. 6. 29.

Validation

Validation์€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•˜๋Š”๋ฐ์— ์žˆ์–ด์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„ ์ค‘ ํ•˜๋‚˜์ž„

  • Java๋Š” null ๊ฐ’์— ๋Œ€ํ•œ ์ ‘๊ทผ์— ๋Œ€ํ•ด NullPointerException ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ๋ถ€๋ถ„์„ ์˜ˆ๋ฐฉํ•˜๊ธฐ ์œ„ํ•ด Validation ์ฆ‰, ๊ฒ€์ฆ ๊ณผ์ •์ด ํ•„์š”ํ•จ
  • Spring์—์„œ๋Š” null ํ™•์ธ ๋ฟ ์•„๋‹ˆ๋ผ ๋ฌธ์ž์˜ ๊ธธ์ด ์ธก์ •๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ ๊ฒ€์ฆ ๊ณผ์ •๋„ ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก Bean Validation ์ œ๊ณตํ•˜๊ณ  ์žˆ์Œ

Bean Validation

@NotNull null ๋ถˆ๊ฐ€
@NotEmpty null, "" ๋ถˆ๊ฐ€
@NotBlank null, "", " " ๋ถˆ๊ฐ€
@Size ๋ฌธ์ž ๊ธธ์ด ์ธก์ •
@Max ์ตœ๋Œ€๊ฐ’
@Min ์ตœ์†Œ๊ฐ’
@Positive ์–‘์ˆ˜
@Negative ์Œ์ˆ˜
@Email E-mail ํ˜•์‹
@Pattern ์ •๊ทœ ํ‘œํ˜„์‹

 

๏นกValidation์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด dependencies์— ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€ํ•ด์•ผํ•จ

implementation 'org.springframework.boot:spring-boot-starter-validation'

DTO์— Bean Validation ์„ค์ •

package com.sparta.springauth.dto;

import jakarta.validation.constraints.*;
import lombok.Getter;

@Getter
public class ProductRequestDto {
    @NotBlank
    private String name;
    @Email
    private String email;
    @Positive(message = "์–‘์ˆ˜๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.")
    private int price;
    @Negative(message = "์Œ์ˆ˜๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.")
    private int discount;
    @Size(min=2, max=10)
    private String link;
    @Max(10)
    private int max;
    @Min(2)
    private int min;
}

Valid ๋™์ž‘ ์ดํ•ด

  • Controller ๋‚ด ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ์„ ํ•˜๊ณ  ์‹ถ์€ DTO ์•ž์— @Valid ์–ด๋…ธํ…Œ์ด์…˜ ์ถ”๊ฐ€
@PostMapping("/validation")
@ResponseBody
public ProductRequestDto testValid(@RequestBody @Valid ProductRequestDto requestDto) {
    return requestDto;
}

 

์ •ํ™•ํ•œ ์ž…๋ ฅ๊ฐ’์„ ๋ณด๋ƒˆ์„ ๊ฒฝ์šฐ

๊ฒฐ๊ณผ

์ž˜๋ชป๋œ ์ž…๋ ฅ๊ฐ’์„ ๋ณด๋ƒˆ์„ ๊ฒฝ์šฐ


Validation ์˜ˆ์™ธ์ฒ˜๋ฆฌ

ํšŒ์›๊ฐ€์ž… DTO Validation ์ ์šฉ

package com.sparta.springauth.dto;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class SignupRequestDto {
    @NotBlank
    private String username;
    @NotBlank
    private String password;
    @Email
    @NotBlank
    private String email;
    private boolean admin = false;
    private String adminToken = "";
}

 

Controller ๋‹จ์—์„œ Validation ์˜ˆ์™ธ์ฒ˜๋ฆฌํ•˜๊ธฐ

- BindingResult๋Š” Validation์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด BindingResult ๊ฐ์ฒด์— ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ๋‹ด๊ฒจ์„œ ๋“ค์–ด์˜ด

@PostMapping("/user/signup")
// BindingResult: Validation์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด BindingResult ๊ฐ์ฒด์— ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ์ •๋ณด ๋‹ด๊ฒจ์„œ ๋“ค์–ด์˜ด
public String signup(@Valid SignupRequestDto requestDto, BindingResult bindingResult) {
    // Validation ์˜ˆ์™ธ์ฒ˜๋ฆฌ
    List<FieldError> fieldErrors = bindingResult.getFieldErrors(); // ์˜ค๋ฅ˜๊ฐ€ ๋‚œ ํ•„๋“œ ๊ฐ€์ ธ์˜ค๊ธฐ
    if(fieldErrors.size() > 0) {
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            // ์˜ค๋ฅ˜๊ฐ€ ๋‚œ ํ•„๋“œ ๊ฐ€์ ธ์˜ค๊ธฐ
            log.error(fieldError.getField() + " ํ•„๋“œ : " + fieldError.getDefaultMessage());
        }
        return "redirect:/api/user/signup";
    }

    userService.signup(requestDto);

    return "redirect:/api/user/login-page";
}

์˜ˆ์™ธ ๋ฐœ์ƒ

์ •๊ทœ ํ‘œํ˜„์‹(Regular Expression; Regex, Regexp)

์ •๊ทœ ํ‘œํ˜„์‹์€ ํŠน์ •ํ•œ ๊ทœ์น™์„ ๊ฐ€์ง„ ๋ฌธ์ž์—ด์˜ ์ง‘ํ•ฉ์„ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์“ฐ์ด๋Š” ํ˜•์‹ ์–ธ์–ด๋กœ,

์–ด๋–ค ํ…์ŠคํŠธ ๋‚ด์—์„œ 'ํŠน์ •ํ•œ ํ˜•ํƒœ๋‚˜ ๊ทœ์น™์„ ๊ฐ€์ง„ ๋ฌธ์ž์—ด'์„ ์ฐพ๊ธฐ ์œ„ํ•ด ๊ทธ ํ˜•ํƒœ๋‚˜ ๊ทœ์น™์„ ๋‚˜ํƒ€๋‚ด๋Š” ํŒจํ„ด์„ ์ •์˜ํ•˜๋Š” ์‹์„ ๋œปํ•จ

 

์ •๊ทœ ํ‘œํ˜„์‹ ๊ธฐ๋ณธ ๋ฌธ๋ฒ•

  1. ํŒจํ„ด ๊ทธ๋Œ€๋กœ๋ฅผ ๋งค์นญํ•˜๋Š” ๊ฒฝ์šฐ: ๋‹จ์–ด ๊ทธ๋Œ€๋กœ๋ฅผ ํŒจํ„ด์œผ๋กœ ์‚ฌ์šฉํ•ด ๋งค์นญ๋˜๋Š” ์˜์—ญ์„ ์ฐพ๋Š” ๋ฐฉ๋ฒ•
  2. ๋ฉ”ํƒ€๋ฌธ์ž ๋ฐ ์ˆ˜๋Ÿ‰ ํ•œ์ •์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ: ์ •๊ทœ์‹ ํŒจํ„ด์— ์“ฐ์ด๋Š” ๋ฌธ์ž ์ค‘์—๋Š” ํŠน๋ณ„ํ•œ ์˜๋ฏธ๋ฅผ ์ง€๋‹ˆ๋Š” ๋ฉ”ํƒ€ ๋ฌธ์ž๋“ค์ด ์žˆ๋Š”๋ฐ, ์ด๋Ÿฌํ•œ ๋ฉ”ํƒ€๋ฌธ์ž์™€ ๊ทธ ๋ฉ”ํƒ€๋ฌธ์ž์˜ ๊ฐœ์ˆ˜๋ฅผ ์ง€์ •(์ˆ˜๋Ÿ‰ ํ•œ์ •์ž์˜ ์—ญํ• )ํ•˜์—ฌ ํญ๋„“์€ ํŒจํ„ด์„ ๋งค์นญํ•˜๋Š” ๋ฐฉ๋ฒ•
  3. ๊ทธ๋ฃน ๋ฐ Look around(์ „, ํ›„๋ฐฉ ํƒ์ƒ‰) ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ: ํŒจํ„ด์˜ ์ผ๋ถ€๋ฅผ ๊ทธ๋ฃน์œผ๋กœ ๋ฌถ๊ฑฐ๋‚˜, ํŠน์ • ํŒจํ„ด์˜ ์•ž ๋˜๋Š” ๋’ค๋กœ ๋‹ค๋ฅธ ํŒจํ„ด์ด ์˜ค๋Š” ์กฐ๊ฑด์„ ๋”ํ•˜๋Š” ๊ฒฝ์šฐ

์ •๊ทœ ํ‘œํ˜„์‹ ๋ฉ”ํƒ€ ๋ฌธ์ž

๋ฉ”ํƒ€ ๋ฌธ์ž๋Š” ํŠน์ •ํ•œ ๋ฌธ์ž ํ˜น์€ ๋ฌธ์ž ๊ณ„์—ด์„ ๋Œ€์‹ ํ•ด ํ‘œ์‹œํ•˜๋Š” ๋ฌธ์ž๋กœ, ๋ฉ”ํƒ€ ๋ฌธ์ž๋ฅผ ์ด์šฉํ•˜๋ฉด ํŠน์ •ํ•œ ๊ทœ์น™์„ ๊ฐ€์ง„ ์—ฌ๋Ÿฌ ๋‹จ์–ด๋ฅผ ํ•˜๋‚˜์˜ ํŒจํ„ด์œผ๋กœ ํ•จ์ถ•ํ•  ์ˆ˜ ์žˆ์Œ
- ๋ฉ”ํƒ€๋ฌธ์ž์—์„œ ๋Œ€์†Œ๋ฌธ์ž๋Š” ์„œ๋กœ ๋ฐ˜๋Œ€๋˜๋Š” ์˜๋ฏธ๋ฅผ ์ง€๋‹ˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Œ!

 

๋ฉ”ํƒ€ ๋ฌธ์ž ์ •๋ฆฌ ์ฐธ๊ณ  ์‚ฌ์ดํŠธ

 

์ •๊ทœํ‘œํ˜„์‹(Regex)์˜ ๊ฐœ๋…๊ณผ ๊ธฐ์ดˆ ๋ฌธ๋ฒ•

์ •๊ทœํ‘œํ˜„์‹์ด๋ž€? : Regular Expression์„ ์ค„์—ฌ์„œ Regex, Regexp ๋“ฑ์œผ๋กœ ๋ถˆ๋ฆฐ๋‹ค. Computer Science์˜ ์ •๊ทœ ์–ธ์–ด(Regular Language)๋กœ๋ถ€ํ„ฐ ์œ ๋ž˜ํ•œ ๊ฒƒ์œผ๋กœ, ํŠน์ •ํ•œ ๊ทœ์น™์„ ๊ฐ€์ง„ ๋ฌธ์ž์—ด์˜ ์ง‘ํ•ฉ์„ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์“ฐ์ด๋Š” *

co-no.tistory.com

 

์ •๊ทœ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•ด ์ด๋ฉ”์ผ Validation ์„ค์ •

@Pattern(regexp = "^(.+)@(.+)$") // '@'๊ธฐํ˜ธ๋งŒ ํ™•์ธ
@Pattern(regexp = "[A-Za-z0-9+_.-]+@(.+)$") // ์•ž ๋ถ€๋ถ„๋งŒ ๊ทœ์น™ ์„ค์ •(A-Z, a-z, 0-9, _, . ๋ชจ๋‘ ํ—ˆ์šฉ)
@Pattern(regexp = "[A-Za-z0-9_!#$%&'*+/=?`{|}~^.-]+@[A-Za-z0-9.-]+$") // ์•ž ๋’ค ๋ชจ๋‘ ๊ฒ€์ฆ(์•ž์€ ์ด๋ฉ”์ผ์—์„œ ํ—ˆ์šฉํ•˜๋Š” ๊ฒƒ๋“ค ๋ชจ๋‘ ์ถ”๊ฐ€ํ•ด๋ด„)