아이디나 비밀번호 입력, 이메일 입력 등에서의 제약조건 (대,소문자,10글자 등)은 보통 js나 jquery로 Client에서 수행하는데, 이 작업을 서버(JAVA)단에서도 할 수 있는 것이다.
폼에서 전달되는 데이터를 위의 커맨드 객체(데이터 객체)에 담아 컨트롤 객체에 전달하는데, 이때 유효성 검사를 할 수 있다.
Validator 인터페이스
유효성 검사를 수행해주는 객체는 다음과 같다. 우선 Validator 인터페이스를 구현하는 클래스를 만든다.
validate는 유효성 검사, supports는 지원하는지에 대해 체크하는 메소드이다.
Error 객체의 rejectValue 메소드를 통해 에러정보를 추가할 수 있다.
public class MemberValidator implements Validator{
public void validate(Object obj, Errors error) {
System.out.println("validate action");
Member member = (Member)obj;
String id = member.getId();
String pw = member.getPw();
//id가 비었는지 확인
if(id == null || pw.trim().isEmpty()) {
error.rejectValue("id", "required");
}
//id가 20자 이상인지 확인
else if(id.length() >= 10) {
error.rejectValue("id", "long");
}
//pw 길이가 8자 이하인지 확인
if(pw.length() <= 8) {
error.rejectValue("pw", "short");
}
}
@Override
public boolean supports(Class<?> clazz) {
return Member.class.isAssignableFrom(clazz);
}
}
이제 컨트롤러에서 다음 Valdiator를 활용한다.
@RequestMapping("/ex")
public String samplecontent(@ModelAttribute("mem") @Valid Member member, BindingResult result) {
MemberValidator validator = new MemberValidator();
validator.validate(validator, result);
String path = "sampleResult";
if(result.hasErrors()) {
path = "home";
}
return path;
}
BindingResult는 validate의 결과를 담는 객체로, hasErrors() 메소드를 통해 에러가 있는지 확인할 수 있다.
에러가 있으면 home (처음 id입력 뷰)로 돌아가게, 없으면 결과창으로 진행되게 하였다.
ValidationUtils 클래스를 사용하여 validate 메소드에서 조건을 일일히 안만들고 사용할 수도 있다.
pw가 비워져 있는지 확인하는 부분을 다음과 같이 한줄로 할 수 있다.
ValidationUtils.rejectIfEmptyOrWhitespace(error, "pw", "required");
@Valid, @InitBinder
직접 validate() 메소드를 호출하지 않고, 스프링에서 호출하는 방법이다.
일단 pom.xml에 의존을 추가한다.
<!-- Validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.8.Final</version>
</dependency>
그리고 위의 컨트롤러의 커맨드 객체 앞에 @Valid 키워드를 추가하여 스프링에서 자동으로 유효성 검사를 호출할 수 있도록 한다. (추가적으로 내가 Validator 객체를 생성하여 검사할 필요가 없다.)
@RequestMapping("/ex")
public String samplecontent(@Valid Member member, BindingResult result) { //Binding = 결과를 담아주는 객
String path = "sampleResult";
if(result.hasErrors()) {
path = "home";
}
return path;
}
이때 미리 @InitBinder를 통해 Validator를 미리 설정해두어야 한다.
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(new MemberValidator());
}
이렇게 한다면, 자동으로 Spring에서 지정된 Validator (MemberValidator)를 실행해 유효성 검사를 수행한다.
hibernate 검사
hibernate에서 제공하던 검사 기능이 자바에서도 제공되면서 annotation으로 간편하게 검사할 수 있다.
간단한 annotation은 위의 hibernate-validator만으로 가능하나, DB 컬럼 매핑등 다양하게 사용하기 위해서는 hibernate-annotations를 사용해야 한다.
<!-- hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.5.6-Final</version>
</dependency>
public class Member {
@Id //DB 테이블에서 priamry key로 매핑
@Size(min = 5, max=10, message="아이디는 5~10자로 작성해야 합니다.")
String id;
@Column
@NotNull
@Size(min = 8, max= 20, message="비밀번호는 8~20자로 작성해야 합니다.")
@Pattern(regexp="^[0-9]+$", message="숫자만 입력가능합니다.")
String pw;
//getter, setter 설정
/* 아래 이외에도 다양한 종류가 존재한다.
@AssertTrue 참
@DecimalMax 지정 값 이하의 실수
@DecimalMin 지정 값 이상의 실수
@Digits(integer=,fraction=) 정수 여부
@Pattern(regexp="()") 원하는 패턴 여부
@Future 미래
@Past 과거
@Max 지정 값 이상
@Min 지정 값 이하
@NotNull
@Null
@Size(min=,max=) 문자열 또는 배열등의 길이*/
이후 커맨드 객체에 @Valid를 적용하면 된다. @InitBinder는 하지 않아도 된다.
Validator 에러메시지 확인하기
hibernate를 사용한 검사에서 에러메시지를 확인하기 위해서 home.jsp를 수정해보자.
form 태그는 HTML form에 데이터 바인딩, 에러처리 등을 간편하게 할 수 있도록 도와준다.
다음과 같이 다양하게 존재한다.
<form:input> == <input type ="text">
<form:password> == <input type ="password">
<form:select>, <form:option>, <form:label>, <form:checkbox>
form 태그를 사용하기 위해서는 태그라이브러리를 import하고 사용하여야 한다.
modelAttribute는 Controller에서와 일치시켜야 하고 (다시 돌아왔을때 에러를 방지하기 위해)
에러는 errors 태그를 사용하여 에러정보를 출력할 수 있다.
path는 커맨드 객체의 특정 속성 (필드)로 이에 관련된 에러 메시지를 출력할 수 있게 해준다.
element는 에러메시지 출력시 사용할 HTML 태그, delimiter는 에러메시지 구분시 (여러개) 사용할 HTML 태그이다.
<!-- home.jsp -->
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<form:form action="/example/ex" method="post" modelAttribute ="mem">
<form:input path="id"/>
<form:errors path="id" element="div" delimiter=" "/>
<form:password path="pw"/>
<form:errors path="pw" element="div" delimiter=" "/>
<button class="btn" type="submit"> 전송 </button>
</form:form>
근데 이대로만 한다면 HTTP 500 에러가 발생한다.
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'mem' available as request attribute
왜냐면 처음에 컨트롤러에서 -> 입력받는 뷰로 보낼때 mem이라는 타겟 객체가 없기 때문이다.
해결방법으로 빈 커맨더 객체를 입력받을 뷰를 호출할때 컨트롤러에서 보내주면 된다.
//빈 객체 추가해서 보내주기
model.addAttribute("mem", new Member());
return "home";
'코딩 > 스프링 [JAVA]' 카테고리의 다른 글
Cannot resolve table Error (Spring Boot, JPA) (0) | 2021.03.23 |
---|---|
Spring Boot CORS header 'Access-Control-Allow-Origin' 에러 (0) | 2021.03.04 |
Form 데이터 주고 받기 [Spring, HttpServletRequest] (0) | 2021.01.14 |
스프링 컨트롤러 [Spring, RequestMapping] (0) | 2021.01.14 |
Spring MVC [Controller, servlet-context, eclipse] (1) | 2021.01.12 |
Comment