바로 직전 https://wedul.tistory.com/562?category=595982 에서 Custom validation을 만들어서 입력된 값에 validation을 체크하는 방법을 알아봤다.
그럼 이 validation체크를 통해서 front에 상황에 맞는 에러를 보내줄 수 있도록 조치를 취해보자.
우선 @valid 처리를 했었던 컨트롤러에서 에러 메시지를 수집해야한다.
1. Controller
Spring에서 Validation 작업을 진행할 시 validation에 문제가 발생하면 에러 내용을 묶어서 BindingResult로 처리할 수 있도록 제공해준다. 이를 사용하기 위해서 parameter로 BindingResult값을 추가해준다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /** * 회원가입 * * @param reqDto * @return * @throws Exception */ @RequestMapping("/join") public ResponseEntity<?> join(@Valid UserDto reqDto, BindingResult bindingResult) throws Exception { // check constraint rules this.checkConstraintRule(bindingResult); return ResponseEntity.ok(userService.insertUser(reqDto)); } | cs |
2. 에러 처리
BindingResult에 validation을 체크하고 발생한 에러들에 대한 내용을 하나씩 뽑아서 국제화 메시지로 변경해주고 \n으로 데이터를 묶어서 view에 전달할 수 있도록 데이터를 바꿔 준다. 공통적으로 사용하것이기 때문에 공통 Controller 클래스를 하나 만들어서 사용한다.
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 | package com.wedul.common.controller; import com.wedul.common.error.BadRequestException; import com.wedul.common.util.MessageBundleUtil; import lombok.AllArgsConstructor; import org.apache.commons.lang.StringUtils; import org.springframework.validation.BindingResult; import java.util.stream.Collectors; /** * wedulpos * * @author wedul * @since 2018-12-24 **/ @AllArgsConstructor public class BaseController { private final MessageBundleUtil messageBundleUtil; protected void checkConstraintRule(BindingResult bindingResult) throws BadRequestException { String msg = null; if (bindingResult.hasErrors()) { msg = bindingResult.getFieldErrors() .stream() .map(error -> messageBundleUtil.getMessage(error.getDefaultMessage())) .collect(Collectors.joining("\n")); } if(StringUtils.isNotBlank(msg)) { throw new BadRequestException(msg); } return; } } | cs |
3. 에러 핸들링
나는 에러를 에러 코드와 메시지로 전달해주는 방식을 좋아한다. 사실 다른 정보를 다 전달해줘봐야 프론트에서 처리하기도 어렵고 나머지는 로그로써 확인하는게 더 편하다. 그래서 전달하는 값을 정제하기 위해서 @ControllerAdvice를 통해 출력되는 에러를 재정의 한다.
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 | package com.wedul.common.config; import com.wedul.common.enums.EnumErrorType; import com.wedul.common.error.BadRequestException; import com.wedul.common.error.ForbiddenException; import com.wedul.common.error.NotFoundException; import com.wedul.common.error.InternalServerException; import lombok.Builder; import lombok.Data; import org.apache.commons.lang.StringUtils; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; /** * 에러 유형을 나타내는 Config * * @author wedul * @Date 2017. 07. 09 */ @ControllerAdvice public class ExceptionConfig { @Data @Builder private static class ErrorResponse { private int errCode; private String msg; } @ExceptionHandler({Exception.class}) @ResponseBody public ErrorResponse errorHandler(Exception ex) { if(ex instanceof BadRequestException) { return this.getError(400, ex); } else if(ex instanceof ForbiddenException) { return this.getError(403, ex); } else if(ex instanceof NotFoundException) { return this.getError(404, ex); } else if(ex instanceof InternalServerException) { return this.getError(500, ex); } else { return ErrorResponse.builder().errCode(500).msg(ex.getMessage()).build(); } } /** * 기본 에러 내용 출력 * * @param errorCode * @param ex * @return */ private ErrorResponse getError(int errorCode, Exception ex) { String message = ex.getMessage(); if(StringUtils.isBlank(message)) { message = EnumErrorType.getErrorMsg(errorCode); } return ErrorResponse.builder().errCode(errorCode).msg(message).build(); } /** * Error code 만들기 * * @return String * @date 2017. 7. 9. * @author wedul */ private String makeErrorCode(Exception ex) { StackTraceElement[] ste = ex.getStackTrace(); StringBuffer sb = new StringBuffer(); StackTraceElement[] arrayOfStackTraceElement1; int j = (arrayOfStackTraceElement1 = ste).length; for (int i = 0; i < j; i++) { StackTraceElement el = arrayOfStackTraceElement1[i]; String className = el.getClassName(); if (className.startsWith("com.wedul.wedulpos")) { sb.append(className.substring(className.lastIndexOf(".") + 1).toUpperCase()).append("["); sb.append(el.getLineNumber()).append("]"); break; } } if (StringUtils.isBlank(sb.toString())) { return ex.getStackTrace()[0].getClassName(); } return sb.toString(); } } | cs |
4. 테스트 진행
1) @NotBlank, @Email 확인
2) Custom Validation인 password check
소스코드 : https://github.com/weduls/wedulpos_boot
참고 : https://meetup.toast.com/posts/147
'web > Spring' 카테고리의 다른 글
kafka docker에 간단 설치 후 Spring boot 연동 테스트 (0) | 2019.01.25 |
---|---|
Spring Reactive Web Application (0) | 2019.01.12 |
Custom Validation 만들어서 추가하기 (0) | 2018.12.24 |
inteliij 사용 시 related gradle configuration 설정을 찾지 못할 경우 해결방법 (2) | 2018.12.19 |
[공유] spring에서 생성자 의존성 주입 (0) | 2018.11.19 |