스프링(Spring), 스프링부트(SpringBoot)/스프링부트(SpringBoot) 기초

스프링부트 핵심 가이드(장정우 지음) - 유효성 검사(1)

개발학생 2025. 10. 24. 16:11
반응형

*책 내용과 다르게, 다음과 같은 환경에서 프로젝트 생성  

 

[Java] 차근차근 Java 설치하기 (JDK17, Window 11)

자바 개발 도구 설치 방법에 대해서 알아보겠습니다. Java17은 LTS(Long Term Support : 장기 지원) 릴리즈로 1년 후까지 기술 지원 및 버그를 개선한 서비스를 제공받을 수 있습니다. 업데이트 버전을 꾸

yungenie.tistory.com

 

[Windows] Spring Tool Suite 4(STS 4) 다운로드 및 설치

STS란?Spring Tool Suite(STS)는 스프링 프로젝트를 생성하고, 개발할 수 있게 해주는 도구입니다. STS 설치 과정에 대해 설명드리겠습니다. 설치 파일 다운로드STS 공식 사이트에서 설치 파일을 다운로

priming.tistory.com

 

MySQL :: Download MySQL Community Server

Select Version: 9.3.0 Innovation 8.4.5 LTS 8.0.42 Select Operating System: Select Operating System… Microsoft Windows Ubuntu Linux Debian Linux SUSE Linux Enterprise Server Red Hat Enterprise Linux / Oracle Linux Fedora Linux - Generic Oracle Solaris mac

dev.mysql.com

  • Gradle

**STS에서 Gradle 프로젝트 생성한 과정 

*** 함께 보면 좋은 글

2025.07.10 - [스프링(Spring), 스프링부트(SpringBoot)/스프링부트(SpringBoot) 기초] - 스프링 부트 핵심 가이드(장정우 지음) - 스프링 부트 개요

 

스프링 부트 핵심 가이드(장정우 지음) - 스프링 부트 개요

1. 스프링 프레임워크자바(Java) 기반 애플리케이션 프레임워크로, 엔터프라이즈급(기업 환경 대상 개발) 애플리케이션을 위한 다양한 기능 제공-> 오픈소스 경량급 애플리케이션 프레임워크로

keep-programming-study.tistory.com

2025.07.11 - [스프링(Spring), 스프링부트(SpringBoot)/스프링부트(SpringBoot) 기초] - 스프링 부트 핵심 가이드(장정우 지음) - 개발에 앞서 알면 좋은 기초 지식

 

스프링 부트 핵심 가이드(장정우 지음) - 개발에 앞서 알면 좋은 기초 지식

1. 서버 간 통신마이크로서비스 아키텍처에서 한 서버가 다른 서버에 통신을 요청하는 것을 의미-> 한 대는 서버/다른 한 대는 클라이언트가 됨 가장 많이 사용되는 방식은 HTTP/HTTPS 방식(TCP/IP, SOA

keep-programming-study.tistory.com

2025.07.16 - [스프링(Spring), 스프링부트(SpringBoot)/스프링부트(SpringBoot) 기초] - 스프링 부트 핵심 가이드(장정우 지음) - REST API 명세를 문서화하는 방법(Swagger), 로깅 라이브러리(Logback)

 

스프링 부트 핵심 가이드(장정우 지음) - REST API 명세를 문서화하는 방법(Swagger), 로깅 라이브러리

*책 내용과 다르게, 다음과 같은 환경에서 프로젝트 생성 Windows11(윈도우 11) 환경자바 JDK 17 버전 설치 https://yungenie.tistory.com/11 [Java] 차근차근 Java 설치하기 (JDK17, Window 11)자바 개발 도구 설치 방법

keep-programming-study.tistory.com

 

1. 일반적인 애플리케이션 유효성 검사의 문제점: 복잡하고 가독성이 떨어지는 코드

  • 계층별로 진행하는 유효성 검사는 데이터 검증 로직이 각 클래스별로 분산되어 잇어 관리가 어려움
  • 데이터 검증 로직에 중복이 많아 여러 곳에 유사한 기능의 코드가 존재할 수 있음
  • 검증해야 할 값이 많다면 검증 코드가 길어짐

2. Bean Validation: 자바 진영에서 2009년부터 데이터 유효성 검사 프레임워크 제공

  • 어노테이션을 통해 다양한 데이터를 검증하는 기능을 제공하여, 코드의 간결함을 유지
  • 유효성 검사를 위한 로직을 DTO같은 도메인 모델과 묶어서,
    각 계층에서 사용하면서 검증 자체를 도메인 모델에 얹는 방식으로 수행

*Hibernate Validator

  • Bean Validation 명세의 구현체가 Hibernate Validator
  • 스프링부트에서는 이를 유효성 검사 표준으로 채택하여 사용함
  • JSR-303 명세의 구현체로서 도메인 모델에서 어노테이션을 통한 필드값 검증을 도움 
    -> JSR-303: 자바에서 객체의 유효성을 검사하기 위한 표준 명세이자 Bean Validation 1.0을 정의한 스펙,
        주로 @Valid와 다양한 제약 애노테이션을 통해 객체 필드의 유효성을 자동으로 검증

3. 스프링 부트에서의 유효성 검사 예시

1) build.gradle에 의존성 추가 및 저장한 후 우클릭 -> Gradle -> Refresh Gradle Project 선택

dependencies {
    ... 생략 ...
    // 유효성 검사
    // spring-boot-starter-web에는 JSR-303 기반 유효성 검사 기능이 일부 포함되어 있지만
	// 구현체인 Hibernate Validator는 spring-boot-starter-validation에 포함돼 있으므로, 유효성 검사를 제대로 사용하려면 이 의존성을 명시적으로 추가
    implementation 'org.springframework.boot:spring-boot-starter-validation'
}

