풀스택 개발자 2020. 5. 10. 19:26

유효성 검사

웹 어플리케이션에서 사용자 입력에 대해 유효성을 검사해야 하는 경우가 있습니다.(회원가입 작성내용 규칙확인,글작성 작성내용 규칙 확인)

 

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>