Search

33. 스프링부트 포토그램 인증 회원정보수정 유효성 검사하기

포토그램 인증 구현하기

회원정보 수정 구현

name, password는 필수값이기 때문에 프론트단에서 값 체크와 유효성검사를 통해서
서버로 넘겨준다. 근데 1번유저를 수정할려는데 영속화 시킬려니까 1번유저가 없는경우도 있을거다.
데이터베이스에서 처리 할 수 있는 부분을 뒷단에서 처리해주고 나머지는 앞단에서 처리 해주면 된다.
update.jsp 에 이름과 패스워드 부분에 required="required"를 추가.
<input type="text" name="name" placeholder="이름" value="${principal.user.name }" required="required"/> <input type="password" name="password" placeholder="패스워드" required="required" />
HTML
복사
필수값인 이름하고 패스워드를 빈값으로 제출해도 화면이 넘어가고 있다
그 이유는 버튼이 submit이 아니라 일반 button이라 그렇다
그래서 required="required" 이런 유효성 검사가 먹질 않는다.
제출버튼 쪽인
<form id="profileUpdate" onsubmit="update(${principal.user.id })">
HTML
복사
이 부분을
<button >제출</button>
HTML
복사
이렇게 수정하고 프로필 수정 관련 form 부분을
<form id="profileUpdate" onsubmit="update(${prinicipal.user.id})">
HTML
복사
이렇게 변경해주고 다시 제출할려고 하면은
이렇게 막아준다
form 태그는 어디론가 이동을 해야하는데 현재 action으로 잡아준게 없다.
안 잡혀있으면 디폴트로 자기 자신한테 돌아온다.
우리는 update 함수가 실행 되야하니까 event를 추가해준다.
<form id="profileUpdate" onsubmit="update(${principal.user.id }, event)">
HTML
복사
update.js에서 event 를 받아주고 preventDefault 추가
function update(userId,event) { event.preventDefault(); //폼 태그 액션을 막는다.
HTML
복사
변경해주고 진행하면
이 화면으로 넘어온다!
앞단의 프론트단은 이제 됐고 유효성 검사를 해야한다.
UserUpdateDto.java에서 필수값 선언부분에 @NotBlank 추가
@NotBlank private String name; //필수 @NotBlank private String password; //필수
Java
복사
UserApiController.java에서 @Valid추가해주면서 userUpdateDto를 검증해서 문제가 생기면 bindingResult에 담아줄거다.
@PutMapping("/api/user/{id}") public CMRespDto<?> update(@PathVariable int id, @Valid UserUpdateDto userUpdateDto, BindingResult bindingResult, //꼭 @Valid가 적혀있는 다음 파라매터 적어야됨. @AuthenticationPrincipal PrincipalDetails principalDetails) { System.out.println("userUpdateDto::"+userUpdateDto); User userEntity = userService.회원수정(id , userUpdateDto.toEntity()); principalDetails.setUser(userEntity); //세션 정보 변경 return new CMRespDto<>(1, "회원수정완료", userEntity); };
Java
복사
AuthController.java에서 signup함수에 에러가 발생했을때 넣어줬던 코드를 가져와서 넣어준다.
//에러가 존재한다 if(bindingResult.hasErrors()) { Map<String, String> errorMap = new HashMap<>(); for(FieldError error :bindingResult.getFieldErrors()) { errorMap.put(error.getField(), error.getDefaultMessage()); System.out.println("=============================="); System.out.println(error.getDefaultMessage()); System.out.println("=============================="); } throw new CustomValidationException("유효성 검사 실패함", errorMap); }
Java
복사
ex 폴더 안에 CustomValidationApiException.java 생성
package com.cos.photogramstart.handler.ex; import java.util.Map; public class CustomValidationApiException extends RuntimeException { //객체를 구분할 때 !! (jvm에게 중요) private static final long serialVersionUID = 1L; private Map<String, String> errorMap; public CustomValidationApiException(String message, Map<String, String> errorMap) { super(message); this.errorMap = errorMap; } public Map<String, String> getErrorMap(){ return errorMap; } }
Java
복사
ControllerExceptionHandler.java
@ExceptionHandler(CustomValidationApiException.class) public CMRespDto<?> validationApiException(CustomValidationApiException e) { return new CMRespDto<>(-1,e.getMessage(),e.getErrorMap()); }
Java
복사
오브젝트가 리턴되는 함수 하나를 추가해준다. 기존에는 스크립트 형태로 리턴이였다면 지금은 오브젝트용.
아까 UserApiController에 추가해줬던 에러존재 if문 안에 throw부분을 고쳐줘야한다.
//에러가 존재한다 if(bindingResult.hasErrors()) { Map<String, String> errorMap = new HashMap<>(); for(FieldError error :bindingResult.getFieldErrors()) { errorMap.put(error.getField(), error.getDefaultMessage()); System.out.println("=============================="); System.out.println(error.getDefaultMessage()); System.out.println("=============================="); } throw new CustomValidationApiException("유효성 검사 실패함", errorMap); }
Java
복사
else에도 기존의 실행되는 코드를 옮겨주면
@PutMapping("/api/user/{id}") public CMRespDto<?> update(@PathVariable int id, @Valid UserUpdateDto userUpdateDto, BindingResult bindingResult, //꼭 @Valid가 적혀있는 다음 파라매터 적어야됨. @AuthenticationPrincipal PrincipalDetails principalDetails) { //에러가 존재한다 if(bindingResult.hasErrors()) { Map<String, String> errorMap = new HashMap<>(); for(FieldError error :bindingResult.getFieldErrors()) { errorMap.put(error.getField(), error.getDefaultMessage()); System.out.println("=============================="); System.out.println(error.getDefaultMessage()); System.out.println("=============================="); } throw new CustomValidationApiException("유효성 검사 실패함", errorMap); }else { System.out.println("userUpdateDto::"+userUpdateDto); User userEntity = userService.회원수정(id , userUpdateDto.toEntity()); principalDetails.setUser(userEntity); //세션 정보 변경 return new CMRespDto<>(1, "회원수정완료", userEntity); } };
Java
복사
update.js에서 성공 실패 부분의 콘솔 로그를 찍어보게 res와 error를 추가해준다. 테스트때문에 location.href 주석처리.
$.ajax({ type: "put", url : `/api/user/${userId}`, data: data, contentType: "application/x-www-form-urlencoded; charset=utf-8", dataType: "json", }).done(res=>{ console.log("update 성공" , res) //location.href=`/user/${userId}`; }).fail(error=>{ console.log("update 실패", error) });
Java
복사
수정해서 제출하면 오른쪽에 성공한 로그를 볼 수 있다
실패부분을 볼려면 잠깐 update.jsp 부분에서
이름부분에 required부분을 지워주자. (테스트 후에는 다시 넣어줘야한다)
필수값인 이름을 빼고 제출하면 실패가 떨어져야하는데 성공이 떨어지고 안의 데이터에서만 실패를 구분하는 코드가 담아져서 왔다.
ajax에서
}).done(res=>{ //HttpStatus 상태가 200번대 console.log("update 성공" , res) }).fail(error=>{ //HttpStatus 상태가 200번대가 아닐 때 console.log("update 실패", error) });
Java
복사
HttpStatus의 상태 코드가 200번이냐 아니냐에 따라 구분하기 때문이다
ControllerExceptionHandler.java에 아까 추가해준 validationApiException 함수에서 리턴되는 타입을 바꿔주면 되는데
@ExceptionHandler(CustomValidationApiException.class) public ResponseEntity<CMRespDto<?>> validationApiException(CustomValidationApiException e) { return new ResponseEntity<>(new CMRespDto<>(-1,e.getMessage(),e.getErrorMap()), HttpStatus.BAD_REQUEST); }
Java
복사
다시 실행 해보면은
이름빼고 진행했을시 실패로그로 찍힌다
update.js의 실패부분에 알럿을 추가해줘서
}).fail(error=>{ //HttpStatus 상태가 200번대가 아닐 때 console.log("update 실패", error.responseJSON.data) alert(error.responseJSON.data); });
Java
복사
error.responseJSON.data 까지만 하면은
이렇게 나오고
error.responseJSON.data.name 까지 쳐줘야지
잘 나온다
근데 이렇게 하는것보단
}).fail(error=>{ //HttpStatus 상태가 200번대가 아닐 때 console.log("update 실패", error.responseJSON.data) alert(JSON.stringify(error.responseJSON.data)); });
Java
복사
JSON.stringify을 이용해서 오브젝트를 JSON으로 변환해주면 된다.

*참고