멋사 Backend Plus 29일차 🦁

μ‹ μž¬μ›Β·2023λ…„ 12μ›” 3일

μ˜€λŠ˜λ„ μ˜€μ „μ—λŠ” νŒ€ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜μ˜€κ³ , λŠ¦μ€ μ˜€ν›„ λΆ€ν„°λŠ” νŒ€ λ°œν‘œλ₯Ό μ§„ν–‰ν•˜μ˜€λ‹€. 맑은 뢀뢄에 λŒ€ν•œ μ½”λ“œλ₯Ό 짜며 κΈ°λ‘ν•˜μ—¬ 남기면 쒋을 것 같은 뢀뢄을 μž‘μ„±ν•΄λ³Όλ €κ³  ν•œλ‹€.

μ˜€μ „

기쑴에 @Valid μ–΄λ…Έν…Œμ΄μ…˜κ³Ό BindingResult 객체λ₯Ό μ‚¬μš©ν•˜μ—¬ μš”μ²­μ— λŒ€ν•œ μ˜ˆμ™Έμ²˜λ¦¬λ₯Ό ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

  • @Valid μ–΄λ…Έν…Œμ΄μ…˜κ³Ό BindingResult μ‚¬μš©

➑ μš”μ²­ DTO 클래슀

@Getter
@Setter
public class CreateRequest {
    @NotBlank(message = "μƒν’ˆ 이름은 ν•„μˆ˜ μž…λ‹ˆλ‹€.")
    private String productName;
    @NotBlank(message = "μƒν’ˆ 가격은 ν•„μˆ˜ μž…λ‹ˆλ‹€.")
    private String price;
    @NotBlank(message = "μƒν’ˆ μ„€λͺ…은 ν•„μˆ˜ μž…λ‹ˆλ‹€.")
    private String content;
    @NotNull(message = "μƒν’ˆ κ°―μˆ˜λŠ” ν•„μˆ˜ μž…λ‹ˆλ‹€.")
    private Integer count;
    @NotNull(message = "μƒν’ˆ μΉ΄ν…Œκ³ λ¦¬λŠ” ν•„μˆ˜ μž…λ‹ˆλ‹€.")
    private Category category;
}

➑ 컨트둀러 단
μ•„λž˜μ˜ μ½”λ“œμ— λŒ€ν•΄μ„œ μ„€λͺ…을 ν•˜μžλ©΄ μž‘μ„±ν•œ CreateRequest 객체에 @Valid μ–΄λ…Έν…Œμ΄μ…˜μ„ μž‘μ„±ν•˜μ—¬, 검증을 ν• μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.
μž‘μ„±ν•œ 검증 쑰건에 λŒ€ν•΄ BindingResult λ©”μ†Œλ“œμ˜ hasErrors() λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ˜ˆμ™Έ 검증을 ν• μˆ˜ 있으며, 400 μ—λŸ¬κ°€ λ°œμƒν•©λ‹ˆλ‹€.

 @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public RsData createProduct(@ModelAttribute @Valid CreateRequest createRequest,
                                @ModelAttribute(name = "images") MultipartFile images,
                                BindingResult bindingResult) throws IOException {
        if (hasErrors(bindingResult)) {
            return RsData.failOf(INVALID_PRODUCT_REQUEST);
        }
        productService.createProductWithImage(createRequest, images);
        return RsData.of("S-1", POST_SUCCESS_PRODUCT, "create");
    }
    
    private boolean hasErrors(BindingResult bindingResult) {
        return bindingResult.hasErrors();
    }

μœ„ 처럼 BindingResult 객체λ₯Ό μ‚¬μš©ν•˜μ—¬ μ˜ˆμ™Έ 검증을 ν• μˆ˜ μžˆμ§€λ§Œ, μ €λŠ” λ§€κ°œλ³€μˆ˜μ˜ κ°―μˆ˜κ°€ 3개 μ΄μƒμœΌλ‘œ λ˜μ–΄ λ¦¬νŒ©ν† λ§ ν•  ν•„μš”μ„±μ„ 느끼게 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

➑ μ˜ˆμ™Έμ²˜λ¦¬λ₯Ό μ»€μŠ€ν…€ν•˜μ—¬ μ „μ—­μœΌλ‘œ κ΄€λ¦¬ν•˜κΈ° μœ„ν•œ @RestControllerAdvice 와 μ˜ˆμ™Έλ₯Ό 핸듀링 ν• μˆ˜ μžˆλŠ” @ExceptionHandler μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€.

μΆ”κ°€λ‘œ @Valid μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜μ—¬ μ˜ˆμ™Έλ₯Ό ν„°νŠΈλ¦¬λ©΄, MethodArgumentNotValidException이 λ°œμƒν•˜κ²Œ λ©λ‹ˆλ‹€.

@RestControllerAdvice
public class GlobalExceptionHandler {
    private static final String INVALID_PRODUCT_REQUEST 
    								= "μœ νš¨ν•˜μ§€ μ•Šμ€ μš”μ²­ μž…λ‹ˆλ‹€.";

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity<String> handleInvalidRequest
    				(MethodArgumentNotValidException exception) {
                    
        String message = Optional
        		.ofNullable(
                	exception.getBindingResult().getFieldError())
                .map(FieldError::getDefaultMessage)
                .orElseThrow(() 
                		-> new RuntimeException(INVALID_PRODUCT_REQUEST));

        return new ResponseEntity<>(message, HttpStatus.BAD_REQUEST);
    }
}

μœ„ μ½”λ“œμ™€ 같이 μ „μ—­μœΌλ‘œ μ˜ˆμ™Έλ₯Ό 처리 ν•˜κ²Œ 되면, 컨트둀러 λ‹¨μ—μ„œ BindingResult 객체λ₯Ό νŒŒλΌλ―Έν„°λ‘œ λ„˜κΈ°μ§€ μ•Šμ•„λ„ 되게 λ©λ‹ˆλ‹€.

➑ BindingResult 객체λ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ μ‚¬μš©ν•˜μ§€ μ•Šμ€ 컨트둀러 단

@PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public RsData createProduct(@ModelAttribute @Valid CreateRequest createRequest,
                                @ModelAttribute(name = "images") MultipartFile images) throws IOException {
        productService.createProductWithImage(createRequest, images);
        return RsData.of("S-1", POST_SUCCESS_PRODUCT, "create");
    }

μ˜€ν›„

  • ERD μ„€κ³„λŠ” μœ„μ™€ 같이 ν•˜μ˜€κ³ , 말둜 ν’€μ–΄μ„œ μ„€λͺ…ν•˜λ©΄
    멀버 ν•œλͺ…이 μž₯λ°”κ΅¬λ‹ˆ(Cart)λ₯Ό ν•œκ°œλ§Œ κ°€μ§ˆμˆ˜ μžˆλ„λ‘ OneToOne 관계
    μž₯λ°”κ΅¬λ‹ˆ(Cart) ν•œκ°œμ˜ μ—¬λŸ¬κ°œμ˜ μƒν’ˆ(Item)이 λ‹΄κΈΈμˆ˜ 있음으둜, OneToMany 관계
    λ“±λ‘ν•œ μƒν’ˆ(Product)λŠ” μ—¬λŸ¬κ°œμ˜ μƒν’ˆ (Item)으둜 μž₯λ°”κ΅¬λ‹ˆμ— λ‹΄κΈΈμˆ˜ 있음으둜, OneToMany κ΄€κ³„λ‘œ 틀을 μž‘μ•˜μŠ΅λ‹ˆλ‹€.

0개의 λŒ“κΈ€