*책 내용과 다르게, 다음과 같은 환경에서 프로젝트 생성
- Windows11(윈도우 11) 환경
- 자바 JDK 17 버전 설치 https://yungenie.tistory.com/11
[Java] 차근차근 Java 설치하기 (JDK17, Window 11)
자바 개발 도구 설치 방법에 대해서 알아보겠습니다. Java17은 LTS(Long Term Support : 장기 지원) 릴리즈로 1년 후까지 기술 지원 및 버그를 개선한 서비스를 제공받을 수 있습니다. 업데이트 버전을 꾸
yungenie.tistory.com
- 스프링 부트 4.31.0 사용 - STS(Spring Tool Suite) 설치(Spring Tools for Eclipse - https://spring.io/tools)
=> https://priming.tistory.com/147 참고
[Windows] Spring Tool Suite 4(STS 4) 다운로드 및 설치
STS란?Spring Tool Suite(STS)는 스프링 프로젝트를 생성하고, 개발할 수 있게 해주는 도구입니다. STS 설치 과정에 대해 설명드리겠습니다. 설치 파일 다운로드STS 공식 사이트에서 설치 파일을 다운로
priming.tistory.com

- MySQL Community Server 8.0.42 설치 https://dev.mysql.com/downloads/mysql/
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 프로젝트 생성한 과정



*** 함께 보면 좋은 글
스프링 부트 핵심 가이드(장정우 지음) - 스프링 부트 개요
1. 스프링 프레임워크자바(Java) 기반 애플리케이션 프레임워크로, 엔터프라이즈급(기업 환경 대상 개발) 애플리케이션을 위한 다양한 기능 제공-> 오픈소스 경량급 애플리케이션 프레임워크로
keep-programming-study.tistory.com
스프링 부트 핵심 가이드(장정우 지음) - 개발에 앞서 알면 좋은 기초 지식
1. 서버 간 통신마이크로서비스 아키텍처에서 한 서버가 다른 서버에 통신을 요청하는 것을 의미-> 한 대는 서버/다른 한 대는 클라이언트가 됨 가장 많이 사용되는 방식은 HTTP/HTTPS 방식(TCP/IP, SOA
keep-programming-study.tistory.com
스프링 부트 핵심 가이드(장정우 지음) - REST API 명세를 문서화하는 방법(Swagger), 로깅 라이브러리
*책 내용과 다르게, 다음과 같은 환경에서 프로젝트 생성 Windows11(윈도우 11) 환경자바 JDK 17 버전 설치 https://yungenie.tistory.com/11 [Java] 차근차근 Java 설치하기 (JDK17, Window 11)자바 개발 도구 설치 방법
keep-programming-study.tistory.com
스프링부트 핵심 가이드(장정우 지음) - 유효성 검사(1)
*책 내용과 다르게, 다음과 같은 환경에서 프로젝트 생성 Windows11(윈도우 11) 환경자바 JDK 17 버전 설치 https://yungenie.tistory.com/11 [Java] 차근차근 Java 설치하기 (JDK17, Window 11)자바 개발 도구 설치 방법
keep-programming-study.tistory.com
1. @Validated 활용
- 스프링에서는, 자바에서 지원하는 @Valid 어노테이션과는 별도의 어노테이션으로 유효성 검사 지원
-> @Valid 어노테이션의 기능을 포함하고 있으므로, @Valid를 @Validated로 변경 가능 - @Validated에서는 유효성 검사를 그룹으로 묶어, 대상을 특정할 수 있는 기능이 있음
*스프링 부트에서 예제 생성
- data 패키지 내에 group 패키지 생성 후, ValidationGroup1과 ValidationGroup2라는 인터페이스 생성
-> 두 인터페이스 모두 내부 코드 없이, 인터페이스만 생성한 후 그룹화하는 용도
(1) 검증 그룹 설정-DTO 객체 새로 생성
package com.example.demo.jpa.data.dto;
import com.example.demo.jpa.data.group.ValidationGroup1;
import com.example.demo.jpa.data.group.ValidationGroup2;
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;
//DTO 클래스: 클라이언트 요청 데이터를 담는 용도
@Data // Lombok: getter/setter, equals, hashCode, toString 자동 생성
@NoArgsConstructor // Lombok: 기본 생성자 자동 생성
@AllArgsConstructor // Lombok: 모든 필드를 받는 생성자 자동 생성
@ToString // Lombok: toString 메서드 자동 생성
@Builder // Lombok: 빌더 패턴 지원
public class ValidatedRequestDto {
// name은 반드시 값이 있어야 함 (null 또는 빈 문자열 불가)
@NotBlank
private String name;
// email은 이메일 형식이어야 함 (예: user@example.com)
@Email
private String email;
// 휴대폰 번호는 정규식에 맞아야 함: 010, 011, 016~019로 시작하고 중간에 - 또는 . 가능
// 예: 010-1234-5678 또는 011.2345.6789
@Pattern(regexp = "01(?:0|1|[6-9])[.-]?(\\d{4})[.-]?(\\d{4})$")
private String phoneNumber;
// age는 ValidationGroup1일 때 최소 20 이상이어야 함
@Min(value = 20, groups = ValidationGroup1.class)
// age는 ValidationGroup2일 때 최대 40 이하이어야 함
@Max(value = 40, groups = ValidationGroup2.class)
private int age;
// description은 길이가 0~40자 사이여야 함
@Size(min = 0, max = 40)
private String description;
// count는 ValidationGroup2일 때 양수여야 함 (0보다 커야 함)
@Positive(groups = ValidationGroup2.class)
private int count;
// booleanCheck는 반드시 true여야 함 (예: 체크박스가 선택된 상태)
@AssertTrue
private boolean booleanCheck;
}
(2) ValidationController.java에 코드 추가
마찬가지로 전에 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 com.example.demo.jpa.data.dto.ValidatedRequestDto;
import com.example.demo.jpa.data.group.ValidationGroup1;
import com.example.demo.jpa.data.group.ValidationGroup2;
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.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
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);
... 생략 ...
/**
* 기본 유효성 검사
* - DTO 전체에 대해 유효성 검사를 수행
* - DTO 클래스에 선언된 모든 제약 조건을 검사
* - 유효성 그룹을 지정하지 않기 때문에 모든 필드가 검사 대상
*/
// POST 요청을 "/validation/validated" 경로로 매핑
@PostMapping("/validated")
public ResponseEntity<String> checkValidation(
@Validated @RequestBody ValidatedRequestDto validatedRequestDto
) {
LOGGER.info(validatedRequestDto.toString());
return ResponseEntity.status(HttpStatus.OK).body(validatedRequestDto.toString());
}
/**
* 그룹1 기반 유효성 검사
* - ValidationGroup1 인터페이스에 해당하는 필드만 검사
* - DTO 클래스에서 각 필드에 `groups = ValidationGroup1.class`로 지정된 제약 조건만 적용
*/
// POST 요청을 "/validation/validated/group1" 경로로 매핑
@PostMapping("/validated/group1")
public ResponseEntity<String> checkValidation1(
@Validated(ValidationGroup1.class) @RequestBody ValidatedRequestDto validatedRequestDto
) {
LOGGER.info(validatedRequestDto.toString());
return ResponseEntity.status(HttpStatus.OK).body(validatedRequestDto.toString());
}
/**
* 그룹2 기반 유효성 검사
* - ValidationGroup2 인터페이스에 해당하는 필드만 검사
* - DTO 클래스에서 `groups = ValidationGroup2.class`로 지정된 필드만 검사 대상입
*/
// POST 요청을 "/validation/validated/group2" 경로로 매핑
@PostMapping("/validated/group2")
public ResponseEntity<String> checkValidation2(
@Validated(ValidationGroup2.class) @RequestBody ValidatedRequestDto validatedRequestDto
) {
LOGGER.info(validatedRequestDto.toString());
return ResponseEntity.status(HttpStatus.OK).body(validatedRequestDto.toString());
}
}
2. 커스텀 Validation 추가
- 실무에서는 유효성 검사를 할 때 자바/스프링의 유효성 검사 어노테이션에서 제공하지 않는 기능을 써야 할 때도 있는데,
이 경우 ConstraintValidator와 커스텀 어노테이션을 조합하여 별도 유효성 검사 어노테이션 생성
1) Telephone 어노테이션 인터페이스 생성
package com.example.demo.config.annotation;
import jakarta.validation.Constraint;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
/**
* 커스텀 유효성 검사 어노테이션 정의: @Telephone
* - 전화번호 형식을 검증하기 위한 어노테이션
* - 해당 어노테이션이 붙은 필드는 TelephoneValidator 클래스에 의해 유효성 검사를 받음
*/
@Target(ElementType.FIELD) // 이 어노테이션은 필드에만 적용됩니다.
@Retention(RetentionPolicy.RUNTIME) // 런타임 시에도 어노테이션 정보가 유지되어야 합니다.
@Constraint(validatedBy = TelephoneValidator.class) // 실제 유효성 검사 로직을 수행할 클래스 지정
public @interface Telephone {
/**
* 유효성 검사 실패 시 반환할 기본 메시지
* - 필요 시 @Telephone(message = "커스텀 메시지")로 오버라이드 가능
*/
String message() default "전화번호 형식이 일치하지 않습니다.";
/**
* 유효성 검사 그룹 지정
* - Bean Validation의 그룹 기능을 사용할 때 활용
*/
Class[] groups() default {};
/**
* 추가적인 메타 정보 전달용
* - 기본적으로 잘 사용되지는 않지만, 확장 시 활용 가능
*/
Class[] payload() default {};
}
2) 전화번호 형식이 일치하는지 확인하는 유효성 검사 어노테이션 생성
package com.example.demo.config.annotation;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
/**
* 커스텀 유효성 검사 로직 클래스: TelephoneValidator
* - @Telephone 어노테이션이 붙은 필드에 대해 실제 유효성 검사를 수행
* - ConstraintValidator<Telephone, String>을 구현하여 String 타입의 전화번호를 검사
*/
public class TelephoneValidator implements ConstraintValidator<Telephone, String> {
/**
* 유효성 검사 로직을 구현하는 메서드
* @param value 검사 대상 값 (전화번호 문자열)
* @param context 유효성 검사 컨텍스트 (메시지 설정 등 가능)
* @return true: 유효한 값 / false: 유효하지 않은 값
*/
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// 값이 null이면 유효하지 않음
if (value == null) {
return false;
}
// 정규식을 통해 전화번호 형식 검사
// 예: 010-1234-5678, 011.234.5678 등
return value.matches("01(?:0|1|[6-9])[.-]?(\\d{3}|\\d{4})[.-]?(\\d{4}))$");
}
}
3) ValidatedRequestDto 클래스에 적용
package com.example.demo.jpa.data.dto;
import com.example.demo.config.annotation.Telephone;
import com.example.demo.jpa.data.group.ValidationGroup1;
import com.example.demo.jpa.data.group.ValidationGroup2;
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;
//DTO 클래스: 클라이언트 요청 데이터를 담는 용도
@Data // Lombok: getter/setter, equals, hashCode, toString 자동 생성
@NoArgsConstructor // Lombok: 기본 생성자 자동 생성
@AllArgsConstructor // Lombok: 모든 필드를 받는 생성자 자동 생성
@ToString // Lombok: toString 메서드 자동 생성
@Builder // Lombok: 빌더 패턴 지원
public class ValidatedRequestDto {
@NotBlank
private String name;
@Email
private String email;
// 휴대폰 번호는 정규식에 맞아야 함: 010, 011, 016~019로 시작하고 중간에 - 또는 . 가능
// - 검증식은 직접 생성한 어노테이션으로 적용
@Telephone
private String phoneNumber;
@Min(value = 20, groups = ValidationGroup1.class)
@Max(value = 40, groups = ValidationGroup2.class)
private int age;
@Size(min = 0, max = 40)
private String description;
@Positive(groups = ValidationGroup2.class)
private int count;
@AssertTrue
private boolean booleanCheck;
}
'스프링(Spring), 스프링부트(SpringBoot) > 스프링부트(SpringBoot) 기초' 카테고리의 다른 글
| 스프링부트 핵심 가이드(장정우 지음) - 유효성 검사(1) (0) | 2025.10.24 |
|---|---|
| 스프링 부트 핵심 가이드(장정우 지음) - 연관관계 매핑 in JPA 마지막[영속성 전이(Cascade)] (0) | 2025.10.20 |
| 스프링 부트 핵심 가이드(장정우 지음) - 연관관계 매핑 in JPA 2[다대일 매핑 예시, 일대다 매핑 예시, 다대다 매핑 예시] (0) | 2025.10.17 |
| 스프링 부트 핵심 가이드(장정우 지음) - 연관관계 매핑 in JPA[연관관계 매핑 개요, 연관관계 매핑 종류와 방향, 일대일 매핑 예시] (0) | 2025.09.27 |
| 스프링 부트 핵심 가이드(장정우 지음) - Spring Data JPA 활용 4(JPA Auditing 적용) (0) | 2025.09.02 |