유효성 검사
유효성 검사
웹 어플리케이션에서 사용자 입력에 대해 유효성을 검사해야 하는 경우가 있습니다.(회원가입 작성내용 규칙확인,글작성 작성내용 규칙 확인)
javascript로 처리할 수도 있지만 spring mvc를 이용하여 처리할 수도 있습니다.
javascript 로 처리
클라이언트 브라우저에서 서버로 요청을 발생하기 전에 확인을 하겠다는 의미
spring mvc에서 처리
클라이언트가 전달한 데이터를 서버에서 확인하고 그것을 저장할지 말지를 결정
JSR -303
spring mvc는 JSR-303규격의 유효성 검사 라이브러리를 사용할 수 있습니다
Bean에 데이터가 입력될 때 어떤 검사를 할 것인지 어노테이션으로 지정하고 지정된 어노테이션의 조건에 맞지 않으면 개발자에게 입력값에 오류가 있다는 정보를 전달합니다
->개발자가 정의한 bean에 일단 값은 주입이 됩니다 들어간 값을 검사해서 규칙에 올바르게 들어왔음과 그렇지 않음을 개발자에게 전달
개발자는 이를 통해 유효성 검사를 진행할 수 있습니다.
JSR-303을 사용하려면 라이브러리를 추가해야 합니다. JSR-303은 실제 유효성 검사를 할 클래스가 존재해야 하는데 여기서는 hibernate(실제로 입력한 데이터(변수에 주입된 값)을 검사하는 검사기)라는 라이브러리를 사용하겠습니다.
javax validation
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
hibernate
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.2.Final</version>
</dependency>
Bean에 어노테이션 설정
먼저 Bean에 어노테이션을 설정합니다 JSR-303과 Hibernate에서는 다양한 어노테이션을 제공하고 있습니다.
@Size(min = 2,max=10)
private String data1;
->이 변수에 들어올 수 있는값이 최소 2글자에서 최대 10글자 (값이 들어가긴 하지만 잘못됬다라는 정보가 같이 나옴
@Max(100)
private int data2;
->변수에 최대 100까지 들어갈 수 있음
package kr.co.softcampus.beans;
import javax.validation.constraints.Max;
import javax.validation.constraints.Size;
public class DataBean1 {
@Max(100)
private int data1;
@Size(min=2,max=10)
private String data2;
public int getData1() {
return data1;
}
public void setData1(int data1) {
this.data1 = data1;
}
public String getData2() {
return data2;
}
public void setData2(String data2) {
this.data2 = data2;
}
}
@Valid
Controller의 메서드에서 주입 받는 Bean에 @Valid를 설정하면 유효성 검사를 실시합니다.
유효성 검사 결과를 사용하고자 한다면 BindingResult 객체를 주입받아야하 합니다.
이 객체에는 유효성 검사를 실행한 결과 정보가 담겨있습니다.
이를 통해 Controller에서 사용자가 입력한 값에 문제가 있는지 파악할 수 있습니다.
ex)public String input_pro(@Valid DataBean1 dataBean1,BindingResult result)
package kr.co.softcampus.controller;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import kr.co.softcampus.beans.DataBean1;
@Controller
public class TestController {
@GetMapping("/input_data")
public String input_data() {
return "input_data";
}
@PostMapping("/input_pro")
public String input_pro(@Valid DataBean1 dataBean1,BindingResult result) {
System.out.println(dataBean1.getData1());
System.out.println(dataBean1.getData2());
System.out.println(result);
return "input_success";
}
}
유효성결과를 출력해보겠습니다 입력할때 data1은 유효성 오류를 입력할것이고 data2는 올바르게 입력하겠다
data1에는 111 data2는 aaa를 입력해보았다
결과창
111
aaa
org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'dataBean1' on field 'data1': rejected value [111]; codes [Max.dataBean1.data1,Max.data1,Max.int,Max]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [dataBean1.data1,data1]; arguments []; default message [data1],100]; default message [100 이하여야 합니다]
1 errors가 발생했고 data1에 에러가 발생했다는것을 볼 수 있다
위 에러를 ObjectError객체를 사용하여 정리하여 출력해보겠다
package kr.co.softcampus.controller;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import kr.co.softcampus.beans.DataBean1;
@Controller
public class TestController {
@GetMapping("/input_data")
public String input_data() {
return "input_data";
}
@PostMapping("/input_pro")
public String input_pro(@Valid DataBean1 dataBean1,BindingResult result) {
System.out.println(dataBean1.getData1());
System.out.println(dataBean1.getData2());
//유효성 검사에서 위반된 부분이 있다면..
if(result.hasErrors()) {//true면 유효성 위반 false면 유효성 위반x
//유효성 위반 결과를 모두 가져온다.
for(ObjectError obj:result.getAllErrors()) {//에러에 대한 정보가 담겨있는 객체가 리스트에 담겨져있음
System.out.println("메시지:"+obj.getDefaultMessage());
System.out.println("code:"+obj.getCode());
System.out.println("object name:"+obj.getObjectName());
System.out.println("-------------------------------------");
}
}
return "input_success";
}
}
결과
올바르지 않게 입력했을때.
111
aaaaaaaaaaaaaa
메시지:크기가 2에서 10 사이여야 합니다
code:Size
object name:dataBean1
-------------------------------------
메시지:100 이하여야 합니다
code:Max
object name:dataBean1
-------------------------------------
에러 내용이 모두 출력됨
올바르게 입력했을때.
23
aa
에러 내용이 없음
문제점
개발자가 사용한 어노테이션 max와 size이 여러개의 변수에 선언되어있으면 어떤 변수가 유효성 검사에서 걸렸는지 알 수 가 없다
Objecterror객체의 getCode는 개발자가 사용한 어노테이션을 출력하지만 getCodes는 어떤 변수에서 에러가 발생했는지도 알려준다.
String [] codes = obj.getCodes();
for(String c1:codes) {
System.out.println(c1);
}
데이터 값을 둘다 올바르지 않게 입력해보겠다
출력값
Max.dataBean1.data1//어떤 어노테이션의 어떤 bean의 어떤 변수가 에러가 있는지 알려줌 배열[0]
Max.data1//변수 배열[1]
Max.int//변수 타입[2]
Max//어노테이션[3]
Size.dataBean1.data2
Size.data2
Size.java.lang.String
Size
데이터 값을 둘다 올바르게 입력했을때
1
aaa
위를 봤을때 codes의 0번째 배열에 값이 Max.dataBean1.data1 ,Size.dataBean1.data2 이렇게 들어가 있으면 에러가 발생한 것이다 이때 에러내용을 출력해보자
if(codes[0].equals("Max.dataBean1.data1")){
System.out.println("data2는 100이하의 값만 담을 수 있습니다.");
}else if(codes[0].equals("Size.dataBean1.data2")) {
System.out.println("data1은 2~10글자를 담을 수 있다.");
}
총 정리
package kr.co.softcampus.controller;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import kr.co.softcampus.beans.DataBean1;
@Controller
public class TestController {
@GetMapping("/input_data")
public String input_data() {
return "input_data";
}
@PostMapping("/input_pro")
public String input_pro(@Valid DataBean1 dataBean1,BindingResult result) {
System.out.println(dataBean1.getData1());
System.out.println(dataBean1.getData2());
//유효성 검사에서 위반된 부분이 있다면..
if(result.hasErrors()) {//true면 유효성 위반 false면 유효성 위반x
//유효성 위반 결과를 모두 가져온다.
for(ObjectError obj:result.getAllErrors()) {//에러에 대한 정보가 담겨있는 객체가 리스트에 담겨져있음
/*
* System.out.println("메시지:"+obj.getDefaultMessage());
* System.out.println("code:"+obj.getCode());
* System.out.println("object name:"+obj.getObjectName());
* System.out.println("-------------------------------------");
*/
String [] codes = obj.getCodes();
for(String c1:codes) {
System.out.println(c1);
}
if(codes[0].equals("Max.dataBean1.data1")){
System.out.println("data2는 100이하의 값만 담을 수 있습니다.");
}else if(codes[0].equals("Size.dataBean1.data2")) {
System.out.println("data1은 2~10글자를 담을 수 있다.");
}
}
return "input_data";//에러가 있으면 다시 입력하도록
}
return "input_success";
}
}
유효성 검사후 jsp에 검사 결과 출력하는방법
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix='c' uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix='spring' uri="http://www.springframework.org/tags"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action='input_pro' method='post'>
data1:<input type='text' name='data1'></br>
<spring:hasBindErrors name="dataBean1"> <!-- dataBean1 bean에 유효성 검사에 문제가 있는게 있는가? -->
<c:if test="${errors.hasFieldErrors('data1') }"> <!-- data1 프로퍼티에 문제가 있는가 -->
${errors.getFieldError('data1').defaultMessage } <!-- 문제가 있으면 여기에 출력을해라 -->
</c:if>
</spring:hasBindErrors>
data2:<input type='text' name='data2'></br>
<spring:hasBindErrors name="dataBean2"> <!-- dataBean1 bean에 유효성 검사에 문제가 있는게 있는가? -->
<c:if test="${errors.hasFieldErrors('data2') }"> <!-- data1 프로퍼티에 문제가 있는가 -->
${errors.getFieldError('data2').defaultMessage } <!-- 문제가 있으면 여기에 출력을해라 -->
</c:if>
</spring:hasBindErrors>
<button type="submit">전송</button>
</form>
</body>
</html>