[CreateAccountController.java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | package spring.controller; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import spring.model.Address; import spring.model.MemberInfo; import spring.validator.MemberInfoValidator; @Controller @RequestMapping("/account/create.do") public class CreateAccountController { @ModelAttribute("command") public MemberInfo formBacking(HttpServletRequest request) { // equalsIgnoreCase 메서드는 // 대소문자 관계 없이(ignore case) equals 검사를 해줍니다. // 따라서 "A".equals("a")는 false, "A".equalsIgnoreCase("a")는 true if (request.getMethod().equalsIgnoreCase("GET")) { MemberInfo mi = new MemberInfo(); Address address = new Address(); address.setZipcode(autoDetectZipcode(request.getRemoteAddr())); System.out.println("request.getRemoteAddr : " + autoDetectZipcode(request.getRemoteAddr())); // getRemoteAddr :: 클라이언트의IP를 얻는 메서드 mi.setAddress(address); return mi; // 처음 GET방식때에는 Zipcode를 저장한 address객체를 => MemberInfo(DTO)에 저장 } else { return new MemberInfo(); // Post방식일때에는 새로운 주소값을 가진 DTO객체 생성 } } private String autoDetectZipcode(String remoteAddr) { // return "000-000"; return remoteAddr; //왜 0:0:0:0:0:0:0:0:1로 나오지? //이유 :: ipv6의 주소를 가져와서 0:0:0:0:0:0:0:1로 가져오게된다. //해결법 :: http://leinger.blogspot.com/2012/05/requestgetremoteaddr-ip-00000001.html } @RequestMapping(method = RequestMethod.GET) public String form() { return "account/creationForm"; } // BindingResult 의 경우 ModelAttribute 을 이용해 매개변수를 Bean 에 binding 할 때, // 발생한 오류 정보를 받기 위해 선언해야 하는 애노테이션 /* RequestParam 도 그렇지만, 매개변수 binding 이 실패하면 400 오류가 발생합니다. 이게 500.1 같은 오류가 발생해야 맞을 것 같지만, Spring 입장에선 요청 자체가 잘못된 것이 뭔가 설계가 잘못 되어서 혹은 잘못된 경로를 호출해서 발생한 걸로 판단하기 때문에 400 으로 오류를 발생시키는 것입니다. */ @RequestMapping(method = RequestMethod.POST) public String Submit(@ModelAttribute("command") MemberInfo memberInfo, BindingResult result) { new MemberInfoValidator().validate(memberInfo, result); if (result.hasErrors()) { return "account/creationForm"; } return "account/created"; } } | cs |
BindingResult result
.validate()
.hasErrors() 에 대해선 밑에 따로 설명을 덧붙힌다.
.validate(MemberInfo memberInfo, BindingResult result);
.validate메서드의 수행이 끝난후 돌아와서
Errors.hasErrors()메서드를 이용해 에러가 존재하는 지 확인하고,
에러가 존재할 경우 알맞은 처리를 수행할 수 있다.
if(result.hasErrors()){
//에러처리
}
//에러가 없을때의 처리
- Spring 인터페이스 유효성 검사
- Validator
Validator 인터페이스
:: Validator가 해당 클래스에 대한 값 검증을 지원하는 지의 여부를 리턴
1 2 3 4 | public boolean supports(Class<?> clazz) { return MemberInfo.class.isAssignableFrom(clazz); } //MemberInfo 커맨드 객체에 대한 값 검증을 지원하는 지의 여부를 리턴한다. | cs |
:: target객체에 대한 검증에 대한 true / false 값을 가져오는 메서드이다.
무조건 써줘야하는 메서드라고 생각하면 편하다
검증을 실행하고 바로 밑에있는 validate 메서드를 실행한다.
resources/messages/validation.properties 파일을 가져온
[dispatcher-servlet.xml]
1 2 3 4 5 6 7 8 | <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>messages.validation</value> </list> </property> </bean> | cs |
명시할때에는 .properties 확장자를 명시 안해주었음을 기억하자.
[MemberInfoValidator.java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | package spring.validator; import org.springframework.validation.Errors; import org.springframework.validation.Validator; import spring.model.Address; import spring.model.MemberInfo; //앞에서 new 로 객체화하기때문에 implements를 안적어도 가능하지만, //어노테이션으로 가져올때에는 구현한 객체만 가져오기때문에 implements로 선언해주어야한다 public class MemberInfoValidator implements Validator { // MemberInfo 커맨드 객체에 대한 값 검증을 지원하는 지의 여부를 리턴한다. public boolean supports(Class<?> clazz) { return MemberInfo.class.isAssignableFrom(clazz); } // properties파일이 어떻게 여기 String으로 가져오는지 에 대한 설명 :: // BindingResult 에는 모델의 바인딩 작업 중에 발생한 타입 변환 오류정보와 // 검증 작업에서 발생한 검증 오류 정보가 모두 저장된다. // 이 오류 정보는 보통 컨트롤러에 의해 폼을 다시 띄울 때 활용된다. // 폼을 출력할 때 BindingResult 에 담긴 오류 정보를 활용해서 // 에러 메시지를 생성할 수 있다. // 스프링은 기본적으로 messages.properties 와 같은 // 프로퍼티 파일에 담긴 메시지를 가져와 에러 메시지로 활용한다. // 여기선 BindingResult를 errors로 사용하였다. public void validate(Object target, Errors errors) { MemberInfo memberInfo = (MemberInfo) target; //.trim().isEmpty() //==> "____" 가져온 값의 앞뒤로 공백을 지우고, 가져온값이 공백이냐 체크할수있음 if (memberInfo.getId() == null || memberInfo.getId().trim().isEmpty()) { errors.rejectValue("id", "required.loginCommand.userId"); // void rejectValue(String field, String errorCode) // 메서드 오버로딩. // String errorCode부분을 프로퍼티스파일에서 key값으로 꺼낼 수 있음 } if (memberInfo.getName() == null || memberInfo.getName().trim().isEmpty()) { errors.rejectValue("name", "required.name"); } Address address = memberInfo.getAddress(); if (address == null) { errors.rejectValue("address", "required"); } if (address != null) { errors.pushNestedPath("address"); //address.zipcode , address.address1으로 들어가야할 작업을 //pushNestedPath가 대신 해주고있기때문에, 안으로 들어가서 바로 //필드명으로 호출할 수 있게 된다. try { if (address.getZipcode() == null || address.getZipcode().trim().isEmpty()) { errors.rejectValue("zipcode", "required"); } if (address.getAddress1() == null || address.getAddress1().trim().isEmpty()) { errors.rejectValue("address1", "required"); } } finally { errors.popNestedPath(); //이전 url을 다시 띄워준다. } } } } | cs |
void validate(Object target,Errors errors)
이것도 무조건 써줘야하는 메서드라고 생각하면 편하다
위의 true / false 값을 가져와서, 검증 결과 문제가 있을 경우 errors객체에 어떤 문제인지 에 대한 정보를 저장한다
- Errors(최상위 에러 객체)
를 상속 받고있는 - BindResult
1. 전체 객체에 대한 글로벌 에러코드 추가 :: reject(String errorCode);
만약 errorCode가 없을때에는 properties에 일치하는 key가 없다고 에러페이지가뜨는데,
없을때를 대비해서 defaultMessage를 지정할 수 있다.
==> reject(String errorCode, String defaultMessage);
2. 필드에 대한 에러코드 추가 :: rejectValue(String field, String errorCode);
위와 마찬가지로 일치하는 에러코드가 없을때 defaultMessage를 보여줄 수 있다.
==> rejectValue(String field, String errorCode, String defaultMessage);
'JAVA > Spring' 카테고리의 다른 글
String MVC - 뷰(ViewResolver) 원칙 (0) | 2018.09.19 |
---|---|
Spring MVC - ajax + responseBody (0) | 2018.09.17 |
Spring - RESTful 예제 (2) | 2018.09.13 |
@ModelAttribute 추가 공부내용. (0) | 2018.09.12 |
Spring - @ModelAttribute + @Controller (0) | 2018.09.12 |