어떤 데이터의 값이 유효한지, 잘못된 내용이 있는지 확인하는 단계.
전체적 흐름
자바빈 validation을 이용해서 DTO 단에서 데이터를 간단하게 검증하고. 2차적으로 메서드 내부로 진입함. 로직으로 넘어와 권한, 서비스정책, API 호출이나 DB조회 등 데이터 검증을 실시하고 검증 실패시에 Exception으로 예외 던지고 처리하는 방식으로 사용함.
Maven프로젝트의 pom.xml에 디펜던시 추가한다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
JavaBean내의 어노테이션으로 검증방법을 명시할 수 있음
package com.example.controller.form;
import javax.validation.GroupSequence;
import javax.validation.constraints.NotEmpty;
import org.hibernate.validator.constraints.Length;
import com.example.validation.ValidationSteps;
import lombok.Data;
@Data
@GroupSequence({
BoardSaveForm.class,
ValidationSteps.Step1.class,
ValidationSteps.Step2.class,
ValidationSteps.Step3.class,
ValidationSteps.Step4.class,
ValidationSteps.Step5.class,
})
public class BoardSaveForm {
private int boardSeq;
@NotEmpty(groups = ValidationSteps.Step4.class, message = "{BoardSaveForm.boardType.notEmpty}")
private String boardType;
@NotEmpty(groups = ValidationSteps.Step1.class,message = "{BoardSaveForm.title.notEmpty}")
@Length(groups=ValidationSteps.Step3.class,
min=2, max=10,
message="{BoardSaveForm.title.length}")
private String title;
@NotEmpty(groups = ValidationSteps.Step5.class,message = "{BoardSaveForm.contents.notEmpty}")
private String contents;
//입력으로 받는것이 아니기 때문에 필드가 필요없음
// private String regDate;
@NotEmpty(groups = ValidationSteps.Step2.class,message = "{BoardSaveForm.userName.notEmpty}")
private String userName;
}
- @NotEmpty (javax.validation.constraints.NotEmpty) : null, 공백체크하는 어노테이션
- @Length(org.hibernate.validator.constraints.Length) : min, max 길이체크
- @NotEmpty내 원하는 메세지 넣기 : 여기서는 따로 message.properties에 작성하여 매핑함.
@PostMapping("/save")
public String save(@Validated BoardSaveForm form) { //**Validated 추가후 BoardSaveForm 으로 변경
//hasLength가 아니면 예외를 던짐
// Assert.hasLength(board.getUserName(),"회원 이름을 입력해주세요");
// Assert.hasLength(board.getTitle(),"제목을 입력해주세요");
// Assert.hasLength(board.getBoardType(),"종류를 입력해주세요");
// Assert.hasLength(board.getContents(),"내용을 입력해주세요");
Board selectBoard = null;
//게시글 수정으로 요청인 경우
if(form.getBoardSeq() > 0) {
selectBoard=boardService.selectBoard(form.getBoardSeq());
}
// 수정인 경우 업데이트
if(selectBoard != null) {
boardService.updateBoard(form);
}else {
//새로 작성인 경우 인서트
boardService.insertBoard(form);
}
return "redirect:/board";
}
- Board를 BoardSaveForm으로 import 변경. 변수도 board에서 form으로 변경
- @Validated (org.springframework.validation.annotation.Validated) : 유효성검증체크수행
package com.example.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.controller.form.BoardSaveForm;
import com.example.mapper.Board;
import com.example.mapper.BoardMapper;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class BoardService {
@Autowired
private final BoardMapper boardMapper;
/**
* 게시물 목록 조회후 리턴
*
* @return
*
*/
public List<Board> selectBoardList() {
return boardMapper.selectBoardList();
}
public Board selectBoard(int boardSeq){
return boardMapper.selectBoard(boardSeq);
}
public void insertBoard(BoardSaveForm board) {
boardMapper.insertBoard(board);
} //변경
public void deleteBoard(int boardSeq) {
boardMapper.deleteBoard(boardSeq);
}
public void updateBoard(BoardSaveForm board) {
boardMapper.updateBoard(board);
} //변경
}
- insertBoard, updateBoard 부분에 BoardSaveForm 변경
등록 버튼 눌렀을시 결과
package com.example.validation;
public class ValidationSteps {
public interface Step1 {}
public interface Step2 {}
public interface Step3 {}
public interface Step4 {}
public interface Step5 {}
}
BoardService에서 @GroupSequence 어노테이션을 선언하여
첫번째는 검증할 클래스, 두번째부터는 순서대로 검증할 인터페이스를 추가함.
(안해줄시, 검증안되는 필드 에러가 여러개라면, 돌아가면서 뜸)
BoardSaveForm.boardType.notEmpty=종류를 선택하세요.
BoardSaveForm.title.notEmpty=제목을 입력해주세요.
BoardSaveForm.contents.notEmpty=내용을 입력해주세요.
BoardSaveForm.userName.notEmpty=회원이름을 입력해주세요.
BoardSaveForm.title.length=제목을 2이상 10이하로 설정해주세요
웹관련 설정 파일 : 웹과 관련된 처리를 구현하기 위해 WebMvcConfigurer를 구현
참고 : https://kdevkr.github.io/all-message-codes-in-spring-boot/
- LocalValidatorFactoryBean는 Spring에서 Validator를 사용하기 위해서 필요함.
참고 : https://kapentaz.github.io/spring/Spring-Boo-Bean-Validation-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%95%8C%EA%B3%A0-%EC%93%B0%EC%9E%90/#
package com.example.configuration;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer{
/**
* 다국어 설정 및 메세지 프로퍼티 사용을 위한 빈 등록
* @return
*/
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource
messagesSource=new ReloadableResourceBundleMessageSource();
// 다국어 파일 경로 set
messagesSource.setBasename("classpath:config/messages/message");
messagesSource.setDefaultEncoding("UTF-8");
return messagesSource;
}
/**
* Validator 메시지 설정을 하기 위한 빈 등록 :
* message.properties에서 설정가능
*/
@Override
public Validator getValidator() {
LocalValidatorFactoryBean
factory=new LocalValidatorFactoryBean();
factory.setValidationMessageSource(messageSource());
return factory;
}
}
:WebMvcConfigurer 인터페이스를 구현하고 getValidator() 메소드를 오버라이드하여 ValidatorFactoryBean을 등록
결과 : 회원이름 입력안했을시
- 콘솔 에러코드
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors Field error in object 'boardSaveForm' on field 'userName': rejected value []; codes [NotEmpty.boardSaveForm.userName,NotEmpty.userName,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [boardSaveForm.userName,userName]; arguments []; default message [userName]]; default message [회원이름을 입력해주세요.]