From 6b96cd252392c2a407370309a6ddd2c8107922a6 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Thu, 18 May 2023 23:52:13 +0900 Subject: [PATCH 01/17] =?UTF-8?q?feat:=20class=20=EB=B0=8F=20method=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/controller/OwnerShopController.java | 37 ++++- .../admin/shop/request/CreateShopRequest.java | 1 + .../shop/request/CreateShopRequest.java | 148 ++++++++++++++++++ .../in/service/OwnerShopService.java | 9 +- .../in/service/OwnerShopServiceImpl.java | 6 + 5 files changed, 197 insertions(+), 4 deletions(-) create mode 100644 src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java diff --git a/src/main/java/koreatech/in/controller/OwnerShopController.java b/src/main/java/koreatech/in/controller/OwnerShopController.java index d40ec377..b4577492 100644 --- a/src/main/java/koreatech/in/controller/OwnerShopController.java +++ b/src/main/java/koreatech/in/controller/OwnerShopController.java @@ -1,6 +1,11 @@ package koreatech.in.controller; -import io.swagger.annotations.*; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import io.swagger.annotations.Authorization; import koreatech.in.annotation.Auth; import koreatech.in.annotation.ParamValid; import koreatech.in.dto.EmptyResponse; @@ -8,16 +13,26 @@ import koreatech.in.dto.RequestDataInvalidResponse; import koreatech.in.dto.normal.shop.request.CreateMenuCategoryRequest; import koreatech.in.dto.normal.shop.request.CreateMenuRequest; +import koreatech.in.dto.normal.shop.request.CreateShopRequest; import koreatech.in.dto.normal.shop.request.UpdateMenuRequest; import koreatech.in.dto.normal.shop.request.UpdateShopRequest; -import koreatech.in.dto.normal.shop.response.*; +import koreatech.in.dto.normal.shop.response.AllMenuCategoriesOfShopResponse; +import koreatech.in.dto.normal.shop.response.AllMenusOfShopResponse; +import koreatech.in.dto.normal.shop.response.AllShopsOfOwnerResponse; +import koreatech.in.dto.normal.shop.response.MenuResponse; +import koreatech.in.dto.normal.shop.response.ShopResponse; import koreatech.in.service.OwnerShopService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; import javax.validation.Valid; @@ -31,6 +46,22 @@ public class OwnerShopController { // =============================================== 상점 ================================================= + @ApiOperation(value = "상점 생성", notes = "- 사장님 권한만 허용\n- 인증 정보에 대한 신원이 해당 상점의 점주가 아니라면 403(Forbidden) 응답", authorizations = {@Authorization("Authorization")}) + @ApiResponses({ + @ApiResponse(code = 401, message = "- 잘못된 접근일 때 (code: 100001) \n" + + "- 액세스 토큰이 만료되었을 때 (code: 100004) \n" + + "- 액세스 토큰이 변경되었을 때 (code: 100005)", response = ExceptionResponse.class), + @ApiResponse(code = 403, message = "- 권한이 없을 때 (code: 100003)", response = ExceptionResponse.class) + }) + @RequestMapping(value = "", method = RequestMethod.POST) + public @ResponseBody + ResponseEntity createShop(@ApiParam(name = "상점 정보 JSON", required = true) @RequestBody @Valid CreateShopRequest request, BindingResult bindingResult) { + request.checkDataConstraintViolation(); // javax validation으로 판단할 수 없는 제약조건 검사 + + ownerShopService.createShop(request); + return new ResponseEntity<>(HttpStatus.OK); + } + @ApiOperation(value = "상점 조회", notes = "- 사장님 권한만 허용\n- 인증 정보에 대한 신원이 해당 상점의 점주가 아니라면 403(Forbidden) 응답", authorizations = {@Authorization("Authorization")}) @ApiResponses({ @ApiResponse(code = 401, message = "- 잘못된 접근일 때 (code: 100001) \n" + diff --git a/src/main/java/koreatech/in/dto/admin/shop/request/CreateShopRequest.java b/src/main/java/koreatech/in/dto/admin/shop/request/CreateShopRequest.java index bd35d128..d8727950 100644 --- a/src/main/java/koreatech/in/dto/admin/shop/request/CreateShopRequest.java +++ b/src/main/java/koreatech/in/dto/admin/shop/request/CreateShopRequest.java @@ -14,6 +14,7 @@ import static koreatech.in.exception.ExceptionInformation.*; @Getter @Setter +@ApiModel("AdminCreateShopRequest") public class CreateShopRequest { @Size(min = 1, max = 15, message = "가게명의 길이는 1자 이상 15자 이하입니다.") @NotNull(message = "가게명은 필수입니다.") diff --git a/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java b/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java new file mode 100644 index 00000000..614dc440 --- /dev/null +++ b/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java @@ -0,0 +1,148 @@ +package koreatech.in.dto.normal.shop.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import koreatech.in.exception.BaseException; +import lombok.Getter; +import lombok.Setter; + +import javax.validation.Valid; +import javax.validation.constraints.*; +import java.time.DayOfWeek; +import java.util.*; + +import static koreatech.in.exception.ExceptionInformation.*; + +@Getter @Setter +@ApiModel("CreateShopRequest") +public class CreateShopRequest { + @Size(min = 1, max = 15, message = "가게명의 길이는 1자 이상 15자 이하입니다.") + @NotNull(message = "가게명은 필수입니다.") + @ApiModelProperty(notes = "가게명 \n" + + "- not null \n" + + "- 1자 이상 15자 이하", example = "써니 숯불 도시락", required = true) + private String name; + + @Pattern(regexp = "^[0-9]{3}-[0-9]{3,4}-[0-9]{4}$", message = "전화번호의 형식이 올바르지 않습니다.") + @NotNull(message = "전화번호는 필수입니다.") + @ApiModelProperty(notes = "전화번호 \n" + + "- not null \n" + + "- 정규식 `^[0-9]{3}-[0-9]{3,4}-[0-9]{4}$`을 만족해야함", example = "041-123-4567", required = true) + private String phone; + + @Valid + @NotNull(message = "운영 시간 정보는 필수입니다.") + @ApiModelProperty(notes = "요일별 운영 시간과 휴무 여부 \n" + + "- not null \n" + + "- 리스트의 길이는 7(1주일 요일 개수) 이어야 함 \n" + + "- day_of_week은 각각 `MONDAY`, `TUESDAY`, `WEDNESDAY`, `THURSDAY`, `FRIDAY`, `SATURDAY`, `SUNDAY` 이어야 함", required = true) + private List open = new ArrayList<>(); + + @Size(min = 1, max = 100, message = "주소의 길이는 1자 이상 100자 이하입니다.") + @NotNull(message = "주소는 필수입니다.") + @ApiModelProperty(notes = "주소 \n" + + "- not null \n" + + "- 1자 이상 100자 이하", example = "충청남도 천안시 동남구 병천면 충절로 1600", required = true) + private String address; + + @PositiveOrZero(message = "배달 금액은 0원 이상 2147483647원 이하여야합니다.") + @ApiModelProperty(notes = "배달 금액 \n" + + "- 0 이상 2147483647 이하 \n" + + "- null일 경우 0으로 저장됨", example = "1000") + private Integer delivery_price = 0; + + @Size(min = 1, max = 50, message = "기타정보의 길이는 1자 이상 50자 이하입니다.") + @ApiModelProperty(notes = "기타정보 \n" + + "- 1자 이상 50자 이하", example = "이번주 전 메뉴 10% 할인 이벤트합니다.") + private String description; + + @NotNull(message = "배달 가능 여부는 필수입니다.") + @ApiModelProperty(notes = "배달 가능 여부 \n" + + "- not null", example = "false", required = true) + private Boolean delivery; + + @NotNull(message = "카드 가능 여부는 필수입니다.") + @ApiModelProperty(notes = "카드 가능 여부 \n" + + "- not null", example = "true", required = true) + private Boolean pay_card; + + @NotNull(message = "계좌 이체 가능 여부는 필수입니다.") + @ApiModelProperty(notes = "계좌 이체 가능 여부 \n" + + "- not null", example = "true", required = true) + private Boolean pay_bank; + + @NotEmpty(message = "소속시킬 상점 카테고리는 최소 1개 선택하여야합니다.") + @ApiModelProperty(notes = "상점 카테고리 고유 id 리스트 \n" + + "- not null \n" + + "- 최소 1개", example = "[1, 4]", required = true) + private List category_ids = new ArrayList<>(); + + @Size(max = 10, message = "상점 이미지 개수 제한은 최대 10개입니다.") + @ApiModelProperty(notes = "이미지 URL 리스트 \n" + + "- 최대 10개") + private List image_urls = new ArrayList<>(); + + @Getter @Setter + @ApiModel("Open_7") + public static class Open { + @NotNull(message = "운영 시간의 요일 정보는 필수입니다.") + @ApiModelProperty(notes = "요일 \n" + + "- not null \n" + + "- `MONDAY`, `TUESDAY`, `WEDNESDAY`, `THURSDAY`, `FRIDAY`, `SATURDAY`, `SUNDAY` 중 택1 (중복되면 안됨)", example = "MONDAY", required = true) + private DayOfWeek day_of_week; + + @NotNull(message = "운영 시간의 휴무 여부는 필수입니다.") + @ApiModelProperty(notes = "휴무 여부 \n" + + "- not null", example = "false", required = true) + private Boolean closed; + + @Pattern(regexp = "^([01][0-9]|2[0-3]):([0-5][0-9])$", message = "운영 시간의 여는 시간 정보 형식이 올바르지 않습니다.") + @ApiModelProperty(notes = "여는 시간 \n" + + "- closed가 false일 때 \n" + + " - not null \n" + + " - 정규식 `^([01][0-9]|2[0-3]):([0-5][0-9])$`을 만족해야 함 \n" + + "- closed가 true일 때 \n" + + " - 어떤 값이 요청되던 null로 저장됨", example = "10:00") + private String open_time; + + @Pattern(regexp = "^([01][0-9]|2[0-3]):([0-5][0-9])$", message = "운영 시간의 닫는 시간 정보 형식이 올바르지 않습니다.") + @ApiModelProperty(notes = "닫는 시간 \n" + + "- closed가 false일때 \n" + + " - not null \n" + + " - 정규식 `^([01][0-9]|2[0-3]):([0-5][0-9])$`을 만족해야 함 \n" + + "- closed가 true일 때 \n" + + " - 어떤 값이 요청되던 null로 저장됨", example = "22:30") + private String close_time; + } + + public void checkDataConstraintViolation() { + checkOpenConstraintViolation(); + } + + private void checkOpenConstraintViolation() { + if (this.open.size() != 7) { + throw new BaseException(LENGTH_OF_OPENS_MUST_BE_7); + } + + Set dayOfWeeksWithoutDuplication = new HashSet<>(); + + for (koreatech.in.dto.admin.shop.request.CreateShopRequest.Open open : this.open) { + DayOfWeek dayOfWeek = open.getDay_of_week(); + Boolean closed = open.getClosed(); + String openTime = open.getOpen_time(); + String closeTime = open.getClose_time(); + + if (!closed) { + if (openTime == null || closeTime == null) { + throw new BaseException(TIME_INFORMATION_IS_REQUIRED_UNLESS_CLOSED); + } + } + + dayOfWeeksWithoutDuplication.add(dayOfWeek); + } + + if (dayOfWeeksWithoutDuplication.size() != 7) { + throw new BaseException(DUPLICATE_DAY_OF_WEEK_INFORMATION_EXISTS); + } + } +} diff --git a/src/main/java/koreatech/in/service/OwnerShopService.java b/src/main/java/koreatech/in/service/OwnerShopService.java index 85043079..d4d67f9f 100644 --- a/src/main/java/koreatech/in/service/OwnerShopService.java +++ b/src/main/java/koreatech/in/service/OwnerShopService.java @@ -2,15 +2,22 @@ import koreatech.in.dto.normal.shop.request.CreateMenuCategoryRequest; import koreatech.in.dto.normal.shop.request.CreateMenuRequest; +import koreatech.in.dto.normal.shop.request.CreateShopRequest; import koreatech.in.dto.normal.shop.request.UpdateMenuRequest; import koreatech.in.dto.normal.shop.request.UpdateShopRequest; -import koreatech.in.dto.normal.shop.response.*; +import koreatech.in.dto.normal.shop.response.AllMenuCategoriesOfShopResponse; +import koreatech.in.dto.normal.shop.response.AllMenusOfShopResponse; +import koreatech.in.dto.normal.shop.response.AllShopsOfOwnerResponse; +import koreatech.in.dto.normal.shop.response.MenuResponse; +import koreatech.in.dto.normal.shop.response.ShopResponse; public interface OwnerShopService { ShopResponse getShop(Integer shopId); AllShopsOfOwnerResponse getAllShopsOfOwner(); + void createShop(CreateShopRequest request); + void updateShop(Integer shopId, UpdateShopRequest request); void createMenuCategory(Integer shopId, CreateMenuCategoryRequest request); diff --git a/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java b/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java index 377fc693..fa9b66a8 100644 --- a/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java +++ b/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java @@ -4,6 +4,7 @@ import koreatech.in.domain.User.owner.Owner; import koreatech.in.dto.normal.shop.request.CreateMenuCategoryRequest; import koreatech.in.dto.normal.shop.request.CreateMenuRequest; +import koreatech.in.dto.normal.shop.request.CreateShopRequest; import koreatech.in.dto.normal.shop.request.UpdateMenuRequest; import koreatech.in.dto.normal.shop.request.UpdateShopRequest; import koreatech.in.dto.normal.shop.response.*; @@ -48,6 +49,11 @@ public AllShopsOfOwnerResponse getAllShopsOfOwner() { return AllShopsOfOwnerResponse.from(shopMapper.getShopProfilesByOwnerId(owner.getId())); } + @Override + public void createShop(CreateShopRequest request) { + + } + @Override public void updateShop(Integer shopId, UpdateShopRequest request) { Shop existingShop = getShopById(shopId); From 597ea5d8406fcb6d4c4e9cdbe2af7debd77fd8eb Mon Sep 17 00:00:00 2001 From: songsunkook Date: Mon, 22 May 2023 12:25:44 +0900 Subject: [PATCH 02/17] =?UTF-8?q?refactor:=20ResponseStatus=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/koreatech/in/controller/OwnerShopController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/koreatech/in/controller/OwnerShopController.java b/src/main/java/koreatech/in/controller/OwnerShopController.java index b4577492..7f131365 100644 --- a/src/main/java/koreatech/in/controller/OwnerShopController.java +++ b/src/main/java/koreatech/in/controller/OwnerShopController.java @@ -53,13 +53,14 @@ public class OwnerShopController { "- 액세스 토큰이 변경되었을 때 (code: 100005)", response = ExceptionResponse.class), @ApiResponse(code = 403, message = "- 권한이 없을 때 (code: 100003)", response = ExceptionResponse.class) }) + @ResponseStatus(HttpStatus.CREATED) @RequestMapping(value = "", method = RequestMethod.POST) public @ResponseBody ResponseEntity createShop(@ApiParam(name = "상점 정보 JSON", required = true) @RequestBody @Valid CreateShopRequest request, BindingResult bindingResult) { request.checkDataConstraintViolation(); // javax validation으로 판단할 수 없는 제약조건 검사 ownerShopService.createShop(request); - return new ResponseEntity<>(HttpStatus.OK); + return new ResponseEntity<>(HttpStatus.CREATED); } @ApiOperation(value = "상점 조회", notes = "- 사장님 권한만 허용\n- 인증 정보에 대한 신원이 해당 상점의 점주가 아니라면 403(Forbidden) 응답", authorizations = {@Authorization("Authorization")}) From 88c878524b4ace9b3c87c88374c640c5ebd32528 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Mon, 22 May 2023 12:27:38 +0900 Subject: [PATCH 03/17] =?UTF-8?q?fix:=20Request=20DTO=20=EC=9E=98=EB=AA=BB?= =?UTF-8?q?=EB=90=9C=20=EC=B0=B8=EC=A1=B0=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/dto/normal/shop/request/CreateShopRequest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java b/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java index 614dc440..36259941 100644 --- a/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java +++ b/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java @@ -36,7 +36,7 @@ public class CreateShopRequest { "- not null \n" + "- 리스트의 길이는 7(1주일 요일 개수) 이어야 함 \n" + "- day_of_week은 각각 `MONDAY`, `TUESDAY`, `WEDNESDAY`, `THURSDAY`, `FRIDAY`, `SATURDAY`, `SUNDAY` 이어야 함", required = true) - private List open = new ArrayList<>(); + private List open = new ArrayList<>(); @Size(min = 1, max = 100, message = "주소의 길이는 1자 이상 100자 이하입니다.") @NotNull(message = "주소는 필수입니다.") @@ -126,7 +126,7 @@ private void checkOpenConstraintViolation() { Set dayOfWeeksWithoutDuplication = new HashSet<>(); - for (koreatech.in.dto.admin.shop.request.CreateShopRequest.Open open : this.open) { + for (Open open : this.open) { DayOfWeek dayOfWeek = open.getDay_of_week(); Boolean closed = open.getClosed(); String openTime = open.getOpen_time(); From e1296aab6d85191718fe968dfe901fb29ea655f6 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Mon, 22 May 2023 14:46:15 +0900 Subject: [PATCH 04/17] =?UTF-8?q?feat:=20createShop=20service=20method=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapstruct/normal/shop/ShopConverter.java | 5 +++ .../normal/shop/ShopOpenConverter.java | 6 +++- .../in/service/OwnerShopServiceImpl.java | 35 ++++++++++++++++++- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/main/java/koreatech/in/mapstruct/normal/shop/ShopConverter.java b/src/main/java/koreatech/in/mapstruct/normal/shop/ShopConverter.java index de03dcc5..245e1585 100644 --- a/src/main/java/koreatech/in/mapstruct/normal/shop/ShopConverter.java +++ b/src/main/java/koreatech/in/mapstruct/normal/shop/ShopConverter.java @@ -1,6 +1,8 @@ package koreatech.in.mapstruct.normal.shop; +import koreatech.in.domain.Shop.Shop; import koreatech.in.domain.Shop.ShopProfile; +import koreatech.in.dto.normal.shop.request.CreateShopRequest; import koreatech.in.dto.normal.shop.response.AllShopsResponse; import koreatech.in.dto.normal.shop.response.ShopResponse; import org.mapstruct.Mapper; @@ -15,4 +17,7 @@ public interface ShopConverter { @Mapping(target = "category_ids", expression = "java(shopProfile.getShopCategoryIds())") AllShopsResponse.Shop toAllShopsResponse$Shop(ShopProfile shopProfile); + + @Mapping(source = "ownerId", target = "shop_id") + Shop toShop(CreateShopRequest request, Integer ownerId); } diff --git a/src/main/java/koreatech/in/mapstruct/normal/shop/ShopOpenConverter.java b/src/main/java/koreatech/in/mapstruct/normal/shop/ShopOpenConverter.java index fe64e94d..0ac16f57 100644 --- a/src/main/java/koreatech/in/mapstruct/normal/shop/ShopOpenConverter.java +++ b/src/main/java/koreatech/in/mapstruct/normal/shop/ShopOpenConverter.java @@ -1,6 +1,7 @@ package koreatech.in.mapstruct.normal.shop; import koreatech.in.domain.Shop.ShopOpen; +import koreatech.in.dto.normal.shop.request.CreateShopRequest; import koreatech.in.dto.normal.shop.request.UpdateShopRequest; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -11,5 +12,8 @@ public interface ShopOpenConverter { ShopOpenConverter INSTANCE = Mappers.getMapper(ShopOpenConverter.class); @Mapping(source = "shopId", target = "shop_id") - ShopOpen toShopOpen(UpdateShopRequest.Open open, Integer shopId); + ShopOpen toShopOpenForCreate(CreateShopRequest.Open open, Integer shopId); + + @Mapping(source = "shopId", target = "shop_id") + ShopOpen toShopOpenForUpdate(UpdateShopRequest.Open open, Integer shopId); } diff --git a/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java b/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java index fa9b66a8..d70f4fc4 100644 --- a/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java +++ b/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java @@ -51,7 +51,40 @@ public AllShopsOfOwnerResponse getAllShopsOfOwner() { @Override public void createShop(CreateShopRequest request) { + Owner owner = (Owner) jwtValidator.validate(); + + /* + INSERT 대상 테이블 + - shops + - shop_opens + - shop_category_map + - shop_images + */ + + // ======= shops 테이블 ======= + Shop shop = ShopConverter.INSTANCE.toShop(request, owner.getId()); + //shop.setOwnerId(owner.getId()); + shopMapper.createShop(shop); + // ======= shop_opens 테이블 ======= + List shopOpens = generateShopOpensAndGetForCreate(request.getOpen(), shop.getId()); + shopMapper.createShopOpens(shopOpens); + + // ======= shop_category_map 테이블 ======= + checkShopCategoriesExistInDatabase(request.getCategory_ids()); + + List shopCategoryMaps = generateShopCategoryMapsAndGet(shop.getId(), request.getCategory_ids()); + shopMapper.createShopCategoryMaps(shopCategoryMaps); + + // ======= shop_images 테이블 ======= + List shopImages = generateShopImagesAndGet(shop.getId(), request.getImage_urls()); + shopMapper.createShopImages(shopImages); + } + + private List generateShopOpensAndGetForCreate(List opens, Integer shopId) { + return opens.stream() + .map(open -> ShopOpenConverter.INSTANCE.toShopOpenForCreate(open, shopId)) + .collect(Collectors.toList()); } @Override @@ -111,7 +144,7 @@ public void updateShop(Integer shopId, UpdateShopRequest request) { private List generateShopOpensAndGetForUpdate(List opens, Integer shopId) { return opens.stream() - .map(open -> ShopOpenConverter.INSTANCE.toShopOpen(open, shopId)) + .map(open -> ShopOpenConverter.INSTANCE.toShopOpenForUpdate(open, shopId)) .collect(Collectors.toList()); } From 02babb53ffaf1175558f596ced83850526b0f67a Mon Sep 17 00:00:00 2001 From: songsunkook Date: Mon, 22 May 2023 15:10:10 +0900 Subject: [PATCH 05/17] =?UTF-8?q?feat:=20createShop=20sql=EB=AC=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koreatech/in/repository/ShopMapper.java | 4 +- .../resources/mapper/normal/ShopMapper.xml | 43 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/main/java/koreatech/in/repository/ShopMapper.java b/src/main/java/koreatech/in/repository/ShopMapper.java index 91678bdb..d39119db 100644 --- a/src/main/java/koreatech/in/repository/ShopMapper.java +++ b/src/main/java/koreatech/in/repository/ShopMapper.java @@ -22,6 +22,8 @@ public interface ShopMapper { List getShopByOwnerId(@Param("ownerId") Integer ownerId); + void createShop(@Param("shop") Shop shop); + void updateShop(@Param("shop") Shop shop); void updateShopOpens(@Param("shopOpens") List shopOpens); @@ -85,4 +87,4 @@ public interface ShopMapper { ShopMenu getMenuById(@Param("id") Integer id); void deleteMenuById(@Param("id") Integer id); -} \ No newline at end of file +} diff --git a/src/main/resources/mapper/normal/ShopMapper.xml b/src/main/resources/mapper/normal/ShopMapper.xml index 75665e61..06daa7a0 100644 --- a/src/main/resources/mapper/normal/ShopMapper.xml +++ b/src/main/resources/mapper/normal/ShopMapper.xml @@ -272,6 +272,47 @@ AND `is_deleted` = 0 + + INSERT INTO `koin`.`shops` ( + `owner_id`, + `name`, + `internal_name`, + `chosung`, + `phone`, + `address`, + `description`, + `delivery`, + `delivery_price`, + `pay_card`, + `pay_bank`, + `is_deleted`, + `created_at`, + `updated_at`, + `is_event`, + `remarks`, + `hit` + ) + VALUES ( + #{shop.owner_id}, + #{shop.name}, + #{shop.internal_name}, + #{shop.chosung}, + #{shop.phone}, + #{shop.address}, + #{shop.description}, + #{shop.delivery}, + #{shop.delivery_price}, + #{shop.pay_card}, + #{shop.pay_bank}, + #{shop.is_deleted}, + #{shop.created_at}, + #{shop.updated_at}, + #{shop.is_event}, + #{shop.remarks}, + #{shop.hit} + ) + + UPDATE `koin`.`shops` SET @@ -685,4 +726,4 @@ - \ No newline at end of file + From 411e8e707fa39883dd975308cc71ea32b7fc77a6 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Mon, 22 May 2023 15:21:43 +0900 Subject: [PATCH 06/17] =?UTF-8?q?feat:=20createShopOpens=20sql=EB=AC=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koreatech/in/repository/ShopMapper.java | 2 ++ .../resources/mapper/normal/ShopMapper.xml | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/main/java/koreatech/in/repository/ShopMapper.java b/src/main/java/koreatech/in/repository/ShopMapper.java index d39119db..e9aed464 100644 --- a/src/main/java/koreatech/in/repository/ShopMapper.java +++ b/src/main/java/koreatech/in/repository/ShopMapper.java @@ -26,6 +26,8 @@ public interface ShopMapper { void updateShop(@Param("shop") Shop shop); + void createShopOpens(@Param("shopOpens") List shopOpens); + void updateShopOpens(@Param("shopOpens") List shopOpens); ShopCategory getShopCategoryById(@Param("id") Integer id); diff --git a/src/main/resources/mapper/normal/ShopMapper.xml b/src/main/resources/mapper/normal/ShopMapper.xml index 06daa7a0..dbd366f0 100644 --- a/src/main/resources/mapper/normal/ShopMapper.xml +++ b/src/main/resources/mapper/normal/ShopMapper.xml @@ -330,6 +330,33 @@ `id` = #{shop.id} + + INSERT INTO `koin`.`shop_opens` ( + `shop_id`, + `day_of_week`, + `closed`, + `open_time`, + `close_time`, + `is_deleted`, + `created_at`, + `updated_at` + ) + VALUES ( + + ( + #{shopOpen.shop_id}, + #{shopOpen.day_of_week}, + #{shopOpen.closed}, + #{shopOpen.open_time}, + #{shopOpen.close_time}, + #{shopOpen.is_deleted}, + #{shopOpen.created_at}, + #{shopOpen.updated_at} + ) + + ) + + UPDATE `koin`.`shop_opens` From fa17e62deacecbfedab0c3108be896a413aa9030 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Thu, 25 May 2023 15:55:13 +0900 Subject: [PATCH 07/17] =?UTF-8?q?fix:=20=EC=A0=95=EC=83=81=20=EB=8F=99?= =?UTF-8?q?=EC=9E=91=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Response를 ShopResponse에서 EmptyResponse로 변경하여 아무것도 반환하지 않도록 변경 2. CreateShop 요청에 대한 DTO to Domain 변환을 update 메서드를 추가하여 진행 3. ShopConverter 오타 수정 4. SQL문 수정 - 불필요한 insert value 제거 - selectkey를 통하여 insert 완료된 행의 id를 반환하도록 작성 --- .../in/controller/OwnerShopController.java | 5 +- .../java/koreatech/in/domain/Shop/Shop.java | 14 ++++++ .../mapstruct/normal/shop/ShopConverter.java | 2 +- .../in/service/OwnerShopServiceImpl.java | 2 +- .../resources/mapper/normal/ShopMapper.xml | 48 +++++++------------ 5 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/main/java/koreatech/in/controller/OwnerShopController.java b/src/main/java/koreatech/in/controller/OwnerShopController.java index 7f131365..1b0c2d7b 100644 --- a/src/main/java/koreatech/in/controller/OwnerShopController.java +++ b/src/main/java/koreatech/in/controller/OwnerShopController.java @@ -46,17 +46,18 @@ public class OwnerShopController { // =============================================== 상점 ================================================= - @ApiOperation(value = "상점 생성", notes = "- 사장님 권한만 허용\n- 인증 정보에 대한 신원이 해당 상점의 점주가 아니라면 403(Forbidden) 응답", authorizations = {@Authorization("Authorization")}) + @ApiOperation(value = "상점 생성", notes = "- 사장님 권한만 허용", authorizations = {@Authorization("Authorization")}) @ApiResponses({ @ApiResponse(code = 401, message = "- 잘못된 접근일 때 (code: 100001) \n" + "- 액세스 토큰이 만료되었을 때 (code: 100004) \n" + "- 액세스 토큰이 변경되었을 때 (code: 100005)", response = ExceptionResponse.class), @ApiResponse(code = 403, message = "- 권한이 없을 때 (code: 100003)", response = ExceptionResponse.class) }) + @ParamValid @ResponseStatus(HttpStatus.CREATED) @RequestMapping(value = "", method = RequestMethod.POST) public @ResponseBody - ResponseEntity createShop(@ApiParam(name = "상점 정보 JSON", required = true) @RequestBody @Valid CreateShopRequest request, BindingResult bindingResult) { + ResponseEntity createShop(@ApiParam(name = "상점 정보 JSON", required = true) @RequestBody @Valid CreateShopRequest request, BindingResult bindingResult) { request.checkDataConstraintViolation(); // javax validation으로 판단할 수 없는 제약조건 검사 ownerShopService.createShop(request); diff --git a/src/main/java/koreatech/in/domain/Shop/Shop.java b/src/main/java/koreatech/in/domain/Shop/Shop.java index 5dadc039..4b78b7e5 100644 --- a/src/main/java/koreatech/in/domain/Shop/Shop.java +++ b/src/main/java/koreatech/in/domain/Shop/Shop.java @@ -1,6 +1,7 @@ package koreatech.in.domain.Shop; import koreatech.in.dto.admin.shop.request.UpdateShopRequest; +import koreatech.in.dto.normal.shop.request.CreateShopRequest; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -79,6 +80,19 @@ public void update(koreatech.in.dto.normal.shop.request.UpdateShopRequest reques this.chosung = this.internal_name.substring(0, 1); } + public void update(CreateShopRequest request) { + this.name = request.getName(); + this.phone = request.getPhone(); + this.address = request.getAddress(); + this.description = request.getDescription(); + this.delivery = request.getDelivery(); + this.delivery_price = request.getDelivery_price(); + this.pay_card = request.getPay_card(); + this.pay_bank = request.getPay_bank(); + this.internal_name = this.name.replace(" ", "").toLowerCase(); + this.chosung = this.internal_name.substring(0, 1); + } + public boolean hasSameOwnerId(Integer ownerId) { if (this.owner_id == null) { return false; diff --git a/src/main/java/koreatech/in/mapstruct/normal/shop/ShopConverter.java b/src/main/java/koreatech/in/mapstruct/normal/shop/ShopConverter.java index 245e1585..0e904530 100644 --- a/src/main/java/koreatech/in/mapstruct/normal/shop/ShopConverter.java +++ b/src/main/java/koreatech/in/mapstruct/normal/shop/ShopConverter.java @@ -18,6 +18,6 @@ public interface ShopConverter { @Mapping(target = "category_ids", expression = "java(shopProfile.getShopCategoryIds())") AllShopsResponse.Shop toAllShopsResponse$Shop(ShopProfile shopProfile); - @Mapping(source = "ownerId", target = "shop_id") + @Mapping(source = "ownerId", target = "owner_id") Shop toShop(CreateShopRequest request, Integer ownerId); } diff --git a/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java b/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java index d70f4fc4..9d4272c0 100644 --- a/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java +++ b/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java @@ -63,7 +63,7 @@ public void createShop(CreateShopRequest request) { // ======= shops 테이블 ======= Shop shop = ShopConverter.INSTANCE.toShop(request, owner.getId()); - //shop.setOwnerId(owner.getId()); + shop.update(request); shopMapper.createShop(shop); // ======= shop_opens 테이블 ======= diff --git a/src/main/resources/mapper/normal/ShopMapper.xml b/src/main/resources/mapper/normal/ShopMapper.xml index dbd366f0..a4dcf310 100644 --- a/src/main/resources/mapper/normal/ShopMapper.xml +++ b/src/main/resources/mapper/normal/ShopMapper.xml @@ -273,7 +273,7 @@ - INSERT INTO `koin`.`shops` ( + INSERT IGNORE INTO `koin`.`shops` ( `owner_id`, `name`, `internal_name`, @@ -284,13 +284,7 @@ `delivery`, `delivery_price`, `pay_card`, - `pay_bank`, - `is_deleted`, - `created_at`, - `updated_at`, - `is_event`, - `remarks`, - `hit` + `pay_bank` ) VALUES ( #{shop.owner_id}, @@ -303,14 +297,11 @@ #{shop.delivery}, #{shop.delivery_price}, #{shop.pay_card}, - #{shop.pay_bank}, - #{shop.is_deleted}, - #{shop.created_at}, - #{shop.updated_at}, - #{shop.is_event}, - #{shop.remarks}, - #{shop.hit} + #{shop.pay_bank} ) + + SELECT LAST_INSERT_ID() + @@ -330,31 +321,24 @@ `id` = #{shop.id} - - INSERT INTO `koin`.`shop_opens` ( + + INSERT IGNORE INTO `koin`.`shop_opens` ( `shop_id`, `day_of_week`, `closed`, `open_time`, - `close_time`, - `is_deleted`, - `created_at`, - `updated_at` + `close_time` ) - VALUES ( - + VALUES + ( - #{shopOpen.shop_id}, - #{shopOpen.day_of_week}, - #{shopOpen.closed}, - #{shopOpen.open_time}, - #{shopOpen.close_time}, - #{shopOpen.is_deleted}, - #{shopOpen.created_at}, - #{shopOpen.updated_at} + #{item.shop_id}, + #{item.day_of_week}, + #{item.closed}, + #{item.open_time}, + #{item.close_time} ) - ) From ae97178b19df6f643cc510e9b5eab153388f4b77 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Sat, 27 May 2023 16:03:43 +0900 Subject: [PATCH 08/17] =?UTF-8?q?refactor:=20Shop.update=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 메서드명 변경 (다중정의 해제) 2. 파라미터 제거 --- .../java/koreatech/in/domain/Shop/Shop.java | 16 ++----- .../in/service/OwnerShopServiceImpl.java | 46 ++++++++++++++----- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/main/java/koreatech/in/domain/Shop/Shop.java b/src/main/java/koreatech/in/domain/Shop/Shop.java index 4b78b7e5..cf5a75ae 100644 --- a/src/main/java/koreatech/in/domain/Shop/Shop.java +++ b/src/main/java/koreatech/in/domain/Shop/Shop.java @@ -1,14 +1,14 @@ package koreatech.in.domain.Shop; +import java.util.Date; +import java.util.Objects; + import koreatech.in.dto.admin.shop.request.UpdateShopRequest; -import koreatech.in.dto.normal.shop.request.CreateShopRequest; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.*; - @Getter @Builder @NoArgsConstructor @AllArgsConstructor @@ -80,15 +80,7 @@ public void update(koreatech.in.dto.normal.shop.request.UpdateShopRequest reques this.chosung = this.internal_name.substring(0, 1); } - public void update(CreateShopRequest request) { - this.name = request.getName(); - this.phone = request.getPhone(); - this.address = request.getAddress(); - this.description = request.getDescription(); - this.delivery = request.getDelivery(); - this.delivery_price = request.getDelivery_price(); - this.pay_card = request.getPay_card(); - this.pay_bank = request.getPay_bank(); + public void informationUpdate() { this.internal_name = this.name.replace(" ", "").toLowerCase(); this.chosung = this.internal_name.substring(0, 1); } diff --git a/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java b/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java index 9d4272c0..9aa919fc 100644 --- a/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java +++ b/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java @@ -1,27 +1,49 @@ package koreatech.in.service; -import koreatech.in.domain.Shop.*; +import static koreatech.in.exception.ExceptionInformation.FORBIDDEN; +import static koreatech.in.exception.ExceptionInformation.SHOP_CATEGORY_NOT_FOUND; +import static koreatech.in.exception.ExceptionInformation.SHOP_MENU_CATEGORY_MAXIMUM_EXCEED; +import static koreatech.in.exception.ExceptionInformation.SHOP_MENU_CATEGORY_NAME_DUPLICATE; +import static koreatech.in.exception.ExceptionInformation.SHOP_MENU_CATEGORY_NOT_FOUND; +import static koreatech.in.exception.ExceptionInformation.SHOP_MENU_NOT_FOUND; +import static koreatech.in.exception.ExceptionInformation.SHOP_MENU_USING_CATEGORY_EXIST; +import static koreatech.in.exception.ExceptionInformation.SHOP_NOT_FOUND; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import koreatech.in.domain.Shop.Shop; +import koreatech.in.domain.Shop.ShopCategoryMap; +import koreatech.in.domain.Shop.ShopImage; +import koreatech.in.domain.Shop.ShopMenu; +import koreatech.in.domain.Shop.ShopMenuCategory; +import koreatech.in.domain.Shop.ShopMenuCategoryMap; +import koreatech.in.domain.Shop.ShopMenuDetail; +import koreatech.in.domain.Shop.ShopMenuImage; +import koreatech.in.domain.Shop.ShopMenuProfile; +import koreatech.in.domain.Shop.ShopOpen; +import koreatech.in.domain.Shop.ShopProfile; import koreatech.in.domain.User.owner.Owner; import koreatech.in.dto.normal.shop.request.CreateMenuCategoryRequest; import koreatech.in.dto.normal.shop.request.CreateMenuRequest; import koreatech.in.dto.normal.shop.request.CreateShopRequest; import koreatech.in.dto.normal.shop.request.UpdateMenuRequest; import koreatech.in.dto.normal.shop.request.UpdateShopRequest; -import koreatech.in.dto.normal.shop.response.*; +import koreatech.in.dto.normal.shop.response.AllMenuCategoriesOfShopResponse; +import koreatech.in.dto.normal.shop.response.AllMenusOfShopResponse; +import koreatech.in.dto.normal.shop.response.AllShopsOfOwnerResponse; +import koreatech.in.dto.normal.shop.response.MenuResponse; +import koreatech.in.dto.normal.shop.response.ShopResponse; import koreatech.in.exception.BaseException; import koreatech.in.mapstruct.normal.shop.ShopConverter; import koreatech.in.mapstruct.normal.shop.ShopMenuConverter; import koreatech.in.mapstruct.normal.shop.ShopOpenConverter; import koreatech.in.repository.ShopMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -import static koreatech.in.exception.ExceptionInformation.*; @Service @Transactional @@ -63,7 +85,7 @@ public void createShop(CreateShopRequest request) { // ======= shops 테이블 ======= Shop shop = ShopConverter.INSTANCE.toShop(request, owner.getId()); - shop.update(request); + shop.informationUpdate(); shopMapper.createShop(shop); // ======= shop_opens 테이블 ======= From 185ec80cb10f8549e2227f07f28d800a5c68b15c Mon Sep 17 00:00:00 2001 From: songsunkook Date: Mon, 29 May 2023 22:19:04 +0900 Subject: [PATCH 09/17] =?UTF-8?q?style:=20=EA=B0=80=EC=8B=9C=EC=A0=81?= =?UTF-8?q?=EC=9D=B8=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=AA=85=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/koreatech/in/domain/Shop/Shop.java | 2 +- src/main/java/koreatech/in/service/OwnerShopServiceImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/koreatech/in/domain/Shop/Shop.java b/src/main/java/koreatech/in/domain/Shop/Shop.java index cf5a75ae..e2613713 100644 --- a/src/main/java/koreatech/in/domain/Shop/Shop.java +++ b/src/main/java/koreatech/in/domain/Shop/Shop.java @@ -80,7 +80,7 @@ public void update(koreatech.in.dto.normal.shop.request.UpdateShopRequest reques this.chosung = this.internal_name.substring(0, 1); } - public void informationUpdate() { + public void nameUpdate() { this.internal_name = this.name.replace(" ", "").toLowerCase(); this.chosung = this.internal_name.substring(0, 1); } diff --git a/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java b/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java index 537498f5..80a52b67 100644 --- a/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java +++ b/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java @@ -86,7 +86,7 @@ public void createShop(CreateShopRequest request) { // ======= shops 테이블 ======= Shop shop = ShopConverter.INSTANCE.toShop(request, owner.getId()); - shop.informationUpdate(); + shop.nameUpdate(); shopMapper.createShop(shop); // ======= shop_opens 테이블 ======= From d6879fc9211f3adc4d84c0451af7d71d8109dae9 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Fri, 2 Jun 2023 17:40:29 +0900 Subject: [PATCH 10/17] =?UTF-8?q?docs:=20=EB=B0=B0=EB=8B=AC=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1=20=EC=95=88=EB=82=B4=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shop/request/CreateShopRequest.java | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java b/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java index 36259941..05648972 100644 --- a/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java +++ b/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java @@ -1,18 +1,28 @@ package koreatech.in.dto.normal.shop.request; +import static koreatech.in.exception.ExceptionInformation.DUPLICATE_DAY_OF_WEEK_INFORMATION_EXISTS; +import static koreatech.in.exception.ExceptionInformation.LENGTH_OF_OPENS_MUST_BE_7; +import static koreatech.in.exception.ExceptionInformation.TIME_INFORMATION_IS_REQUIRED_UNLESS_CLOSED; + +import java.time.DayOfWeek; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.PositiveOrZero; +import javax.validation.constraints.Size; + import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import koreatech.in.exception.BaseException; import lombok.Getter; import lombok.Setter; -import javax.validation.Valid; -import javax.validation.constraints.*; -import java.time.DayOfWeek; -import java.util.*; - -import static koreatech.in.exception.ExceptionInformation.*; - @Getter @Setter @ApiModel("CreateShopRequest") public class CreateShopRequest { @@ -45,7 +55,7 @@ public class CreateShopRequest { "- 1자 이상 100자 이하", example = "충청남도 천안시 동남구 병천면 충절로 1600", required = true) private String address; - @PositiveOrZero(message = "배달 금액은 0원 이상 2147483647원 이하여야합니다.") + @PositiveOrZero(message = "배달 금액은 0원 이상이어야 합니다.") @ApiModelProperty(notes = "배달 금액 \n" + "- 0 이상 2147483647 이하 \n" + "- null일 경우 0으로 저장됨", example = "1000") From f6f4047d65e14fea265beffc405b1ec891794404 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Fri, 2 Jun 2023 18:02:55 +0900 Subject: [PATCH 11/17] =?UTF-8?q?docs:=20Swagger=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=EC=98=88=EC=8B=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Swagger example value에 리스트가 문자열로 표기되는 현상 수정 --- .../koreatech/in/dto/normal/shop/request/CreateShopRequest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java b/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java index 05648972..bb24f9e5 100644 --- a/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java +++ b/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java @@ -84,7 +84,7 @@ public class CreateShopRequest { @NotEmpty(message = "소속시킬 상점 카테고리는 최소 1개 선택하여야합니다.") @ApiModelProperty(notes = "상점 카테고리 고유 id 리스트 \n" + "- not null \n" + - "- 최소 1개", example = "[1, 4]", required = true) + "- 최소 1개", required = true) private List category_ids = new ArrayList<>(); @Size(max = 10, message = "상점 이미지 개수 제한은 최대 10개입니다.") From f38916126684bc556979ffa412fa9b5376796cd1 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Mon, 5 Jun 2023 00:05:45 +0900 Subject: [PATCH 12/17] =?UTF-8?q?refactor:=20xss=20check=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/controller/OwnerShopController.java | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/main/java/koreatech/in/controller/OwnerShopController.java b/src/main/java/koreatech/in/controller/OwnerShopController.java index 1b0c2d7b..c0c53eeb 100644 --- a/src/main/java/koreatech/in/controller/OwnerShopController.java +++ b/src/main/java/koreatech/in/controller/OwnerShopController.java @@ -1,5 +1,19 @@ package koreatech.in.controller; +import javax.validation.Valid; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; @@ -21,20 +35,10 @@ import koreatech.in.dto.normal.shop.response.AllShopsOfOwnerResponse; import koreatech.in.dto.normal.shop.response.MenuResponse; import koreatech.in.dto.normal.shop.response.ShopResponse; +import koreatech.in.exception.BaseException; +import koreatech.in.exception.ExceptionInformation; import koreatech.in.service.OwnerShopService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; - -import javax.validation.Valid; +import koreatech.in.util.StringXssChecker; @Auth(role = Auth.Role.OWNER, authority = Auth.Authority.SHOP) @Api(tags = "(Normal) Owner Shop", description = "상점 (점주 전용)") @@ -58,6 +62,12 @@ public class OwnerShopController { @RequestMapping(value = "", method = RequestMethod.POST) public @ResponseBody ResponseEntity createShop(@ApiParam(name = "상점 정보 JSON", required = true) @RequestBody @Valid CreateShopRequest request, BindingResult bindingResult) { + try { + request = StringXssChecker.xssCheck(request, request.getClass().newInstance()); + } catch (Exception exception) { + throw new BaseException(ExceptionInformation.REQUEST_DATA_INVALID); + } + request.checkDataConstraintViolation(); // javax validation으로 판단할 수 없는 제약조건 검사 ownerShopService.createShop(request); From 674d8cef44469b81c3bf5d3b7cac3d5fc5a5e850 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Mon, 5 Jun 2023 00:24:44 +0900 Subject: [PATCH 13/17] =?UTF-8?q?refactor:=20for-each=EB=A5=BC=20stream?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shop/request/CreateShopRequest.java | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java b/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java index bb24f9e5..24684ed8 100644 --- a/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java +++ b/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java @@ -6,9 +6,7 @@ import java.time.DayOfWeek; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set; import javax.validation.Valid; import javax.validation.constraints.NotEmpty; @@ -134,24 +132,20 @@ private void checkOpenConstraintViolation() { throw new BaseException(LENGTH_OF_OPENS_MUST_BE_7); } - Set dayOfWeeksWithoutDuplication = new HashSet<>(); + boolean hasEmptyTimeInformation = this.open.stream() + .filter(open -> !open.getClosed()) + .anyMatch(open -> open.getOpen_time() == null || open.getClose_time() == null); - for (Open open : this.open) { - DayOfWeek dayOfWeek = open.getDay_of_week(); - Boolean closed = open.getClosed(); - String openTime = open.getOpen_time(); - String closeTime = open.getClose_time(); - - if (!closed) { - if (openTime == null || closeTime == null) { - throw new BaseException(TIME_INFORMATION_IS_REQUIRED_UNLESS_CLOSED); - } - } - - dayOfWeeksWithoutDuplication.add(dayOfWeek); + if (hasEmptyTimeInformation) { + throw new BaseException(TIME_INFORMATION_IS_REQUIRED_UNLESS_CLOSED); } - if (dayOfWeeksWithoutDuplication.size() != 7) { + boolean hasDuplicateDayOfWeek = this.open.stream() + .map(Open::getDay_of_week) + .distinct() + .count() != 7; + + if (hasDuplicateDayOfWeek) { throw new BaseException(DUPLICATE_DAY_OF_WEEK_INFORMATION_EXISTS); } } From ac9bb9048862f9c9210ce806b0089309e21593f1 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Mon, 5 Jun 2023 00:29:25 +0900 Subject: [PATCH 14/17] =?UTF-8?q?refactor:=20SQL=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/mapper/normal/ShopMapper.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/mapper/normal/ShopMapper.xml b/src/main/resources/mapper/normal/ShopMapper.xml index 0d6e0b16..52189d2b 100644 --- a/src/main/resources/mapper/normal/ShopMapper.xml +++ b/src/main/resources/mapper/normal/ShopMapper.xml @@ -273,7 +273,7 @@ - INSERT IGNORE INTO `koin`.`shops` ( + INSERT INTO `koin`.`shops` ( `owner_id`, `name`, `internal_name`, @@ -322,7 +322,7 @@ - INSERT IGNORE INTO `koin`.`shop_opens` ( + INSERT INTO `koin`.`shop_opens` ( `shop_id`, `day_of_week`, `closed`, From 3c55e9d3c653e5d5ac71669d7c44ec5db27c78d3 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Mon, 5 Jun 2023 00:52:34 +0900 Subject: [PATCH 15/17] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/service/OwnerShopServiceImpl.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java b/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java index 80a52b67..bf34cf4b 100644 --- a/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java +++ b/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java @@ -74,32 +74,33 @@ public AllShopsOfOwnerResponse getAllShopsOfOwner() { @Override public void createShop(CreateShopRequest request) { - Owner owner = (Owner) jwtValidator.validate(); - - /* - INSERT 대상 테이블 - - shops - - shop_opens - - shop_category_map - - shop_images - */ + Shop shop = createShopsTable(request); + createShopOpensTable(request, shop); + createShopCategoryMapTable(request, shop); + createShopImages(request, shop); + } - // ======= shops 테이블 ======= + private Shop createShopsTable(CreateShopRequest request) { + Owner owner = (Owner) jwtValidator.validate(); Shop shop = ShopConverter.INSTANCE.toShop(request, owner.getId()); shop.nameUpdate(); shopMapper.createShop(shop); - // ======= shop_opens 테이블 ======= + return shop; + } + + private void createShopOpensTable(CreateShopRequest request, Shop shop) { List shopOpens = generateShopOpensAndGetForCreate(request.getOpen(), shop.getId()); shopMapper.createShopOpens(shopOpens); + } - // ======= shop_category_map 테이블 ======= + private void createShopCategoryMapTable(CreateShopRequest request, Shop shop) { checkShopCategoriesExistInDatabase(request.getCategory_ids()); - List shopCategoryMaps = generateShopCategoryMapsAndGet(shop.getId(), request.getCategory_ids()); shopMapper.createShopCategoryMaps(shopCategoryMaps); + } - // ======= shop_images 테이블 ======= + private void createShopImages(CreateShopRequest request, Shop shop) { List shopImages = generateShopImagesAndGet(shop.getId(), request.getImage_urls()); shopMapper.createShopImages(shopImages); } From cc27ea953e21beca9092c9fabdabc9963d71b8a5 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Mon, 5 Jun 2023 01:02:58 +0900 Subject: [PATCH 16/17] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/service/OwnerShopServiceImpl.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java b/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java index bf34cf4b..1b659a6c 100644 --- a/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java +++ b/src/main/java/koreatech/in/service/OwnerShopServiceImpl.java @@ -90,22 +90,22 @@ private Shop createShopsTable(CreateShopRequest request) { } private void createShopOpensTable(CreateShopRequest request, Shop shop) { - List shopOpens = generateShopOpensAndGetForCreate(request.getOpen(), shop.getId()); + List shopOpens = generateShopOpens(request.getOpen(), shop.getId()); shopMapper.createShopOpens(shopOpens); } private void createShopCategoryMapTable(CreateShopRequest request, Shop shop) { - checkShopCategoriesExistInDatabase(request.getCategory_ids()); - List shopCategoryMaps = generateShopCategoryMapsAndGet(shop.getId(), request.getCategory_ids()); + shopCategoriesExist(request.getCategory_ids()); + List shopCategoryMaps = generateShopCategoryMaps(shop.getId(), request.getCategory_ids()); shopMapper.createShopCategoryMaps(shopCategoryMaps); } private void createShopImages(CreateShopRequest request, Shop shop) { - List shopImages = generateShopImagesAndGet(shop.getId(), request.getImage_urls()); + List shopImages = generateShopImages(shop.getId(), request.getImage_urls()); shopMapper.createShopImages(shopImages); } - private List generateShopOpensAndGetForCreate(List opens, Integer shopId) { + private List generateShopOpens(List opens, Integer shopId) { return opens.stream() .map(open -> ShopOpenConverter.INSTANCE.toShopOpenForCreate(open, shopId)) .collect(Collectors.toList()); @@ -137,12 +137,12 @@ public void updateShop(Integer shopId, UpdateShopRequest request) { // ======= shop_category_map 테이블 ======= - checkShopCategoriesExistInDatabase(request.getCategory_ids()); + shopCategoriesExist(request.getCategory_ids()); List existingShopCategoryMaps = shopMapper.getShopCategoryMapsByShopId(existingShop.getId()); // IGNORE에 의하여 (shop_id, shop_category_id)가 중복일 경우는 insert가 무시된다. - List requestedCategoryMaps = generateShopCategoryMapsAndGet(existingShop.getId(), request.getCategory_ids()); + List requestedCategoryMaps = generateShopCategoryMaps(existingShop.getId(), request.getCategory_ids()); shopMapper.createShopCategoryMaps(requestedCategoryMaps); // 기존에 있던 관계들에서 요청된 관계들을 제거하면 삭제해야할 관계들을 알아낼 수 있다. @@ -155,7 +155,7 @@ public void updateShop(Integer shopId, UpdateShopRequest request) { // ======= shop_images 테이블 ======= List existingShopImages = shopMapper.getShopImagesByShopId(existingShop.getId()); - List requestedShopImages = generateShopImagesAndGet(existingShop.getId(), request.getImage_urls()); + List requestedShopImages = generateShopImages(existingShop.getId(), request.getImage_urls()); if (!requestedShopImages.isEmpty()) { shopMapper.createShopImages(requestedShopImages); } @@ -172,14 +172,14 @@ private List generateShopOpensAndGetForUpdate(List shopCategoryIds) { + private void shopCategoriesExist(List shopCategoryIds) { shopCategoryIds.forEach(categoryId -> { Optional.ofNullable(shopMapper.getShopCategoryById(categoryId)) .orElseThrow(() -> new BaseException(SHOP_CATEGORY_NOT_FOUND)); }); } - private List generateShopCategoryMapsAndGet(Integer shopId, List shopCategoryIds) { + private List generateShopCategoryMaps(Integer shopId, List shopCategoryIds) { return shopCategoryIds.stream() .map(shopCategoryId -> ShopCategoryMap.of(shopId, shopCategoryId)) .collect(Collectors.toList()); @@ -190,7 +190,7 @@ private List getToBeDeletedShopCategoryMaps(List generateShopImagesAndGet(Integer shopId, List imageUrls) { + private List generateShopImages(Integer shopId, List imageUrls) { return imageUrls.stream() .map(url -> ShopImage.of(shopId, url)) .collect(Collectors.toList()); From 32f84fe9fc68b5d5a03ba0ded69bf5b82d4dcbc2 Mon Sep 17 00:00:00 2001 From: songsunkook Date: Wed, 7 Jun 2023 19:13:26 +0900 Subject: [PATCH 17/17] =?UTF-8?q?docs:=20swagger=20model=20=EC=84=A4?= =?UTF-8?q?=EB=AA=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/dto/normal/shop/request/CreateShopRequest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java b/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java index 24684ed8..c5dfc882 100644 --- a/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java +++ b/src/main/java/koreatech/in/dto/normal/shop/request/CreateShopRequest.java @@ -82,7 +82,8 @@ public class CreateShopRequest { @NotEmpty(message = "소속시킬 상점 카테고리는 최소 1개 선택하여야합니다.") @ApiModelProperty(notes = "상점 카테고리 고유 id 리스트 \n" + "- not null \n" + - "- 최소 1개", required = true) + "- 최소 1개 \n" + + "- 예시 : [1, 4]", allowableValues = "1, 2, 3, 4, 5", required = true) private List category_ids = new ArrayList<>(); @Size(max = 10, message = "상점 이미지 개수 제한은 최대 10개입니다.")