diff --git a/src/main/java/com/example/couphoneserver/common/response/status/BaseExceptionResponseStatus.java b/src/main/java/com/example/couphoneserver/common/response/status/BaseExceptionResponseStatus.java index 710cd89..2fa2422 100644 --- a/src/main/java/com/example/couphoneserver/common/response/status/BaseExceptionResponseStatus.java +++ b/src/main/java/com/example/couphoneserver/common/response/status/BaseExceptionResponseStatus.java @@ -58,9 +58,10 @@ public enum BaseExceptionResponseStatus implements ResponseStatus { /** * 8000: 가게 오류 */ - COORDINATE_NOT_FOUND(8000,HttpStatus.BAD_REQUEST.value(), "좌표를 찾을 수 없습니다."), - DUPLICATE_STORE_NAME(8001,HttpStatus.BAD_REQUEST.value(), "중복된 지점이 존재합니다."), - NEARBY_STORE_NOT_FOUND(8002,HttpStatus.BAD_REQUEST.value(), "좌표 기준 주변 가게가 없습니다."), + INVALID_STORE_VALUE(8000,HttpStatus.BAD_REQUEST.value(), "가게 등록에 유효하지 않은 정보입니다."), + COORDINATE_NOT_FOUND(8001,HttpStatus.BAD_REQUEST.value(), "좌표를 찾을 수 없습니다."), + DUPLICATE_STORE_NAME(8002,HttpStatus.BAD_REQUEST.value(), "중복된 지점이 존재합니다."), + NEARBY_STORE_NOT_FOUND(8003,HttpStatus.BAD_REQUEST.value(), "좌표 기준 주변 가게가 없습니다."), /** * 9000: 쿠폰 오류 diff --git a/src/main/java/com/example/couphoneserver/controller/StoreController.java b/src/main/java/com/example/couphoneserver/controller/StoreController.java index e4a02c3..fb0e636 100644 --- a/src/main/java/com/example/couphoneserver/controller/StoreController.java +++ b/src/main/java/com/example/couphoneserver/controller/StoreController.java @@ -1,16 +1,39 @@ package com.example.couphoneserver.controller; +import com.example.couphoneserver.common.exception.StoreException; +import com.example.couphoneserver.common.response.BaseResponse; +import com.example.couphoneserver.dto.store.PostStoreRequest; +import com.example.couphoneserver.dto.store.PostStoreResponse; +import com.example.couphoneserver.service.StoreService; +import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.BindingResult; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import static com.example.couphoneserver.common.response.status.BaseExceptionResponseStatus.INVALID_STORE_VALUE; +import static com.example.couphoneserver.utils.BindingResultUtils.getErrorMessages; + @Tag(name = "store", description = "가게 관련 API 입니다.") @Slf4j @RestController @RequiredArgsConstructor @RequestMapping("/stores") public class StoreController { + private final StoreService storeService; + @PostMapping("") + @Operation(summary = "가게 등록", description = "Request Body에 브랜드 아이디, 매장명, 위도, 경도, 주소를 담아서 보내주세요!") + public BaseResponse postBrand(@Validated @RequestBody PostStoreRequest request, + BindingResult bindingResult){ + if (bindingResult.hasErrors()){ + throw new StoreException(INVALID_STORE_VALUE,getErrorMessages(bindingResult)); + } + return new BaseResponse<>(storeService.save(request)); + } } diff --git a/src/main/java/com/example/couphoneserver/domain/entity/Store.java b/src/main/java/com/example/couphoneserver/domain/entity/Store.java index 27cc2e6..7da30ef 100644 --- a/src/main/java/com/example/couphoneserver/domain/entity/Store.java +++ b/src/main/java/com/example/couphoneserver/domain/entity/Store.java @@ -3,6 +3,7 @@ import com.example.couphoneserver.domain.StoreStatus; import jakarta.persistence.*; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -25,4 +26,14 @@ public class Store extends BaseTimeEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "brand_id") private Brand brand; // 해당 매장의 브랜드 + + @Builder + public Store(String name, String address, Double longitude, Double latitude, StoreStatus status, Brand brand) { + this.name = name; + this.address = address; + this.longitude = longitude; + this.latitude = latitude; + this.status = status; + this.brand = brand; + } } diff --git a/src/main/java/com/example/couphoneserver/dto/store/PostStoreRequest.java b/src/main/java/com/example/couphoneserver/dto/store/PostStoreRequest.java index df04a65..71fed10 100644 --- a/src/main/java/com/example/couphoneserver/dto/store/PostStoreRequest.java +++ b/src/main/java/com/example/couphoneserver/dto/store/PostStoreRequest.java @@ -1,37 +1,48 @@ package com.example.couphoneserver.dto.store; import com.example.couphoneserver.domain.StoreStatus; +import com.example.couphoneserver.domain.entity.Brand; +import com.example.couphoneserver.domain.entity.Store; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.annotation.Nullable; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; +import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import org.hibernate.validator.constraints.Range; @Data +@NoArgsConstructor +@AllArgsConstructor public class PostStoreRequest { - @NotNull - @Range(min=1,message="bid: 브랜드 아이디는 {min} 이상부터 가능합니다.") + @NotNull(message = "bid: {NotNull}") + @Range(min=1,message="bid: 브랜드 아이디는 {min} 이상부터 가능합니다") @Schema(example="1", description = "브랜드 등록 후 응답값으로 받은 브랜드 아이디를 넣어주세요.") private Long bid; - @NotNull - @Size(min=1,max=100,message = "name: 가게 이름의 길이는 {min} 이상, {max} 이하 가능합니다.") + + @NotBlank(message = "name: {NotBlank}") + @Size(min=1,max=100,message = "name: 가게 이름의 길이는 {min} 이상, {max} 이하 가능합니다") @Schema(example="건국대학교 서울캠퍼스",description = "브랜드 이름+공백+지점명으로 보내주세요.") private String name; - @NotNull + @NotBlank(message = "address: {NotBlank}") @Schema(example = "서울특별시 광진구 능동로 120") private String address; - @NotNull + @NotNull(message = "longitude: {NotNull}") @Schema(example = "123456.111111") private Double longitude; - @NotNull + @NotNull(message = "latitude: {NotNull}") @Schema(example = "123456.111111") private Double latitude; - @Nullable - @Enumerated(EnumType.STRING) - private StoreStatus status = StoreStatus.ACTIVE; - + public Store toEntity(Brand brand) { + return Store.builder() + .name(name) + .address(address) + .longitude(longitude) + .latitude(latitude) + .status(StoreStatus.ACTIVE) + .brand(brand) + .build(); + } } diff --git a/src/main/java/com/example/couphoneserver/dto/store/PostStoreResponse.java b/src/main/java/com/example/couphoneserver/dto/store/PostStoreResponse.java index 6d73ae0..bce651a 100644 --- a/src/main/java/com/example/couphoneserver/dto/store/PostStoreResponse.java +++ b/src/main/java/com/example/couphoneserver/dto/store/PostStoreResponse.java @@ -1,4 +1,16 @@ package com.example.couphoneserver.dto.store; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + + + +@Data public class PostStoreResponse { + @Schema(example = "1", description = "회원 아이디") + private Long id; + + public PostStoreResponse(Long id) { + this.id = id; + } } diff --git a/src/main/java/com/example/couphoneserver/repository/StoreRepository.java b/src/main/java/com/example/couphoneserver/repository/StoreRepository.java index 1205181..03a8cdf 100644 --- a/src/main/java/com/example/couphoneserver/repository/StoreRepository.java +++ b/src/main/java/com/example/couphoneserver/repository/StoreRepository.java @@ -6,4 +6,7 @@ public interface StoreRepository extends JpaRepository { //TODO 1. 가게 등록 //TODO 2. 최단 거리 가게 조회 + + boolean existsByName(String name); + } diff --git a/src/main/java/com/example/couphoneserver/service/StoreService.java b/src/main/java/com/example/couphoneserver/service/StoreService.java index c7f9f39..1bbd782 100644 --- a/src/main/java/com/example/couphoneserver/service/StoreService.java +++ b/src/main/java/com/example/couphoneserver/service/StoreService.java @@ -1,26 +1,56 @@ package com.example.couphoneserver.service; +import com.example.couphoneserver.common.exception.BrandException; +import com.example.couphoneserver.common.exception.StoreException; +import com.example.couphoneserver.domain.entity.Brand; +import com.example.couphoneserver.domain.entity.Store; import com.example.couphoneserver.dto.store.PostStoreRequest; import com.example.couphoneserver.dto.store.PostStoreResponse; +import com.example.couphoneserver.repository.BrandRepository; import com.example.couphoneserver.repository.StoreRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Optional; + +import static com.example.couphoneserver.common.response.status.BaseExceptionResponseStatus.BRAND_NOT_FOUND; +import static com.example.couphoneserver.common.response.status.BaseExceptionResponseStatus.DUPLICATE_STORE_NAME; + @Slf4j @Service @Transactional(readOnly = true) @RequiredArgsConstructor public class StoreService { private final StoreRepository storeRepository; + private final BrandRepository brandRepository; /* 가게 등록 */ @Transactional - public PostStoreResponse save(PostStoreRequest postStoreRequest) { - return null; + public PostStoreResponse save(PostStoreRequest request) { + //매장 브랜드 찾기 + Brand brandOfStore = validateBrand(request.getBid()); + //지점명 중복 확인 + validateStoreName(request); + //매장 등록 + Store store = storeRepository.save(request.toEntity(brandOfStore)); + return new PostStoreResponse(store.getId()); + } + + private void validateStoreName(PostStoreRequest postStoreRequest) { +// log.info("[StoreService.validateStoreName]"); + if(storeRepository.existsByName(postStoreRequest.getName())) + throw new StoreException(DUPLICATE_STORE_NAME); + } + + private Brand validateBrand(Long brandId) { +// log.info("[StoreService.validateBrand]"); + Optional brand = brandRepository.findById(brandId); + if(brand.isEmpty()) throw new BrandException(BRAND_NOT_FOUND); + return brand.get(); } /*