728x90
반응형
커맨드 객체의 값 검증의 중요성
- 폼에 입력한 값을 검증하지 안흥면 잘못된 값이 시스템에 입력되어 어플리케이션이 비정상 동작할 수 있음
- 에러 메시지를 제대로 보여주지 않으면 사용자는 서비스를 제대로 이용할 수 없음
스프링이 제공하는 해결 방법
- 커맨드 객체를 검증하고 결과를 에러 코드로 저장
- JSP에서 에러 코드로부터 메시지를 출력
커맨드 객체 검증과 에러 코드 지정하기
스프링 MVC에서 커맨드 객체의 값이 올바른지 검사하기 위해 사용하는 인터페이스
org.springframework.validation
- Validator
- Errors
객체를 검증할 때 사용하는 Validator 인터페이스
package org.springframework.validation;
public interface Validator {
boolean supports(Class<?> clazz);
void validate(Object target, Errors errors);
}
supprots()
- Validator가 검증할 수 있는 타입인지 검사
- 첫 번째 파라미터로 전달받은 객체를 검증하고 오류 결과를 Errors에 담는 기능 정의
Validator 인터페이스 구현체
package controller;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import spring.RegisterRequest;
public class RegisterRequestValidator implements Validator {
private static final String emailRegExp = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@"
+ "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
private Pattern pattern;
public RegisterRequestValidator() {
pattern = Pattern.compile(emailRegExp);
}
/***
* 전달받은 clazz 객체가 RegisterRequest 클래스로 타입 변환이 가능한지 확인
* 스프링 MVC가 자동으로 검증 기능을 수행하도록 설정하려면 해당 메서드를 올바르게 구현해야한다.
*/
@Override
public boolean supports(Class<?> clazz) {
return RegisterRequest.class.isAssignableFrom(clazz);
}
/**
* target 파라미터 : 검사 대상 / erros 파라미터 : 검사 결과 에러코드를 설정
* 구현
* 1. 검사 대상 객체의 특정 프로퍼티나 상태가 올바른지 검사
* 2. 올바르지 않다면 Errors의 rejectValue() 메서드를 이용해 에러코드 저장
* - rejectValue(프로퍼티 이름, 에러 코드)
*/
@Override
public void validate(Object target, Errors errors) {
//검사대상 target을 실제 타입으로 변환 후 값 검사
RegisterRequest regReq = (RegisterRequest) target;
// 값 검사
if (regReq.getEmail() == null || regReq.getEmail().trim().isEmpty()) {
//email 프로퍼티 값이 존재하지 않으면 -> null or 빈 문자열
//email 프로퍼티의 에러 코드로 "required" 추가
errors.rejectValue("email", "required");
} else {
//이메일 정규표현식으로 올바른 이메일 형식인지 확인
Matcher matcher = pattern.matcher(regReq.getEmail());
if (!matcher.matches()) {
//정규 표현식이 일치하지 않으면, "email" 프로퍼티에 "bad" 추가
errors.rejectValue("email", "bad");
}
}
/**
* ValidationUtils 클래스
* - 객체의 값 검증 코드를 간결하게 작성할 수 있게 함.
* - 비어있거나,공백이 있는 경우 등 원활한 코드 작성
* - target 파라미터를 전달하지 않아도 프로퍼티 값 검사 가능
* - Errors 객체가 그 역할
* (컨트롤러의 요청 매핑 애노테이션 적용 메서드에 Errors 타입을 첫번째 파라미터로 전달받고
* Validator.validate() 메서드로 두 번째 파라미터로 전달받음
* -
*/
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "required");
ValidationUtils.rejectIfEmpty(errors, "confirmPassword", "required");
if (!regReq.getPassword().isEmpty()) {
if (!regReq.isPasswordEqualToConfirmPassword()) {
errors.rejectValue("confirmPassword", "nomatch");
}
}
}
}
위 코드의 상세 설명은 주석으로 처리하였다.
ValidationUtils 클래스
객체의 값 검증 코드를 간결하게 작성할 수 있도록 함.
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "required");
위 코드와 같은 코드
String name = regReq.getName(); if(name == null || name.trim().isEmpty()){ errors.rejectValue("name","required"); }
ValidationUtils.rejectIfEmptyOrWhitespace() 메서드 실행 시 target 객체 전달
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import spring.DuplicateMemberException;
import spring.MemberRegisterService;
import spring.RegisterRequest;
@Controller
public class RegisterController {
private MemberRegisterService memberRegisterService;
public void setMemberRegisterService(MemberRegisterService memberRegisterService) {
this.memberRegisterService = memberRegisterService;
}
...
@PostMapping("/register/step3")
public String handleStep3(RegisterRequest regReq, Errors errors) {
// regReq 커맨드 객체 요청 검증
/**
* @PostMapping 요청 애노테이션 적용 메서드의 커맨드 객체 파라미터 뒤 Errors 파라미터가 존재하면
* 스프링 MVC는 해당 메서드 호출 시 커맨드 객체와 연결된 Errors 객체를 생성해서 파라미터로 전달
* Errors.getFieldValue() 메서드 :커맨드 객체의 특정 프로퍼티 값을 구할 수 있는 메서드
* ValidationUtils.rejectIfEmptyOrWhitespace() 메서드는 커맨드 객체를 전달받지 않아도
* Errors 객체를 이용해 지정한 값 구할 수 있음.
*/
new RegisterRequestValidator().validate(regReq, errors);
if (errors.hasErrors()) {
return "register/step2";
}
try {
memberRegisterService.reigst(regReq);
return "register/step3";
} catch (DuplicateMemberException ex) {
//이메일 중복 익셉션 발생 시, "email" 프로퍼티 에러코드 "duplicate" 추가
errors.rejectValue("email", "duplicate");
return "register/step2";
}
}
}
커맨드 객체 자체가 잘못된 경우
reject() 메서드 사용
아이디와 비밀번호를 잘못 입력한 경우, 아이디와 비밀번호가 불일치 한다는 메시지를 보여줘야할 때
커맨드 객체 자체에 에러를 추가
try { ...인증 처리 코드 } catch(WrongIdPasswordException ex) { // 특정 프로퍼티가 아닌 커맨드 객체 자체에 에러코드 추가 errors.reject("notMatchingIdPassword"); return "login/loginForm";
객체 자체에 에러 코드를 추가하는 것을 글로벌 에러라고 한다.
요청 매핑 애노테이션을 붙인 메서드에 Erros 타입의 파라미터가 메소드의 첫번째 파라미터인 경우
주의 : Errors 파라미터는 반드시 커맨드 객체를 위한 파라미터 다음에 위치해야 한다.
이럴 경우 익셉션이 발생함
//Errors 타입 파라미터가 커맨드 객체 앞에 위치하면 실행 시점에 에러 발생 @PostMapping("/register/step3") public String handleStep3(Errors errors, RegisterRequest regReq){ ... }
Errors 대신 BindingResult 인터페이스 파라미터 타입으로 사용 가능
@PostMapping("/register/step3")
public String handleStep3(RegisterRequest regReq, BindingResult errors){
new RegisterRequestValidator().validate(regReq, errors);
...
}
728x90
반응형
'Spring' 카테고리의 다른 글
[Spring] 커맨드 객체의 에러 메시지 출력하기 (0) | 2024.05.14 |
---|---|
[Spring] Errors 와 ValidationUtils 클래스의 주요 메서드 (0) | 2024.05.13 |
[Spring] <spring:message> 메시지 인자 처리 (0) | 2024.05.11 |
[Spring] 메시지 처리 : MessageSource, <spring:message> (0) | 2024.05.11 |
[Spring] Spring Message 기능 사용해보기 (0) | 2024.05.07 |