diff --git a/src/main/java/com/kakaoteck/golagola/domain/buyer/entity/Buyer.java b/src/main/java/com/kakaoteck/golagola/domain/buyer/entity/Buyer.java index a7fac3a..ec1386f 100644 --- a/src/main/java/com/kakaoteck/golagola/domain/buyer/entity/Buyer.java +++ b/src/main/java/com/kakaoteck/golagola/domain/buyer/entity/Buyer.java @@ -2,6 +2,7 @@ import com.kakaoteck.golagola.domain.buyer.dto.BuyerRequest; import com.kakaoteck.golagola.domain.cart.entity.Cart; +import com.kakaoteck.golagola.domain.cart.entity.CartProduct; import com.kakaoteck.golagola.domain.order.entity.Order; import com.kakaoteck.golagola.domain.product.entity.Product; import com.kakaoteck.golagola.domain.review.entity.Review; @@ -25,8 +26,8 @@ @Entity @NoArgsConstructor @AllArgsConstructor -@Builder @Getter +@Builder @Table(name = "buyer_table") public class Buyer extends BaseEntity implements UserDetails { @@ -63,7 +64,7 @@ public class Buyer extends BaseEntity implements UserDetails { @Column(nullable = false) private LocalDate registerDate; - @OneToOne(mappedBy = "buyer", cascade = CascadeType.ALL) + @OneToOne(mappedBy = "buyer", cascade = CascadeType.ALL, orphanRemoval = true) private Cart cart; @OneToMany(mappedBy = "buyer", cascade = CascadeType.ALL) @@ -114,28 +115,36 @@ public void updateProfile(BuyerRequest.MyPagePutDto request) { } public void assignCart(Cart cart) { - if (cart != null) { - this.cart = cart; + this.cart = cart; + if (cart.getBuyer() != this) { cart.assignBuyer(this); } } - public void addProductToCart(Product product) { + // Cart를 자동으로 초기화 + @PrePersist + public void initializeCart() { if (this.cart == null) { - this.cart = new Cart(); // 새로운 Cart 객체 생성 - this.cart.assignBuyer(this); // Cart와 Buyer 간의 양방향 연관관계 설정 + Cart newCart = new Cart(); + newCart.assignBuyer(this); + this.cart = newCart; } - this.cart.getProductList().add(product); } public Cart getOrCreateCart() { if (this.cart == null) { - this.cart = new Cart(); // 새로운 Cart 객체 생성 - this.cart.assignBuyer(this); // Cart와 Buyer 간의 양방향 연관관계 설정 + Cart newCart = new Cart(); + newCart.assignBuyer(this); + this.cart = newCart; } return this.cart; } + public void addProductToCart(Product product) { + Cart cart = this.getOrCreateCart(); + cart.addProduct(product); + } + public static Buyer from(Long buyerId, String nickname, String realName, Gender gender, String email, String password, String address, String phoneNum, Role role, LocalDate registerDate) { return Buyer.builder() @@ -152,4 +161,3 @@ public static Buyer from(Long buyerId, String nickname, String realName, Gender .build(); } } - diff --git a/src/main/java/com/kakaoteck/golagola/domain/cart/dto/CartResponse.java b/src/main/java/com/kakaoteck/golagola/domain/cart/dto/CartResponse.java index 2372ce0..9ceb9b6 100644 --- a/src/main/java/com/kakaoteck/golagola/domain/cart/dto/CartResponse.java +++ b/src/main/java/com/kakaoteck/golagola/domain/cart/dto/CartResponse.java @@ -1,5 +1,6 @@ package com.kakaoteck.golagola.domain.cart.dto; +import com.kakaoteck.golagola.domain.product.dto.ProductResponse; import com.kakaoteck.golagola.domain.product.entity.Product; import lombok.Builder; @@ -7,7 +8,6 @@ @Builder public record CartResponse( - List productList + List productList ) { - } diff --git a/src/main/java/com/kakaoteck/golagola/domain/cart/entity/Cart.java b/src/main/java/com/kakaoteck/golagola/domain/cart/entity/Cart.java index ad35481..c1b4ca6 100644 --- a/src/main/java/com/kakaoteck/golagola/domain/cart/entity/Cart.java +++ b/src/main/java/com/kakaoteck/golagola/domain/cart/entity/Cart.java @@ -8,6 +8,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; +import java.util.ArrayList; import java.util.List; @Entity @@ -22,18 +23,24 @@ public class Cart { @JoinColumn(name = "buyer_id") private Buyer buyer; - @OneToMany(mappedBy = "cart", cascade = CascadeType.ALL) - private List productList; + @OneToMany(mappedBy = "cart", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true) + private List cartProducts = new ArrayList<>(); @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long cartId; public void assignBuyer(Buyer buyer) { - if (buyer != null) { - this.buyer = buyer; + this.buyer = buyer; + if (buyer.getCart() != this) { buyer.assignCart(this); } } + public void addProduct(Product product) { + CartProduct cartProduct = new CartProduct(); + cartProduct.assignCart(this); + cartProduct.assignProduct(product); + this.cartProducts.add(cartProduct); + } } diff --git a/src/main/java/com/kakaoteck/golagola/domain/cart/entity/CartProduct.java b/src/main/java/com/kakaoteck/golagola/domain/cart/entity/CartProduct.java new file mode 100644 index 0000000..b6257a7 --- /dev/null +++ b/src/main/java/com/kakaoteck/golagola/domain/cart/entity/CartProduct.java @@ -0,0 +1,43 @@ +package com.kakaoteck.golagola.domain.cart.entity; + +import com.kakaoteck.golagola.domain.product.entity.Product; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Builder +@Table(name = "cart_product_table") +public class CartProduct { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "cart_id") + private Cart cart; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "product_id") + private Product product; + + public void assignCart(Cart cart) { + this.cart = cart; + if (!cart.getCartProducts().contains(this)) { + cart.getCartProducts().add(this); + } + } + + public void assignProduct(Product product) { + this.product = product; + if (!product.getCartProducts().contains(this)) { + product.getCartProducts().add(this); + } + } +} diff --git a/src/main/java/com/kakaoteck/golagola/domain/cart/repository/CartProductRepository.java b/src/main/java/com/kakaoteck/golagola/domain/cart/repository/CartProductRepository.java new file mode 100644 index 0000000..155a72e --- /dev/null +++ b/src/main/java/com/kakaoteck/golagola/domain/cart/repository/CartProductRepository.java @@ -0,0 +1,10 @@ +package com.kakaoteck.golagola.domain.cart.repository; + +import com.kakaoteck.golagola.domain.cart.entity.Cart; +import com.kakaoteck.golagola.domain.cart.entity.CartProduct; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface CartProductRepository extends JpaRepository { +} diff --git a/src/main/java/com/kakaoteck/golagola/domain/cart/service/CartService.java b/src/main/java/com/kakaoteck/golagola/domain/cart/service/CartService.java index 238c57c..31cac9e 100644 --- a/src/main/java/com/kakaoteck/golagola/domain/cart/service/CartService.java +++ b/src/main/java/com/kakaoteck/golagola/domain/cart/service/CartService.java @@ -1,21 +1,23 @@ package com.kakaoteck.golagola.domain.cart.service; -import com.kakaoteck.golagola.domain.buyer.dto.BuyerResponse; import com.kakaoteck.golagola.domain.buyer.entity.Buyer; -import com.kakaoteck.golagola.domain.cart.dto.CartRequest; import com.kakaoteck.golagola.domain.cart.dto.CartResponse; +import com.kakaoteck.golagola.domain.cart.entity.Cart; +import com.kakaoteck.golagola.domain.cart.entity.CartProduct; +import com.kakaoteck.golagola.domain.cart.repository.CartProductRepository; +import com.kakaoteck.golagola.domain.product.dto.ProductResponse; import com.kakaoteck.golagola.domain.product.entity.Product; import com.kakaoteck.golagola.domain.product.repository.ProductRepository; import com.kakaoteck.golagola.global.common.code.status.ErrorStatus; import com.kakaoteck.golagola.global.common.exception.GeneralException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.hibernate.Hibernate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Collections; import java.util.List; -import java.util.Optional; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -24,16 +26,29 @@ public class CartService { private final ProductRepository productRepository; + private final CartProductRepository cartProductRepository; public CartResponse getCartProducts(Buyer buyer) { - // Cart가 null이 아닌 경우에만 productList를 가져오고, 그렇지 않으면 빈 리스트를 반환 - List productList = Collections.emptyList(); - if (buyer.getCart() != null) { - productList = buyer.getCart().getProductList() != null ? buyer.getCart().getProductList() : Collections.emptyList(); - } + Cart cart = buyer.getCart(); + + // Lazy 로딩을 명시적으로 초기화 + Hibernate.initialize(cart.getCartProducts()); + + // CartProduct 객체에서 Product를 추출하여 리스트 생성 + List products = cart.getCartProducts().stream() + .map(cartProduct -> { + Product product = cartProduct.getProduct(); + return ProductResponse.ProductDto.builder() + .productId(product.getProductId()) + .productName(product.getProductName()) + .productExplanation(product.getProductExplanation()) + .productPrice(product.getProductPrice()) + .build(); + }) + .collect(Collectors.toList()); return CartResponse.builder() - .productList(productList) + .productList(products) .build(); } @@ -41,41 +56,48 @@ public CartResponse addCartProduct(Buyer buyer, Long productId) { Product product = productRepository.findById(productId) .orElseThrow(() -> new GeneralException(ErrorStatus._NOT_FOUND_PRODUCT)); - // Buyer의 cart에 product를 추가 - buyer.addProductToCart(product); + Cart cart = buyer.getOrCreateCart(); - return CartResponse.builder() - .productList(buyer.getCart().getProductList()) + // 장바구니에 이미 동일한 상품이 있는지 확인 + boolean productExistsInCart = cart.getCartProducts().stream() + .anyMatch(cp -> cp.getProduct().getProductId().equals(productId)); + + if (productExistsInCart) { + throw new GeneralException(ErrorStatus._PRODUCT_ALREADY_IN_CART); // 이미 존재한다면 예외를 던집니다. + } + + // 장바구니에 상품 추가 + CartProduct cartProduct = CartProduct.builder() + .cart(cart) + .product(product) .build(); + + cartProductRepository.save(cartProduct); + + return getCartProducts(buyer); } public CartResponse deleteCartProduct(Buyer buyer, Long productId) { - if (buyer.getCart() == null || buyer.getCart().getProductList() == null) { - throw new GeneralException(ErrorStatus._NOT_FOUND_PRODUCT_IN_CART); - } + Cart cart = buyer.getCart(); - // Buyer의 cart에서 해당 productId에 해당하는 제품을 찾음 - List productList = buyer.getCart().getProductList(); - Product productToRemove = productList.stream() - .filter(product -> product.getProductId().equals(productId)) + CartProduct cartProduct = cart.getCartProducts().stream() + .filter(cp -> cp.getProduct().getProductId().equals(productId)) .findFirst() .orElseThrow(() -> new GeneralException(ErrorStatus._NOT_FOUND_PRODUCT_IN_CART)); - // 제품을 장바구니에서 삭제 - productList.remove(productToRemove); + cartProductRepository.delete(cartProduct); - return CartResponse.builder() - .productList(productList) - .build(); + return getCartProducts(buyer); } public String emptyCart(Buyer buyer) { - if (buyer.getCart() == null || buyer.getCart().getProductList() == null) { + Cart cart = buyer.getCart(); + + if (cart.getCartProducts().isEmpty()) { throw new GeneralException(ErrorStatus._CART_IS_ALREADY_EMPTY); } - // 장바구니를 비움 - buyer.getCart().getProductList().clear(); + cartProductRepository.deleteAll(cart.getCartProducts()); return "장바구니에 있는 모든 제품이 삭제되었습니다."; } diff --git a/src/main/java/com/kakaoteck/golagola/domain/product/controller/ProductController.java b/src/main/java/com/kakaoteck/golagola/domain/product/controller/ProductController.java new file mode 100644 index 0000000..2fe7a71 --- /dev/null +++ b/src/main/java/com/kakaoteck/golagola/domain/product/controller/ProductController.java @@ -0,0 +1,51 @@ +package com.kakaoteck.golagola.domain.product.controller; + +import com.kakaoteck.golagola.domain.product.dto.ProductRequest; +import com.kakaoteck.golagola.domain.product.dto.ProductResponse; +import com.kakaoteck.golagola.domain.product.service.ProductService; +import com.kakaoteck.golagola.domain.seller.dto.SellerResponse; +import com.kakaoteck.golagola.domain.seller.entity.Seller; +import com.kakaoteck.golagola.global.common.ApiResponse; +import io.swagger.v3.oas.annotations.Operation; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/product") +@CrossOrigin("*") +public class ProductController { + + private final ProductService productService; + + @Operation(summary = "상품 등록", description = "상품을 등록합니다. 판매자 전용") + @PostMapping() + public ApiResponse postProduct( + @AuthenticationPrincipal Seller seller, + @RequestBody ProductRequest request + ) { + return ApiResponse.onSuccess(productService.postProduct(seller, request)); + } + + @Operation(summary = "상품 수정", description = "상품 정보를 수정합니다.") + @PutMapping("/{productId}") + public ApiResponse modifyProduct( + @AuthenticationPrincipal Seller seller, + @PathVariable Long productId, + @RequestBody ProductRequest request + ) { + return ApiResponse.onSuccess(productService.modifyProduct(seller, productId, request)); + } + + @Operation(summary = "상품 삭제", description = "상품을 삭제합니다. 판매자 전용") + @DeleteMapping("/{productId}") + public ApiResponse deleteProduct( + @AuthenticationPrincipal Seller seller, + @PathVariable Long productId + ) { + productService.deleteProduct(seller, productId); + return ApiResponse.onSuccess("상품이 성공적으로 삭제되었습니다."); + } + +} diff --git a/src/main/java/com/kakaoteck/golagola/domain/product/dto/ProductRequest.java b/src/main/java/com/kakaoteck/golagola/domain/product/dto/ProductRequest.java new file mode 100644 index 0000000..7fb83b3 --- /dev/null +++ b/src/main/java/com/kakaoteck/golagola/domain/product/dto/ProductRequest.java @@ -0,0 +1,19 @@ +package com.kakaoteck.golagola.domain.product.dto; + +import com.kakaoteck.golagola.global.common.enums.Category; +import com.kakaoteck.golagola.global.common.enums.DetailCategory; +import lombok.Builder; + +@Builder +public record ProductRequest( + String productName, + String productExplanation, + String productImage, + Long productPrice, + Long productInventory, + Category category, + DetailCategory detailCategory, + Long discount, + Long productQuantity +) { +} diff --git a/src/main/java/com/kakaoteck/golagola/domain/product/dto/ProductResponse.java b/src/main/java/com/kakaoteck/golagola/domain/product/dto/ProductResponse.java new file mode 100644 index 0000000..9b5eec4 --- /dev/null +++ b/src/main/java/com/kakaoteck/golagola/domain/product/dto/ProductResponse.java @@ -0,0 +1,29 @@ +package com.kakaoteck.golagola.domain.product.dto; + +import com.kakaoteck.golagola.global.common.enums.Category; +import com.kakaoteck.golagola.global.common.enums.DetailCategory; +import lombok.Builder; + +@Builder +public record ProductResponse( + Long productId, + String productName, + String productExplanation, + String productImage, + Long productPrice, + Long productInventory, + Category category, + DetailCategory detailCategory, + Long discount, + Long productQuantity, + Float predictReviewStar, + Float productStar +) { + @Builder + public record ProductDto (Long productId, + String productName, + String productExplanation, + Long productPrice) { + + } +} diff --git a/src/main/java/com/kakaoteck/golagola/domain/product/entity/Product.java b/src/main/java/com/kakaoteck/golagola/domain/product/entity/Product.java index 3031f8f..52db5a0 100644 --- a/src/main/java/com/kakaoteck/golagola/domain/product/entity/Product.java +++ b/src/main/java/com/kakaoteck/golagola/domain/product/entity/Product.java @@ -1,6 +1,7 @@ package com.kakaoteck.golagola.domain.product.entity; -import com.kakaoteck.golagola.domain.cart.entity.Cart; +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.kakaoteck.golagola.domain.cart.entity.CartProduct; import com.kakaoteck.golagola.domain.orderProduct.entity.OrderProduct; import com.kakaoteck.golagola.domain.review.entity.Review; import com.kakaoteck.golagola.domain.seller.entity.Seller; @@ -30,11 +31,11 @@ public class Product extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "seller_id") + @JsonBackReference private Seller seller; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "cart_id") - private Cart cart; + @OneToMany(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true) + private List cartProducts; @OneToMany(mappedBy = "product", cascade = CascadeType.ALL) private List reviewList; @@ -77,24 +78,35 @@ public class Product extends BaseEntity { @Column(nullable = false) private Long productQuantity; - @Column(nullable = false) + @Column() private Float predictReviewStar; - @Column(nullable = false) + @Column() private Float productStar; - public static Product from(Long productId, Seller seller, Cart cart, List reviewList, - List orderProductList, String productName, - String productExplanation, String productImage, Long productPrice, - Long productInventory, Category category, DetailCategory detailCategory, - Long discount, LocalTime createTime, LocalTime updateTime, - Long productQuantity, Float predictReviewStar, Float productStar) { + // Product 수정 메서드 + public void updateProduct(String productName, String productExplanation, String productImage, Long productPrice, + Long productInventory, Category category, DetailCategory detailCategory, + Long discount, Long productQuantity, LocalTime updateTime) { + this.productName = productName; + this.productExplanation = productExplanation; + this.productImage = productImage; + this.productPrice = productPrice; + this.productInventory = productInventory; + this.category = category; + this.detailCategory = detailCategory; + this.discount = discount; + this.productQuantity = productQuantity; + this.updateTime = updateTime; + } + + // Product 생성 메서드 + public static Product createProduct(Seller seller, String productName, String productExplanation, + String productImage, Long productPrice, Long productInventory, + Category category, DetailCategory detailCategory, Long discount, + Long productQuantity) { return Product.builder() - .productId(productId) .seller(seller) - .cart(cart) - .reviewList(reviewList) - .orderProductList(orderProductList) .productName(productName) .productExplanation(productExplanation) .productImage(productImage) @@ -103,12 +115,11 @@ public static Product from(Long productId, Seller seller, Cart cart, List new GeneralException(ErrorStatus._NOT_FOUND_PRODUCT)); + + // 해당 상품이 현재 로그인한 seller가 등록한 것인지 확인 + if (!product.getSeller().getSellerId().equals(seller.getSellerId())) { + throw new GeneralException(ErrorStatus._UNAUTHORIZED_ACCESS); + } + + // Product 정보 업데이트 + product.updateProduct( + request.productName(), + request.productExplanation(), + request.productImage(), + request.productPrice(), + request.productInventory(), + request.category(), + request.detailCategory(), + request.discount(), + request.productQuantity(), + LocalTime.now() // updateTime을 현재 시간으로 업데이트 + ); + + // 업데이트된 Product 저장 + productRepository.save(product); + + return ProductResponse.builder() + .productId(product.getProductId()) + .productName(product.getProductName()) + .productExplanation(product.getProductExplanation()) + .productImage(product.getProductImage()) + .productPrice(product.getProductPrice()) + .productInventory(product.getProductInventory()) + .category(product.getCategory()) + .detailCategory(product.getDetailCategory()) + .discount(product.getDiscount()) + .productQuantity(product.getProductQuantity()) + .build(); + } + + public void deleteProduct(Seller seller, Long productId) { + // productId로 Product를 찾음 + Product product = productRepository.findById(productId) + .orElseThrow(() -> new GeneralException(ErrorStatus._NOT_FOUND_PRODUCT)); + + // 해당 Product가 현재 로그인된 seller가 등록한 제품인지 확인 + if (!product.getSeller().getSellerId().equals(seller.getSellerId())) { + throw new GeneralException(ErrorStatus._UNAUTHORIZED_ACCESS); + } + + // 해당 Product가 장바구니에 담겨 있는지 확인 + boolean isInCart = product.getCartProducts() != null && !product.getCartProducts().isEmpty(); + + if (isInCart) { + throw new GeneralException(ErrorStatus._PRODUCT_IN_CART_CANNOT_DELETE); + } + + // Product 삭제 + productRepository.delete(product); + } + +} diff --git a/src/main/java/com/kakaoteck/golagola/domain/seller/entity/Seller.java b/src/main/java/com/kakaoteck/golagola/domain/seller/entity/Seller.java index 4e3b22b..bef1ad2 100644 --- a/src/main/java/com/kakaoteck/golagola/domain/seller/entity/Seller.java +++ b/src/main/java/com/kakaoteck/golagola/domain/seller/entity/Seller.java @@ -1,5 +1,6 @@ package com.kakaoteck.golagola.domain.seller.entity; +import com.fasterxml.jackson.annotation.JsonManagedReference; import com.fasterxml.jackson.databind.ser.Serializers; import com.kakaoteck.golagola.domain.buyer.dto.BuyerRequest; import com.kakaoteck.golagola.domain.order.entity.Order; @@ -65,6 +66,7 @@ public class Seller extends BaseEntity implements UserDetails { private LocalDate registerDate; @OneToMany(mappedBy = "seller", cascade = CascadeType.ALL) + @JsonManagedReference private List productList = new ArrayList<>(); @OneToMany(mappedBy = "seller", cascade = CascadeType.ALL) diff --git a/src/main/java/com/kakaoteck/golagola/global/common/code/status/ErrorStatus.java b/src/main/java/com/kakaoteck/golagola/global/common/code/status/ErrorStatus.java index 98715c8..3849fbc 100644 --- a/src/main/java/com/kakaoteck/golagola/global/common/code/status/ErrorStatus.java +++ b/src/main/java/com/kakaoteck/golagola/global/common/code/status/ErrorStatus.java @@ -19,13 +19,16 @@ public enum ErrorStatus implements BaseErrorCode { _NOT_FOUND_USER(HttpStatus.NOT_FOUND, "USER400", "사용자가 존재하지 않습니다."), _LOGIN_USER_INVALID(HttpStatus.BAD_REQUEST, "USER401", "로그인 중 오류가 발생하였습니다."), _INVALID_USER(HttpStatus.BAD_REQUEST, "USER401" , "아이디 또는 비밀번호가 틀렸습니다."), + _UNAUTHORIZED_ACCESS(HttpStatus.UNAUTHORIZED, "USER401", "본인이 등록한 제품만 수정할 수 있습니다."), // Product 에러 _NOT_FOUND_PRODUCT(HttpStatus.NOT_FOUND, "USER400", "제품이 존재하지 않습니다."), _NOT_FOUND_PRODUCT_IN_CART(HttpStatus.NOT_FOUND, "USER400", "제품이 장바구니에 존재하지 않습니다."), + _PRODUCT_IN_CART_CANNOT_DELETE(HttpStatus.BAD_REQUEST, "USER400", "장바구니에 담겨있는 상품은 삭제할 수 없습니다."), // Cart 에러 _CART_IS_ALREADY_EMPTY(HttpStatus.BAD_REQUEST, "USER400", "장바구니가 이미 비어있습니다."), + _PRODUCT_ALREADY_IN_CART(HttpStatus.BAD_REQUEST, "USER400", "장바구니에 이미 해당상품이 존재합니다."), // Security 에러 INVALID_TOKEN(HttpStatus.BAD_REQUEST, "SEC4001", "잘못된 형식의 토큰입니다."),