ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [๊ตฌํ˜„] Spring์—์„œ ์—๋Ÿฌ๋ฅผ ๋‚ด๋Š” 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•
    SPRING/PROJECT 2023. 4. 2. 21:48

    ์—๋Ÿฌ๋ฅผ.. ๋‚ด๋ด…์‹œ๋‹ค

    ํ”„๋กœ์ ํŠธ์—์„œ ์—๋Ÿฌ๋ฅผ ๋‚ผ ๋•Œ ๋‚ด๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ด ์„ธ ๊ฐ€์ง€์ด๋‹ค.

    1. ResponseEntity ์‚ฌ์šฉ
    2. Custom ์˜ˆ์™ธ ํด๋ž˜์Šค ๋งŒ๋“ค๊ธฐ
    3. ControllerAdvice ์‚ฌ์šฉํ•˜๊ธฐ

    ๊ฐœ์ธ์ ์œผ๋กœ ์•„์ฃผ ๊ฐ„๋‹จํ•œ ํ”„๋กœ์ ํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด 3๋ฒˆ์„ ์ถ”์ฒœํ•œ๋‹ค.

    ํ•˜๋‚˜์”ฉ ๋ด๋ณด์ž๋ฉด,

     

    1. ResponseEntity ์‚ฌ์šฉ

    ์„ค๋ช…ํ•  ๊ฒŒ ์—†์„ ์ •๋„๋กœ ๋งค์šฐ ๊ฐ„๋‹จํ•œ ๊ฒƒ์ด ์žฅ์ ์ด๋‹ค.

    ๋‹จ์ ์€ ์ฝ”๋“œ๊ฐ€ ์ง€์ €๋ถ„ํ•ด์ง„๋‹ค๋Š” ์ ์ด๋‹ค.

    new ResponseEntity<>({๋ณด๋‚ผ ๋ฐ์ดํ„ฐ}, HttpStatus.{status});

    ์ด ํ•œ ์ค„๋งŒ ๋ฆฌํ„ดํ•˜๋ฉด ๋œ๋‹ค.

    ํ•˜์ง€๋งŒ ์˜ˆ์™ธ์ฒ˜๋ฆฌํ•  ๊ฒŒ ์—ฌ๋Ÿฌ๊ฐœ๊ฐ€ ๋˜๋ฉด ๋„ˆ๋ฌด ๋ณต์žกํ•ด์ง„๋‹ค.

        @PostMapping("/users/login")
        public ResponseEntity<HashMap> socialLogin(@RequestBody UserDto.LoginDto loginDto) {
    
            HashMap<String, Object> responseMap = new HashMap<>();
            User user = userService.signIn(loginDto.getSocialType(), loginDto.getSocialToken());
    
            if (loginDto.getSocialType().equals("kakao")) {
                if (user == null) {
                    responseMap.put("status", 404);
                    responseMap.put("message", "ํšŒ์› ์ •๋ณด ์—†์Œ");
                    return new ResponseEntity<>(responseMap, HttpStatus.NOT_FOUND);
                }
    
                responseMap.put("status", 200);
                responseMap.put("message", "๋กœ๊ทธ์ธ ์„ฑ๊ณต");
                responseMap.put("data", new HashMap<String, String>() {{
                    put("token", jwtTokenProvider.createToken(user.getSocialId(), user.getRoles()));
                }});
                return new ResponseEntity<>(responseMap, HttpStatus.OK);
            } else {
                responseMap.put("status", 401);
                responseMap.put("message", "์†Œ์…œ ํƒ€์ž… ์˜ค๋ฅ˜");
                return new ResponseEntity<>(responseMap, HttpStatus.NOT_FOUND);
            }
            responseMap.put("status", 404);
            responseMap.put("message", "ํšŒ์› ์ •๋ณด ์—†์Œ");
            return new ResponseEntity<>(responseMap, HttpStatus.NOT_FOUND);
        }

    ์œ„ ๊ฒฝ์šฐ ์‘๋‹ต์€ ์•„๋ž˜ ๋ชจ์–‘์œผ๋กœ ๋‚˜๊ฐ„๋‹ค.

    {
        "message": "ํšŒ์› ์ •๋ณด ์—†์Œ",
        "status": 404
    }

     

    ResponseEntity๋ฅผ ์ „๋ถ€ Service ๋‹จ๊ณ„์—์„œ return ํ•˜๊ณ , ๊ทธ๋ฅผ ๊ทธ๋Œ€๋กœ Controller์—์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๊ธด ํ•˜์ง€๋งŒ,

    ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์ด ๋ณ„๋กœ์ผ ๊ฒƒ ๊ฐ™๋‹ค.

    ๊ฐ„๋‹จํ•˜๊ฒŒ ์—๋Ÿฌ๋ฅผ ๋‚ด์•ผํ•  ๋•Œ ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค.

     

    2. Custom ์˜ˆ์™ธ ํด๋ž˜์Šค ๋งŒ๋“ค๊ธฐ

    ์—ญ์‹œ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๋‹ค.

    ํ•˜์ง€๋งŒ ๋ชจ๋“  ์—๋Ÿฌ์— ๋Œ€ํ•ด ์ „๋ถ€ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

    @ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "ํ•ด๋‹น id์— ํ•ด๋‹นํ•˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.")
    public class NotFoundIdException extends RuntimeException{ }

    ์ด๋Ÿฐ ํด๋ž˜์Šค๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์„œ ํ•„์š”ํ•  ๋•Œ Throw ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

    {
      "timestamp": "2023-04-02T13:13:11.287+00:00",
      "status": 400,
      "error": "Bad Request",
      "trace": "{trace}",
      "message": "์ž˜๋ชป๋œ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’ ์ž…๋‹ˆ๋‹ค.",
      "path": "/api/dresses/search"
    }

    ์ด๋Ÿฐ ํ˜•์‹์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์ „์†ก๋œ๋‹ค.

    3. ControllerAdvice ์‚ฌ์šฉํ•˜๊ธฐ

    ๊ฐ€์žฅ ์ถ”์ฒœํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

    ๊น”๋”ํ•˜๊ณ , ๋งŽ์€ ์—๋Ÿฌ๋ฅผ ๋งŽ์€ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๊ณ ๋„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

    @RequiredArgsConstructor
    @Getter
    public enum ErrorResponseStatus {
    
        BAD_REQUEST_WRONG_TAG_EXCEPTION(HttpStatus.BAD_REQUEST, "์ž˜๋ชป๋œ ํƒœ๊ทธ"),
        
        UNAUTHORIZED_WRONG_SOCIAL_TYPE(HttpStatus.UNAUTHORIZED, "์ž˜๋ชป๋œ ์†Œ์…œ ํƒ€์ž…"),
        UNAUTHORIZED_INVALID_SOCIAL_TOKEN(HttpStatus.UNAUTHORIZED, "์ž˜๋ชป๋œ ์†Œ์…œ ํ† ํฐ"),
    
        NOT_FOUND_USER_EXCEPTION(HttpStatus.NOT_FOUND, "ํšŒ์› ์ •๋ณด ์—†์Œ"),
        NOT_FOUND_PASSWORD_EXCEPTION(HttpStatus.NOT_FOUND, "๋น„๋ฐ€๋ฒˆํ˜ธ ๋ถˆ์ผ์น˜"),
    
        CONFLICT_DUPLICATED_NICKNAME(HttpStatus.CONFLICT, "์ค‘๋ณต๋œ ๋‹‰๋„ค์ž„");
    
        private final HttpStatus code;
        private final String message;
    }

    ์ด๋Ÿฐ enum ํŒŒ์ผ์„ ํ•˜๋‚˜ ์ƒ์„ฑํ•˜๊ณ ,

    ์ด enum ํŒŒ์ผ๋กœ ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ๋Š” Exception ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค.

    @Getter
    @AllArgsConstructor
    public class CustomException extends RuntimeException {
        private final ErrorResponseStatus errorResponseStatus;
    }

    ๋‹ค์Œ ์œ„ Exception ํŒŒ์ผ์„ handleํ•˜๋Š” ExceptionHandler๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค.

    @RestControllerAdvice ๋˜๋Š” @ControllerAdvice๋ฅผ ๋ถ™์—ฌ์•ผ Spring์ด ์ธ์‹ํ•ด์„œ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ์ค€๋‹ค.

    @RestControllerAdvice
    public class ExceptionHandler extends ResponseEntityExceptionHandler{
    
        @org.springframework.web.bind.annotation.ExceptionHandler(value = CustomException.class)
        protected ResponseEntity<ResponseTemplate> handleCustomException(CustomException e) {
            return ResponseTemplate.toResponseEntity(e.getResponseCode());
        }
    }
    

    ResponseTemplete์˜ toResponseEntity ๋ฉ”์†Œ๋“œ๋ฅผ ๋ฆฌํ„ดํ•˜๋ฉด์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”๋ฐ,

    toResponseEntity์—์„œ๋Š” ErrorResponseStatus์˜ status์™€ ๋‚ด์šฉ์„ ๋ฐ›์•„์™€ ResponseEntity์— ์ง‘์–ด ๋„ฃ์–ด์„œ ์œ„ 1๋ฒˆ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ์žˆ๋‹ค.

    @Builder
    @AllArgsConstructor
    public class ResponseTemplate {
    
        public int status;
    
        public String message;
    
        private final LocalDateTime timestamp = LocalDateTime.now();
    
        public static ResponseEntity<ResponseTemplate> toResponseEntity(ErrorResponseStatus errorResponseStatus) {
            return ResponseEntity
                    .status(errorResponseStatus.getHttpStatus())
                    .body(ResponseTemplate.builder()
                            .status(errorResponseStatus.getHttpStatus().value())
                            .message(errorResponseStatus.getMessage())
                            .build()
                    );
        }
    }

     

    ์œ„ 4๊ฐœ์˜ ํด๋ž˜์Šค๋งŒ ๋งŒ๋“ค์–ด์ฃผ๋ฉด ์ˆ˜ ๋งŽ์€ ์—๋Ÿฌ๋ฅผ ์ฝ”๋“œ๋ฅผ ์žฌํ™œ์šฉํ•˜์—ฌ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์–ด ๊ฐ€์žฅ ์• ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

    1, 2๋ฒˆ๋ณด๋‹ค๋Š” ์กฐ๊ธˆ ๋ณต์žกํ•˜๊ฒŒ ๋А๊ปด์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ๋‹จ์ ์€ ์žˆ์œผ๋‹ˆ ์ƒํ™ฉ์— ๋”ฐ๋ผ ํ•„์š”ํ•œ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

Designed by Tistory.