|
@Validated와 @Pattern regex체크로 받은 BindingResult 에러메세지 확인OK (에러발생된 vo filed만 BindingResult가 갖고 오는 것 확인 OK)
세번째 도전 : 그냥 Vo 멤버필드마다 에러스타일VO를 각각 설정하면 분명 잘된다. 근데 난 왜자꾸 map을 해결하고싶은걸까... 아...
두번째 도전 : Map에 Map을 넣어서 에러스타일 찍어보려고 했는데, map.get(인덱스)로 받을 수는 있지만 왜 타입에러가 나는걸까.ㅜㅜ 제너럴타입캐스팅했는데ㅜㅜ 아... 아시는분 알려주세요ㅜㅜ 아...
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 | @Controller @RequestMapping("/customComp") public class CustomCompController { private static final Logger logger = LoggerFactory.getLogger(CustomCompController.class); //회원가입 @RequestMapping(value="/customCompEntry", method=RequestMethod.POST) public String customCompEntryPost(HttpServletRequest request, MultipartFile fName, @Validated CustomCompEntryUpdateFormVO customCompVo, BindingResult bindRes, Model model) { logger.info("[" + new Object(){}.getClass().getEnclosingMethod().getName() + "]"); //현재 실행중인 메소드명 if (bindRes.hasErrors()) { if (bindRes.hasErrors()) { List<FieldError> fieldErrors = bindRes.getFieldErrors();//발생된 에러 Map<String, Map> errMsgMaps = new HashMap<>(); Map<String, String> errMsgMap = new HashMap<>(); initErrMsgList(errMsgMaps);//에러메세지 빈값 초기화 setErrMsgList(errMsgMaps, fieldErrors);//발생된 에러메세지 재설정 model.addAttribute("errMsgMap", errMsgMap); model.addAttribute("compEntryVo", customCompVo); return "custom/comp/customCompEntry"; } } //VO에 있는 멤버필드수만큼 ErrMsgList에 ErrMsgMap을 빈값으로 초기화 private void initErrMsgList(Map<String, Map> errMsgMaps) { Map<String, String> errMsgMap = null; //key1은 Field, key2는 MessageText, key3은 FieldClass, key4는 InvalidClass로 구성되는 Map 생성 CustomCompEntryUpdateFormVO vo = new CustomCompEntryUpdateFormVO(); Field[] fields = vo.getClass().getDeclaredFields(); for (Field field : fields) { errMsgMap = new HashMap<>(); errMsgMap.put("Field", field.getName()); //Field라는 key1의 value는 멤버필드명으로 설정 errMsgMap.put("MessageText", ""); //Message라는 key2의 value는 빈값으로 초기화 errMsgMap.put("FieldClass", "is-valid"); //FieldClass라는 key3의 value는 HTML Element의 Class값을 유효값스타일 is-valid로 설정(w3c에서 제공하는 bootstrap의 css) errMsgMap.put("InvalidClass", "is-valid"); //InvalidClass라는 key4의 value는 HTML Element의 Class값을 유효값스타일 is-valid로 설정(w3c에서 제공하는 bootstrap의 css) errMsgMaps.put(field.getName(), errMsgMap); //FieldName key의 value에 Map을 설정 } } //initErrMsgList()에서 초기화된 ErrMsgMap의 Filed key에 해당하는 Message key의 value를 실제로 발생된 Error Message 값으로 재설정 private void setErrMsgList(Map<String, Map> msgMaps, List<FieldError> fieldErrors) { logger.info("[" + new Object(){}.getClass().getEnclosingMethod().getName() + "]"); //현재 실행중인 메소드명 int msgMapsSize=msgMaps.size(), fieldErrorsListSize=fieldErrors.size(); Map<String, String> errMsgMap = null; FieldError fe = null; for (int j=0; j<msgMapsSize; j++) { errMsgMap = (Map<String,String>)msgMaps.get(j); //###### HELP ################<-- 이거 타입에러나는데 아시는분 알려주세요ㅜㅜ for (int i=0; i<fieldErrorsListSize; i++) { fe = fieldErrors.get(i); if ((errMsgMap.get("Field")).equals(fe.getField())) { //멤버필드명 비교 errMsgMap.put("MessageText", fe.getDefaultMessage()); //ErrMsgMap의 Filed key에 해당하는 MessageText key의 value를 실제로 발생된 Error Message 값으로 재설정 errMsgMap.put("FieldClass", "is-invalid"); //ErrMsgMap의 Filed key에 해당하는 FieldClass key의 value를 실제로 발생된 Error Message 값으로 재설정 errMsgMap.put("InvalidClass", "is-invalid"); //ErrMsgMap의 Filed key에 해당하는 InvalidClass key의 value를 실제로 발생된 Error Message 값으로 재설정 // System.out.println("field : " + fe.getField()); // System.out.println("Message : " + fe.getDefaultMessage()); } } } System.out.println(" FieldErrors : " + fieldErrorsListSize); } } | cs |
첫번째 도전 : list에 map넣어서 에러스타일 찍어보려고 했는데, 생각해보니 아닌것 같다.ㅜㅜ
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 | @Controller @RequestMapping("/customComp") public class CustomCompController { private static final Logger logger = LoggerFactory.getLogger(CustomCompController.class); //회원가입 @RequestMapping(value="/customCompEntry", method=RequestMethod.POST) public String customCompEntryPost(HttpServletRequest request, MultipartFile fName, @Validated CustomCompEntryUpdateFormVO customCompVo, BindingResult bindRes, Model model) { logger.info("[" + new Object(){}.getClass().getEnclosingMethod().getName() + "]"); //현재 실행중인 메소드명 if (bindRes.hasErrors()) { if (bindRes.hasErrors()) { List<FieldError> fieldErrors = bindRes.getFieldErrors();//발생된 에러 List<Map<String, String>> errMsgList = new ArrayList<>(); Map<String, String> errMsgMap = new HashMap<>(); initErrMsgList(errMsgList);//에러메세지 빈값 초기화 setErrMsgList(errMsgList, fieldErrors);//발생된 에러메세지 재설정 model.addAttribute("errMsgMap", errMsgMap); model.addAttribute("compEntryVo", customCompVo); return "custom/comp/customCompEntry"; } } //VO에 있는 멤버필드수만큼 ErrMsgList에 ErrMsgMap을 빈값으로 초기화 private void initErrMsgList(List<Map<String, String>> errMsgList) { logger.info("[" + new Object(){}.getClass().getEnclosingMethod().getName() + "]"); //현재 실행중인 메소드명 errMsgList = new ArrayList<>(); Map<String, String> errMsgMap = null; //key1은 Field, key2는 MessageText, key3은 FieldClass, key4는 InvalidClass로 구성되는 Map 생성 CustomCompEntryUpdateFormVO vo = new CustomCompEntryUpdateFormVO(); Field[] fields = vo.getClass().getDeclaredFields(); for (Field field : fields) { errMsgMap = new HashMap<>(); errMsgMap.put("Field", field.getName()); //Field라는 key1의 value는 멤버필드명으로 설정 errMsgMap.put("MessageText", ""); //Message라는 key2의 value는 빈값으로 초기화 errMsgMap.put("FieldClass", "is-valid"); //FieldClass라는 key3의 value는 HTML Element의 Class값을 유효값스타일 is-valid로 설정(w3c에서 제공하는 bootstrap의 css) errMsgMap.put("InvalidClass", "is-valid"); //InvalidClass라는 key4의 value는 HTML Element의 Class값을 유효값스타일 is-valid로 설정(w3c에서 제공하는 bootstrap의 css) errMsgList.add(errMsgMap); //key1이라는 Field에만 value를 입력한 Map을 list에 추가 } } //initErrMsgList()에서 초기화된 ErrMsgMap의 Filed key에 해당하는 Message key의 value를 실제로 발생된 Error Message 값으로 재설정 private void setErrMsgList(List<Map<String, String>> errMsgList, List<FieldError> fieldErrors) { logger.info("[" + new Object(){}.getClass().getEnclosingMethod().getName() + "]"); //현재 실행중인 메소드명 int errListSize=errMsgList.size(), fieldErrorsListSize=fieldErrors.size(); Map<String, String> errMsgMap = null; FieldError fe = null; for (int j=0; j<errListSize; j++) { errMsgMap = errMsgList.get(j); for (int i=0; i<fieldErrorsListSize; i++) { fe = fieldErrors.get(i); if (errMsgMap.get("Field").equals(fe.getField())) { //멤버필드명 비교 errMsgMap.put("MessageText", fe.getDefaultMessage()); //ErrMsgMap의 Filed key에 해당하는 MessageText key의 value를 실제로 발생된 Error Message 값으로 재설정 errMsgMap.put("FieldClass", "is-invalid"); //ErrMsgMap의 Filed key에 해당하는 FieldClass key의 value를 실제로 발생된 Error Message 값으로 재설정 errMsgMap.put("InvalidClass", "is-invalid"); //ErrMsgMap의 Filed key에 해당하는 InvalidClass key의 value를 실제로 발생된 Error Message 값으로 재설정 errMsgList.add(errMsgMap); // System.out.println("field : " + fe.getField()); // System.out.println("Message : " + fe.getDefaultMessage()); } } } System.out.println(" FieldErrors : " + fieldErrorsListSize); } } | cs |
향상된 for문은 debug모드에서 10,000번 돌리니깐 메모리오버플로우 에러떨어진다 ㅜㅜ List같이 뚱뚱한 객체변수는 특히 조심하자
그냥 for문 돌리자
그리고 로컬변수를 로컬메소드에서 초기화하거나 값을 설정할 때 return void 메소드파라미터로 값을 설정해서 재사용가능한데, 객체는 null 타입이면 설정이 안되고 반드시 new로 생성된 빈객체를 넘겨줘야한다.
그럴필요없는 생성유무가 매번 바뀌는 경우는 그냥 로컬객체를 메소드파라미터로 넘겨서 재설정 후 객체를 return 받도록 하면 메모리 낭비를 줄일수 있다
@Pattern regex에러체크시 필수체크회피하려면 ()|을 붙이라고 한다. 예) regex="( 표현식 )|";
javascript regex는 문자가 아닌 const 변수값에 슬래시로 시작하는 regex표현식을 사용하지만, 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 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | package com.spring.javagreenS_khv.vo; import javax.validation.constraints.Email; import javax.validation.constraints.Pattern; import org.hibernate.validator.constraints.Length; import lombok.Data; public @Data class CustomCompEntryUpdateFormVO { /** * 기업고객회원정보(customComp) */ private int seq; private int customId; @Pattern(regexp="[가-힣a-zA-Z()]{3,10}([0-9]*)" , message="한글 또는 영문 3자리 이상으로 필요하면 숫자, 중괄호 조합 3~20자리로 입력하세요") private String customName; //기업명체크(한글or영문에 필요하면 숫자포함 조합 3~20자리) @Pattern(regexp="[가-힣a-zA-Z()]{3,10}([0-9]*)" , message="한글 또는 영문 3자리 이상으로 필요하면 숫자, 중괄호 조합 3~20자리로 입력하세요") private String customNameShort; //기업명(단축명칭)체크(한글or영문에 필요하면 숫자포함 조합 3~20자리) private int customKindGroupCode; private String kindGroupName; private String customKindCode; private String customKindName; private char customGrade; private String gradeName; private String estblDate; @Pattern(regexp="[0-9]{3}-[0-9]{2}-[0-9]{5}" , message="숫자-숫자-숫자로 입력하세요") private String companyNo; //사업자등록번호체크(숫자3자리-숫자2자리-숫자5자리) @Pattern(regexp="[기타:]{0,3}[가-힣a-zA-Z0-9]{0,100}" , message="한글 또는 영문 또는 숫자 2~100자리로 입력하세요") private String txtOffice; //사무실명체크(한글 또는 영문 또는 숫자 1~100자리) private String office; private String tel1; @Pattern(regexp="\\d{3,4}" , message="숫자 3자리~4자리로 입력하세요") private String tel2; //전화번호2체크(숫자 3~4자리) @Pattern(regexp="\\d{4}" , message="숫자 4자리로 입력하세요") private String tel3; //전화번호3체크(숫자 4자리) private String telNo; private String hp1; @Pattern(regexp="(\\d{4})|" , message="숫자 4자리로 입력하세요") private String hp2; //휴대폰번호2체크(숫자 4자리) @Pattern(regexp="(\\d{4})|" , message="숫자 4자리로 입력하세요") private String hp3; //휴대폰번호3체크(숫자 4자리) private String hpNo; @Pattern(regexp="^[a-zA-Z]{2}[0-9_+-.]*[a-zA-Z]([a-zA-Z0-9_+-.]*)$" , message="영문자 3자리 이상으로 필요하면 특수기호(_+-.), 숫자, 영문 조합 3~25자리로 입력하세요") private String email1; //이메일체크(영문자으로 시작하여 특수기호 _+-. 또는 숫자 또는 문자 조합 3~25자리) private String email2; //@Pattern(regexp="[a-zA-Z][a-zA-Z0-9_+-]*[.][a-zA-Z0-9]([_+-.][a-zA-Z]|[a-zA-Z])" , message="도메인명은 영문자와 특수기호(_+-.), 숫자, 영문 조합 3~25자리까지 입력가능합니다") private String txtEmail2; //도메인체크(domain deep 2이상, 영문자와 특수기호 _+-. 또는 숫자 또는 문자 조합 3~25자리) @Email(message="이메일 형식을 맞춰주세요") @Length(min=8, max=50, message="이메일은 8~50자리로 입력하세요") private String email; private String postcode; private String validatingPostcode; private String roadAddress; private String extraAddress; @Pattern(regexp="[a-zA-Z0-9가-힣#-. ]{1,50}" , message="한글 또는 영문에 필요하면 숫자, 특수문자( .-#) 포함하여 1~50자리로 입력하세요") private String detailAddress;//상세주소체크(한글or영문에 필요하면 숫자 또는 특수문자( .-#) 1~50자리) @Pattern(regexp="[a-zA-Z0-9가-힣]([@#$%^&!?]|[~()<>_*+-=]|[,.:;\\/]|[ ]*)" , message="문자, 숫자, 특수문자(~!?@#$%^&*()<>_+=-,.:;/ )의 조합 500자 이하로 입력하세요") private String memo;//메모 체크(숫자,문자,특수문자체크(~!?@#$%^&*()<>_+=-,.:;/ ) 조합 500자리) @Pattern(regexp="[a-zA-Z0-9가-힣_-~()+][.](JPG|JPEG|GIF|jpg|jpeg|gif)$" , message="문자,숫자,특수문자(_-~()+) 50자리의 화일명과 .jpg 또는 .jpeg 또는 .gif확장자만 가능합니다") private String customImgFileName; //화일명 체크(문자,숫자,특수문자(~()<>_*+-) 50자리의 화일명과 .JPG 또는 .JPEG 또는 .GIF확장자만 가능합니다) private String photo; private int overDaysUserDel; //회원탈퇴신청 후 30일 경과시 회원삭제처리 private String createDate; private String createUser; private String updateDate; private String updateUser; private String deleteDate; private String deleteUser; /** * 기업고객회원로그인정보(customCompLogin) */ @Pattern(regexp = "^[a-zA-Z]+[0-9_+-.]*[a-zA-Z_+-.]*[0-9]([a-zA-Z0-9_+-.]*)$" , message="영문자로 시작하여 숫자1자리 이상 포함하는 영문,숫자,특수기호(_+-.)의 조합 2~20자리로 입력하세요") private String loginId;//아이디체크(영문자1자리이상, 숫자나 특수기호 조합 2~20자리) private String loginPwd; private String encryptPwd; private int point; private int visitCnt; private int todayCnt; private String createDate2; private String createUser2; private String updateDate2; private String updateUser2; private String deleteDate2; private String deleteUser2; /* hibernate validator 체크 @Digits(Integer=, fraction=) : @숫자(정수, 소수이하자릿수) @Past() : 과거 날짜?, @Future : 미래 날짜? @Size() : 요청값 길이 체크 @Range() : 요청값 범위 체크 @Email(message="이메일 형식을 맞춰주세요") @NotNull(message="아이디를 입력하세요?") @Length(min=4, max=20, message="아이디는 4자 ~ 20글자로 입력하세요") @Pattern(regexp = "", message="입력규칙위반") @Range(min=20, max=99, message="나이는 20~99세까지 가입 가능합니다") private String mid; */ } | cs |
에러스타일CSS 적용은 작성중
가입체크 후 받았던 FormVO를 model에 다시 추가해서 가입화면으로 돌아가서 입력받았던FormVO값을 재설정할 때,
selected값을 설정시 jstl <c:if></c:if>로 vo값을 찍어야 값이 설정된다.
이전에 ${ vo.a == 1 ? selected : '' } 만으로는 값이 재설정안된다.