server side validation
목차
사용자가 입력한 값에 대한 유효성을 서버에서 체크하는 것 ( 그동안은 client에서 했는데, 이것은 보안측면에서 봤을 때 좋지 않아)
이것 반드시 해야해.
- User validation check 추가 및 error message 처리
- validation library 추가
- validation annotation 처리
- 에러 메시지 처리
- validation error를 jsp에 보여주기
- 단위 테스트로 validation check 자동화하기
User validation check 추가 및 error message 처리
- spring mvc validation example annotation을 구글에 검색해서 링크 참고.
- 링크 잘 읽어보시고, 하단의 코드 pom.xml에 추가
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.0.Final</version>
</dependency>
* 위에서의 링크를 잘 읽어보면, 어떤 형태로 validation check를 할 수 있는지 써있어.
- User class를 하단의 코드처럼 바꿈
@NotNull @Min(4) @Max(12)
private String userId;
@NotNull @Min(4) @Max(12)
private String password;
@NotNull
private String name;
@Email
private String email;
- UserController class를 하단의 코드처럼 바꿈
public String create(@Valid User user, BindingResult bindingResult){
logger.debug("User : {}", user);
if ( bindingResult.hasErrors()) {
logger.debug("binding Result has error!");
List<ObjectError> errors = bindingResult.getAllErrors();
for (ObjectError error : errors) {
logger.debug("error : {}, {}", error.getCode(), error.getDefaultMessage());
}
//validation에서 에러가 뜨면 다시 입력화면으로 넘어갈겡
return "users/form";
}
userDao.create(user);
logger.debug("Database: {}", userDao.findById(user.getUserId()));
//에러가 에러가 없을 때는 다시 입력화면으로 넘어갈 것이 아니라, 메인으로 넘어가는게 좋으니까.
return "redirect:/";
}
- 구글에서 java validation annotation list로 검색하여 링크로 들어가서, 어떤 annotation을 쓸 수 있는지, custom validation check는 어떻게 할건지 등등 알아봐
- 또 다른 링크로는 튜토리얼 링크가 있어. 예시까지 아주 친절하니까 잘 보렴
*** User에서 추가한 코드를 약간 수정
@NotEmpty @Size(min=4, max=12)
private String userId;
@NotEmpty @Size(min=4, max=12)
private String password;
@NotEmpty
private String name;
@Email
private String email;
- 이유는
validation error를 jsp에 보여주기
- error 발생시 사용자에게 발생한 error message를 보여주도록 처리
- src/main/resources에 file을 추가 (messages.properties)
- 하단의 코드 추가
Size.user.userId = User {0} should be between {2} and {1} characters long
NotEmpty.user.userId = User {0} is required
Size.user.password = User password {0} should be between {2} and {1} characters long
NotEmpty.user.password = User {0} is required
NotEmpty.user.name = User {0} is required
* 뜻
* Size(유효성체크한 annotation이름).user(클래스 이름, 대문자 아님!!! 주의!!).userId(필드이름) = User {0} should be between {2} and {1} characters long
- rbwiki-servlet.xml에 하단의 코드 추가
<bean id ="messageSource" class = "org.springframework.context.support.ResourceBundleMessageSource" p:basename="messages"
p:defaultEncoding="UTF-8"
/>
* [[spring localization example | http://www.journaldev.com/2610/spring-mvc-internationalization-i18n-and-localization-l10n-example]] 을 참고하면 설정하는 방법이 나와있음.
* 한가지, classpath:는 추가하지 않는 것이 다름. 그렇게 하면 파일을 못찾아서 그냥 src/main/resources 하단에 놓고 쓰기로.
- 이제 이 error message를 사용자한테 보여줘야하니까, form.jsp의 각 필드마다 하단의 코드를 추가
<form:errors path="userId" cssClass="error" />
] 5. UTF-8을 추가함으로써 messages.properties 파일에 한글이 추가가 되지만 보기 불편하게 나온다. 이를 해결하기 위해 plugin설치
* help > eclipse marketplace > properties editor 검색 후 install > 전부 체크후 confirm > accept > 자동 재시작
-
이제 messages.properties에 가서 한글로 치면 정상적으로 보기 편하게 나온다.
-
추가적으로 spring localization example 에서 다국어 지원에 대한 설정도 할 수 있도록 나와있다.
- messages.properties는 default 언어로 하고, messages_en.properties를 하면 영어, messages_fr.properties로 하면 프랑스어 등으로 설정할 수 있다고 나와있음.
단위 테스트로 validation check 자동화하기
- java validation test는 hibernate라는 구현체를 사용
- 첫번째 목차에서 dependency 이미 추가
- 함께 추가했던 javax.validation은 삭제해도 됨.
- dependency hierarchy에 확인해보면, hibernate-validator가 추가되면 자동으로 javax.validation도 추가되게 되어있음
- hibernate validator test를 참고
- User.java에서 eclipse 상단의 c+모양 아이콘 클릭해서 Junit Test Case 클릭 > package를 src/test/java로 바꿔줌
- 하단의 코드 추가
private static Validator validator;
@BeforeClass
public static void setUp() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
* @beforeclass의 역할
* @before의 경우, 매 단위테스트마다 실행되는 것이고, @beforeclass는 테스트 통틀어 한번만 실행되는거야.
* 그에 대비되는 개념으로 @afterclass와 @after가 있어
- UserId 값이 empty일 때 제대로 처리되는지 확인하는 코드
@Test
public void userIdWhenIsEmpty() {
//사용자 데이터를 하나 추가하고
User user = new User("", "password", "name","111@111.com");
//유효성체크를 하자
Set<ConstraintViolation<User>> constraintViolations = validator.validate(user);
// validation이 맞지 않는 것이 2개인지 체크해라. (size를 지키지 않은 것, notempty를 지키지 않은 것)
assertThat(constraintViolations.size(), is(2));
}
* 뜻이 뭘까..뭐니?
* 에러 발생
* 위에서 제공한 링크의 문서를 참고하여 아래의 코드를 추가함으로써 해결
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.4</version>
</dependency>
* 테스트 성공 후 , 하단의 코드를 추가하여 validation violated된 부분을 에러 메세지로 확인할 수 있도록 함 .
for (ConstraintViolation<User> constraintViolation : constraintViolations) {
logger.debug("validation error message: {}", constraintViolation.getMessage());
}
* 그런데, 에러 메세지가 messages.properties의 내용이 아니다.
* testclass에서 사용중인 에러 메시지는 validation jar파일에서 기본으로 제공하고 있는 한글용 에러 메시지
@RequestMapping(value="", method=RequestMethod.POST)
public String create(@Valid User user, BindingResult bindingResult ){
logger.debug("User : {} " , user);
if(bindingResult.hasErrors()){
logger.debug("Binding Result has error!");
List<ObjectError> errors=bindingResult.getAllErrors();
for(ObjectError error : errors){
logger.debug("error : {}, {}", error.getCode(), error.getDefaultMessage());
}
return "users/form";
}
userDao.create(user);
logger.debug("Database : {} " , userDao.findById(user.getUserId()));
return "redirect:/";
}
댓글 ( 4)
댓글 남기기