본문 바로가기

공부/Spring

[Spring] Chapter 12 - MVC 2 : 메시지, 커맨드 객체 검증


Chapter 12 내용

  • 메시지 처리
  • 커맨드 객체 검증

 

<spring:message>태그로 메시지 출력, 다국어 처리하기



- 이메일과 같은 문자열은 로그인, 회원가입, 회원 정보 등 반복되 사용할 떄 전 세계를 대상으로 다국어 지원을 해야하는데 언어별로 뷰 코드를 따로 만들수는 없다.

 

-  다국어 지원을 위해 뷰 코드에서 사용할 문자열을 언어별로 파일에 보관해 뷰 코드가 언어에 따라 알맞은 파일을 읽어와 출력하게 한다.

 

  • 문자열을 담은 메시지 파일 작성하기
  • 메시지 파일에서 값을 읽어오는 MessageSource 빈 설정
  • JSP 코드에서 <spring:message>태그를 사용


1. 메시지 파일을 작성


- 메시지 파일을 보관하기 위해 src/main/resources에 message 폴더를 생성하고 label.properties파일을 작성한다.

 

 

member.register=회원가입
term=약관
term.agree=약관동의
next.btn=다음단계
member.info=회원정보
email=이메일
name=이름
password=비밀번호
password.confirm=비밀번호 확인
register.btn=가입 완료
register.done=<strong>{0}님 ({1})</strong>, 회원 가입을 완료했습니다.



2. MessageSource 타입의 빈을 추가한다.

 

스프링 설정파일에서 MessageSource 타입의 빈을 등록한다.

 
    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource ms = 
                new ResourceBundleMessageSource();
        ms.setBasenames("message.label");
        ms.setDefaultEncoding("UTF-8");
        return ms;
    }
 
 
cs


ms.setBasenames("message.label")
- message 패키지에 속한 label 프로퍼티 파일로부터 메시지를 읽어온다고 설정

 

3. 뷰 파일 수정


메시지 파일과 빈으로 등록했다면 <spring:message> 태그를 사용해서 꺼내쓰면 된다.

<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<!DOCTYPE html>
<html>
<head>
    <title><spring:message code="member.register" /></title>
</head>
<body>
    <h2><spring:message code="term" /></h2>
    <p>약관 내용</p>
    <form action="step2" method="post">
    <label>
        <input type="checkbox" name="agree" value="true"> 
        <spring:message code="term.agree" />
    </label>
    <input type="submit" value="<spring:message code="next.btn" />" />
    </form>
</body>
</html>
 
 
cs

 

다국어 지원을 위한 메시지 파일
- label_ko.properties
- label_en.properties

label 뒤에 '_언어' 형식의 언어 구분자를 작성해 주면 된다.
언어 구분자는 , 브라우저가 서버에 요청을 전송할 때 Accept-Language 헤더에 언어 정보를 담아 전송하는데, 한글인 경우에는 ko를 전송한다.

스프링 MVC는 웹 브라우저가 전송한 Accept-Langauge 헤더를 이용해서 Locale를 구하고, Locale을 MessageSource에서 메시지를 구할 때 사용한다.


<spring:message> 태그는 스프링 설정에 등록된 'messageSource' 빈을 이용해 메시지를 구하는데, 내부적으로 messageSource의 getMessage()메서드를 실행해서 필요한 메시지를 구하는 방식이다.


4. <spring:message> 태그의 메시지 인자 처리

 

register.done=<strong>{0}님 ({1})</strong>, 회원 가입을 완료했습니다.


위와 같이 인덱스로 메시지를 출력 할 수 있다.

 

  • 콤마로 구분한 문자열
  • 객체 배열
  • <spring:argument> 태그 사용


위 3가지 방식을 사용하면 된다.

 

    <p>
        <spring:message code="register.done">
            <spring:argument value="${registerRequest.name}" />
            <spring:argument value="${registerRequest.email}" />
        </spring:message>
    </p>
 
 
    <p>
        <spring:message code="register.done" argument= "${registerRequest.name}","${registerRequest.email}"/>
    </p>
 
cs

 

커맨드 객체의 값 검증과 에러 메시지 처리


 

- 코드가 동작은 하지만, 비정상적인 값을 입력했을때는 동작하지 않아야된다. 
- 비정상적인 값을 체크하기 위해 객체 검증을 한다.

객체 검증 인터페이스

  • org.strpingframework.validation.Validator
  • org.springframework.validation.Errors
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);
        System.out.println("RegisterRequestValidator#new(): " + this);
    }
    @Override public boolean supports(Class <?> clazz) {
        return RegisterRequest.class.isAssignableFrom(clazz);
    }
    @Override public void validate(Object target, Errors errors) {
        System.out.println("RegisterRequestValidator#validate(): " + this);
        RegisterRequest regReq = (RegisterRequest)target;
        if (regReq.getEmail() == null || regReq
                .getEmail()
                .trim()
                .isEmpty()) {
            errors.rejectValue("email", "required");
        } else {
            Matcher matcher = pattern.matcher(regReq.getEmail());
            if (!matcher.matches()) {
                errors.rejectValue("email", "bad");
            }
        }
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "required");
        ValidationUtils.rejectIfEmpty(errors, "password", "required");
        ValidationUtils.rejectIfEmpty(errors, "confirmPassword", "required");
        if (!regReq.getPassword().isEmpty()) {
            if (!regReq.isPasswordEqualToConfirmPassword()) {
                errors.rejectValue("confirmPassword", "nomatch");
            }
        }
    }
}
if (regReq.getEmail() == null || regReq
        .getEmail()
        .trim()
        .isEmpty()) {
    errors.rejectValue("email", "required");
} else {
    Matcher matcher = pattern.matcher(regReq.getEmail());
    if (!matcher.matches()) {
        errors.rejectValue("email", "bad");
    }
}

 

ValudationUtils 검증 코드 간결

 

- 객체의 값 검증 코드를 간결하게 작성할 수 있다.

ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "required");
ValidationUtils.rejectIfEmpty(errors, "password", "required");
ValidationUtils.rejectIfEmpty(errors, "confirmPassword", "required");

 


유효성 검사해주는 클래스를 생성하고, 이 클래스를 사용해서 객체를 검증해주면 된다.

 

    @PostMapping("/register/step3")
    public String handleStep3(RegisterRequest regReq, Errors errors) {
        new RegisterRequestValidator().validate(regReq, errors);
        if (errors.hasErrors())
            return "register/step2";
 
        try {
            memberRegisterService.regist(regReq);
            return "register/step3";
        } catch (DuplicateMemberException ex) {
            errors.rejectValue("email""duplicate");
            return "register/step2";
        }
    }
 
cs


public String handleStep3(RegisterRequest regReq, Errors errors) 처럼 Errors 타입 파라미터가 커맨드 객체 뒤에 위치하면, 스프링 MVC에서 메서드를 호출할 때 커맨드 객체와 연결된 Errors 객체를 생성해서 파라미터로 전달한다.

위의 코드에서 new RegisterRequestValidator().validate로 객체 생성, validate()메서드를 실행하고, 커맨드 객체의 값이 올바른지 검사 후 결과를 Error객체에 담았다.

 

REFERENCE


 초보 웹 개발자를 위한 스프링 5 프로그래밍 입문(최범균)

300x250