build.gradle에 의존성 코드 추가

2) 스프링 부트의 유효성 검사 이해

  • 각 계층으로 넘어오는 시점에 해당 데이터에 대한 유효성 검사를 실시
  • 스프링 부트 프로젝트에서는 계층 간 데이터 전송에 대체로 DTO 객체를 활용하고 있으며, 
    따라서 다음과 같이 유효성 검사를 DTO 객체를 대상으로 수행하는 것이 일반적

교재와 같음: 도메인 모델에 유효성 검사 적용 도식화

3) DTO와 컨트롤러 생성

(1) DTO 생성 

package com.example.demo.jpa.data.dto;

import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data // Getter, Setter, equals(), hashCode(), toString() 메서드를 자동 생성해주는 종합 패키지 애노테이션
@NoArgsConstructor // 파라미터가 없는 기본 생성자 자동 생성
@AllArgsConstructor // 모든 필드를 파라미터로 받는 생성자 자동 생성
@ToString // toString() 메서드를 자동 생성 (필드 값을 문자열로 표현)
@Builder // 빌더 패턴을 적용해 객체를 유연하게 생성할 수 있도록 지원
public class ValidRequestDto {
    // name 필드는 null이거나 공백이면 안 됨 (빈 문자열도 허용하지 않음)
    @NotBlank
    String name;

    // email 필드는 이메일 형식이어야 함 (예: user@example.com)
    @Email
    String email;

    // 휴대폰 번호는 특정 패턴을 따라야 하므로 정규표현식 사용 (010-1234-5678 또는 011.234.5678 형식)
    @Pattern(regexp = "01(?:0|1|[6-9]).[.-]?(\\d{3}|\\d{4})[.-]?(\\d{4})$")
    String phoneNumber;

    // age는 최소 20 이상, 최대 40 이하의 값이어야 함
    @Min(value = 20)
    @Max(value = 40)
    int age;

    // description은 길이가 0 이상 40 이하의 문자열이어야 함
    @Size(min = 0, max = 40)
    String description;

    // count는 반드시 양수여야 함 (0은 허용되지 않음)
    @Positive
    int count;

    // booleanCheck는 반드시 true여야 함 (false이면 유효성 검사 실패)
    @AssertTrue
    boolean booleanCheck;
}

(2) 컨트롤러 생성

  • 전에 STS4에서 @RequestBody가 죽어도 먹히지 않는 지옥을 경험했기 때문에,
    책 내용과 다르게 @RequestParam 방식의 코드 작성

    -> 실제로는 보안에 좋지 않기 때문에 IntelliJ를 써서 @RequestBody로 받는게 맞습니다
package com.example.demo.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.Size;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

@RestController // REST API 컨트롤러로 동작함을 나타냄 (@Controller + @ResponseBody)
@RequestMapping("/validation") // 이 컨트롤러의 기본 URL 경로를 "/validation"으로 설정
public class ValidationController {

    // SLF4J 로깅 인터페이스를 사용하여 로그를 출력할 수 있도록 Logger 객체 생성
    private final Logger LOGGER = LoggerFactory.getLogger(ValidationController.class);

    // POST 요청을 "/validation/valid" 경로로 매핑
    @PostMapping("/valid")
    public ResponseEntity<String> checkValidationByValid(
        // 각 파라미터에 유효성 검사 애노테이션을 직접 적용
        @RequestParam("name") @NotBlank String name,
        @RequestParam("email") @Email String email,
        @RequestParam("phoneNumber") @Pattern(regexp = "01(?:0|1|[6-9]).[.-]?(\\d{3}|\\d{4})[.-]?(\\d{4})$") String phoneNumber,
        @RequestParam("age") @Min(20) @Max(40) int age,
        @RequestParam("description") @Size(min = 0, max = 40) String description,
        @RequestParam("count") @Positive int count,
        @RequestParam("booleanCheck") @AssertTrue boolean booleanCheck
    ) {
        // 요청 파라미터를 로그로 출력
        LOGGER.info("name={}, email={}, phoneNumber={}, age={}, description={}, count={}, booleanCheck={}",
            name, email, phoneNumber, age, description, count, booleanCheck);

        // 응답 본문으로 파라미터 내용을 문자열로 반환
        String response = String.format("name=%s, email=%s, phoneNumber=%s, age=%d, description=%s, count=%d, booleanCheck=%b",
            name, email, phoneNumber, age, description, count, booleanCheck);

        return ResponseEntity.status(HttpStatus.OK).body(response);
    }
}

(3) 스프링부트 서버 실행 후 swagger에 접속해서 확인

  • 스프링부트 서버 실행 시 오류 발생! DBC 드라이버가 데이터베이스 서버로부터 응답을 받지 못했으므로 윈도우의 '서비스'에서 MySQL8을 우클릭해서 '시작' 눌러서 해결 
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
2025-10-24 15:50:42.258 [main] WARN  o.h.e.j.e.i.JdbcEnvironmentInitiator - HHH000342: Could not obtain connection to query metadata
org.hibernate.exception.JDBCConnectionException: unable to obtain isolated JDBC connection [Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.] [n/a]

윈도우의 '서비스' 창

  • http://localhost:8080/swagger-ui/index.html에 접속하여 동작 확인

해당 메서드에서 Try it out 클릭
유효성 검사를 통과할 수 있는 값들을 넣고 Excute 클릭
당연히 200을 반환!

(4) 하나의 값이라도 유효성 검사에 맞지 않는 값을 입력하면 400 에러 발생
-> 예외 처리를 하지 않았으므로, 클라이언트는 어디서 에러가 발생했는지 알 수 없음

유효성 검사에 맞지 않는 값을 입력하고 다시 Execute
400 에러를 반환하는 모습

 

반응형