====== Commons Validator에 validation rule 추가하기 ====== ===== 개요 ===== Commons Validator는 primitive type, 필수값, 이메일등 흔히 사용되는 유형에 대한 validation rule을 template으로 제공하지만, \\ 프로젝트의 특성에 따라 공통으로 사용되는 validation rule이 발생되고 이를 추가해야할 필요가 생길 수 있다. \\ 공공프로젝트에서 흔히 사용되는 주민등록번호 validator를 추가해 봄으로써, validation rule을 추가하는 방법을 알아보고자 한다. \\ 예제는 easycompany를 이용했다. \\ \\ ===== 설명 ===== Spring Module을 이용해서 Commons Validator를 사용한다면 아래와 같은 내용을 validation rule 정의 파일(validator-rules.xml 같은)에서 보았을 것이다. \\ validator 태그의 각각의 attribute는 다음과 같은 의미를 같는다. ^ name | validation rule(required,mask,integer,email...) | ^ classname | validation check를 수행하는 클래스명 | ^ method | validation check를 수행하는 클래스의 메소드명 | ^ methodParams | validation check를 수행하는 클래스의 메소드의 파라미터 | ^ msg | 에러 메시지 key | ^ javascript | client-side validation을 위한 자바스크립트 코드 | 주민등록번호 rule을 아래와 같이 추가한다고 하면, 필요한 작업은 아래와 같다. \\ - [[#FieldCheck class 작성|FieldCheck class(RteFieldChecks) 작성]] - [[#Validator class 작성|Validator class(RteGenericValidator) 작성]] - [[#validator-rules.xml 설정|validator-rules.xml 설정]] - [[#validator.xml 설정|validator.xml 설정]] - [[#에러메시지 설정|에러메시지 설정]] - [[#TEST|TEST]] ==== FieldCheck class 작성 ==== org.springmodules.validation.commons.FieldChecks를 상속 받는 RteFieldChecks 클래스를 생성한다. \\ 그리고 주민등록번호 validation을 담당할 validateIhIdNum 메소드를 추가한다. \\ 주민등록번호 validation 로직이 RteFieldChecks.validateIhIdNum() 안에 있어도 되지만, org.springmodules.validation.commons.FieldChecks와 같은 방식으로 다른 Validator에 위임했다. package egovframework.rte.ptl.mvc.validation; import org.apache.commons.validator.Field; import org.apache.commons.validator.ValidatorAction; import org.springframework.validation.Errors; import org.springmodules.validation.commons.FieldChecks; public class RteFieldChecks extends FieldChecks{ public static boolean validateIhIdNum(Object bean, ValidatorAction va, Field field, Errors errors){ //bean에서 해당 field 값을 추출 String ihidnum = FieldChecks.extractValue(bean, field); //주민등록번호 유효성 검사 알고리즘은 RteGenericValidator가 가지고 있다. if(!RteGenericValidator.isValidIdIhNum(ihidnum)){ //유효한 주민등록번호가 아니면 FieldChecks.rejectValue(errors, field, va); //에러 처리 return false; }else{ return true; } } } ==== Validator class 작성 ==== 주민등록번호 유효성체크 로직이 있는 RteGenericValidator 클래스를 작성해 보자. \\ 유효성 체크 기준은 - 값의 길이가 13자리이며, 7번째 자리가 1,2,3,4 중에 하나인가? - 앞 6자리의 값이 유효한 날짜인가? - 주민등록번호 마지막 자리를 이용한 check 로 했다. package egovframework.rte.ptl.mvc.validation; import java.io.Serializable; import org.apache.commons.validator.GenericTypeValidator; public class RteGenericValidator implements Serializable { public static boolean isValidIdIhNum(String value) { //값의 길이가 13자리이며, 7번째 자리가 1,2,3,4 중에 하나인지 check. String regex = "\\d{6}[1234]\\d{6}"; if (!value.matches(regex)) { return false; } //앞 6자리의 값이 유효한 날짜인지 check. try { String strDate = value.substring(0, 6); strDate = ((value.charAt(6) == '1' || value.charAt(6) == '2') ? "19":"20") + strDate; strDate = strDate.substring(0, 4) + "/" + strDate.substring(4, 6) + "/" + strDate.substring(6, 8); SimpleDateFormat dateformat = new SimpleDateFormat("yyyy/MM/dd"); Date date = dateformat.parse(strDate); String resultStr = dateformat.format(date); if (!resultStr.equalsIgnoreCase(strDate)) { return false; } } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); return false; } //주민등록번호 마지막 자리를 이용한 check. char[] charArray = value.toCharArray(); long sum = 0; int[] arrDivide = new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5 }; for (int i = 0; i < charArray.length - 1; i++) { sum += Integer.parseInt(String.valueOf(charArray[i])) * arrDivide[i]; } int checkdigit = (int) ((int) (11 - sum % 11)) % 10; return (checkdigit == Integer.parseInt(String.valueOf(charArray[12]))) ? true : false; } } ==== validator-rules.xml 설정 ==== 이제 주민등록번호 validation rule을 추가해 보자. \\ rule 이름은 ihidnum으로 하고 위에서 작성한 코드를 바탕으로 설정하면, (이미 위 개요에 나온 대로) 아래와 같다. \\ client-validation을 위해서 자바스크립트 코드도 추가했다. \\ 0) { alert(fields.join('\n')); } return bValid; } /** * Reference: JS Guide * http://jsguide.net/ver2/articles/frame.php?artnum=002 */ function checkIhIdNum(ihidnum){ fmt = /^\d{6}[1234]\d{6}$/; if(!fmt.test(ihidnum)){ return false; } birthYear = (ihidnum.charAt(7) <= "2") ? "19" : "20"; birthYear += ihidnum.substr(0, 2); birthMonth = ihidnum.substr(2, 2) - 1; birthDate = ihidnum.substr(4, 2); birth = new Date(birthYear, birthMonth, birthDate); if( birth.getYear() % 100 != ihidnum.substr(0, 2) || birth.getMonth() != birthMonth || birth.getDate() != birthDate) { return false; } var arrDivide = [2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5]; var checkdigit = 0; for(var i=0;i ==== validator.xml 설정 ==== ihidnum이란 필드에 주민등록번호 validation 체크를 해보자. \\ validator.xml에 필요한 내용을 추가하고. \\
... ...
==== 에러메시지 설정 ==== messages 프로퍼티에 에러메시지를 추가하자. errors.ihidnum=유효하지 않은 주민등록번호입니다. ==== TEST ==== 주민등록번호 server-side,client-side validatin을 위한 환경은 다 갖추어졌다. \\ 이제 EmployeeController에 validation을 추가하고,(이미 추가되어 있다면 pass) \\ package com.easycompany.controller.annotation; ... import org.springmodules.validation.commons.DefaultBeanValidator; ... @Controller public class EmployeeController { ... @Autowired private DefaultBeanValidator beanValidator; ... @RequestMapping(value = "/updateEmployee.do", method = RequestMethod.POST) public String updateEmployee(@ModelAttribute("employee") Employee employee, BindingResult bindingResult, Model model) { beanValidator.validate(employee, bindingResult); //validation 수행 if (bindingResult.hasErrors()) { //만일 validation 에러가 있으면... ..... return "modifyemployee"; } employeeManageService.updateEmployee(employee); return "changenotify"; } } VO Class(com.easycompany.model.Employee.java)에 주민등록번호 필드를 추가하고, package com.easycompany.model; public class Employee { .... private String ihidnum; private String ihidnum1; private String ihidnum2; ... public String getIhidnum() { return ihidnum1+ihidnum2; } public String getIhidnum1() { return ihidnum1; } public void setIhidnum1(String ihidnum1) { this.ihidnum1 = ihidnum1; } public String getIhidnum2() { return ihidnum2; } public void setIhidnum2(String ihidnum2) { this.ihidnum2 = ihidnum2; } } JSP(/easycompany/webapp/jsp/modifyemployee.jsp)에 주민등록번호 입력 필드를 추가하자. ... 주민번호 - ... 주민등록번호를 입력하지 않거나, 틀린번호를 입력시엔 아래와 같은 경고창이 뜬다. \\ {{:egovframework:rte:ptl:validation:ihidnum-validation.jpg|}} \\ 틀린 입력값으로 client를 통과하더라도 Controller에서 validation이 추가로 동작하므로, server-side에서 validation error가 일어날것이다. ====== 참고자료 ====== * Spring Modules Reference Documentation v 0.9, Chapter 17.Validation, P133~136