diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..15bdab2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
diff --git a/.idea/dataSources.local.xml b/.idea/dataSources.local.xml
new file mode 100644
index 0000000..f020fb5
--- /dev/null
+++ b/.idea/dataSources.local.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+ #@
+ `
+
+
+ admin
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 0000000..d3281c4
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ mariadb
+ true
+ org.mariadb.jdbc.Driver
+ jdbc:mariadb://seonggil-maria.cmigfdh4psla.ap-northeast-2.rds.amazonaws.com:3306
+ $ProjectFileDir$
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..26b3516
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..5d67138
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..257cd97
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,779 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ "keyToString": {
+ "RequestMappingsPanelOrder0": "0",
+ "RequestMappingsPanelOrder1": "1",
+ "RequestMappingsPanelOrder2": "2",
+ "RequestMappingsPanelWidth0": "75",
+ "RequestMappingsPanelWidth1": "75",
+ "RequestMappingsPanelWidth2": "75",
+ "WebServerToolWindowFactoryState": "false",
+ "last_opened_file_path": "C:/SpringBootWorks/SubMarket/DiscoveryService",
+ "node.js.detected.package.eslint": "true",
+ "node.js.selected.package.eslint": "(autodetect)",
+ "node.js.selected.package.tslint": "(autodetect)",
+ "project.structure.last.edited": "Modules",
+ "project.structure.proportion": "0.15",
+ "project.structure.side.proportion": "0.27471265",
+ "settings.editor.selected.configurable": "bigdataide_conn_settings",
+ "spring.configuration.checksum": "b9a7970c2902b48ff1e793a804d5e365"
+ },
+ "keyToStringList": {
+ "DatabaseDriversLRU": [
+ "mariadb"
+ ]
+ }
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1653191488907
+
+
+ 1653191488907
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1654327661985
+
+
+
+ 1654327661985
+
+
+ 1654328860378
+
+
+
+ 1654328860378
+
+
+ 1654329645233
+
+
+
+ 1654329645233
+
+
+ 1654406099051
+
+
+
+ 1654406099051
+
+
+ 1654406716386
+
+
+
+ 1654406716386
+
+
+ 1654407264169
+
+
+
+ 1654407264169
+
+
+ 1654407495937
+
+
+
+ 1654407495937
+
+
+ 1654407892732
+
+
+
+ 1654407892732
+
+
+ 1654407919345
+
+
+
+ 1654407919345
+
+
+ 1654407940264
+
+
+
+ 1654407940264
+
+
+ 1654407969978
+
+
+
+ 1654407969978
+
+
+ 1654419251951
+
+
+
+ 1654419251952
+
+
+ 1654419270968
+
+
+
+ 1654419270968
+
+
+ 1654419297889
+
+
+
+ 1654419297889
+
+
+ 1654419642502
+
+
+
+ 1654419642502
+
+
+ 1654420481024
+
+
+
+ 1654420481024
+
+
+ 1654435081615
+
+
+
+ 1654435081615
+
+
+ 1654442576394
+
+
+
+ 1654442576394
+
+
+ 1655028818146
+
+
+
+ 1655028818147
+
+
+ 1655032075359
+
+
+
+ 1655032075359
+
+
+ 1655032484330
+
+
+
+ 1655032484330
+
+
+ 1655090114790
+
+
+
+ 1655090114791
+
+
+ 1655097579665
+
+
+
+ 1655097579665
+
+
+ 1655102146453
+
+
+
+ 1655102146453
+
+
+ 1655105770518
+
+
+
+ 1655105770518
+
+
+ 1655170275465
+
+
+
+ 1655170275465
+
+
+ 1655171853916
+
+
+
+ 1655171853916
+
+
+ 1655173395212
+
+
+
+ 1655173395212
+
+
+ 1655178318823
+
+
+
+ 1655178318823
+
+
+ 1655264755697
+
+
+
+ 1655264755697
+
+
+ 1655265177999
+
+
+
+ 1655265177999
+
+
+ 1655269714687
+
+
+
+ 1655269714687
+
+
+ 1655271323605
+
+
+
+ 1655271323605
+
+
+ 1655271396740
+
+
+
+ 1655271396740
+
+
+ 1655426133353
+
+
+
+ 1655426133353
+
+
+ 1663497945730
+
+
+
+ 1663497945730
+
+
+ 1663498719231
+
+
+
+ 1663498719231
+
+
+ 1663498735217
+
+
+
+ 1663498735217
+
+
+ 1663498897013
+
+
+
+ 1663498897013
+
+
+ 1663671416922
+
+
+
+ 1663671416923
+
+
+ 1663672884586
+
+
+
+ 1663672884586
+
+
+ 1663673932945
+
+
+
+ 1663673932945
+
+
+ 1663674805292
+
+
+
+ 1663674805292
+
+
+ 1663865701638
+
+
+
+ 1663865701639
+
+
+ 1663930457773
+
+
+
+ 1663930457773
+
+
+ 1663955148024
+
+
+
+ 1663955148025
+
+
+ 1664102235319
+
+
+
+ 1664102235320
+
+
+ 1664102533681
+
+
+
+ 1664102533681
+
+
+ 1664103094950
+
+
+
+ 1664103094950
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ApiGateway/pom.xml b/ApiGateway/pom.xml
index 1705571..713f019 100644
--- a/ApiGateway/pom.xml
+++ b/ApiGateway/pom.xml
@@ -10,7 +10,7 @@
com.submarket
apigateway
- 1.0.0
+ 2.0.0
ApiGateway
ApiGateway
@@ -83,6 +83,24 @@
org.springframework.cloud
spring-cloud-starter-bus-amqp
+
+
+
+ io.micrometer
+ micrometer-registry-prometheus
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-sleuth
+
+
+ org.springframework.cloud
+ spring-cloud-starter-zipkin
+ 2.2.3.RELEASE
+
+
diff --git a/ConfigService/pom.xml b/ConfigService/pom.xml
index 240f9b7..dc8ec55 100644
--- a/ConfigService/pom.xml
+++ b/ConfigService/pom.xml
@@ -10,7 +10,7 @@
com.submarket
configservice
- 1.0.0
+ 2.0.0
ConfigService
ConfigService
diff --git a/DiscoveryService/pom.xml b/DiscoveryService/pom.xml
index 6e27966..72e0a6f 100644
--- a/DiscoveryService/pom.xml
+++ b/DiscoveryService/pom.xml
@@ -10,7 +10,7 @@
com.submarket
discoveryservice
- 1.0.0
+ 2.0.0
DiscoveryService
DiscoveryService
@@ -33,6 +33,17 @@
spring-boot-starter-test
test
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-sleuth
+
+
+ org.springframework.cloud
+ spring-cloud-starter-zipkin
+ 2.2.3.RELEASE
+
diff --git a/ItemService/pom.xml b/ItemService/pom.xml
index 7e582be..b26e070 100644
--- a/ItemService/pom.xml
+++ b/ItemService/pom.xml
@@ -10,7 +10,7 @@
com.submarket
itemservice
- 1.0.0
+ 2.0.0
ItemService
ItemService
@@ -18,10 +18,6 @@
2021.0.3-SNAPSHOT
-
- org.springframework.boot
- spring-boot-starter-data-jpa
-
org.springframework.boot
spring-boot-starter-web
@@ -66,16 +62,18 @@
1.5.0.RC1
-
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
com.fasterxml.jackson.core
jackson-databind
- 2.13.1
-
- com.fasterxml.jackson.dataformat
- jackson-dataformat-xml
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-xml
@@ -143,6 +141,50 @@
org.springframework.kafka
spring-kafka
+
+
+
+ org.hibernate
+ hibernate-ehcache
+ 5.6.11.Final
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-circuitbreaker-resilience4j
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-sleuth
+
+
+ org.springframework.cloud
+ spring-cloud-starter-zipkin
+ 2.2.3.RELEASE
+
+
+
+
+ io.micrometer
+ micrometer-registry-prometheus
+
+
+
+
+ org.springdoc
+ springdoc-openapi-ui
+ 1.6.6
+
+
diff --git a/ItemService/src/main/java/com/submarket/itemservice/ItemServiceApplication.java b/ItemService/src/main/java/com/submarket/itemservice/ItemServiceApplication.java
index 15d2546..8ea4259 100644
--- a/ItemService/src/main/java/com/submarket/itemservice/ItemServiceApplication.java
+++ b/ItemService/src/main/java/com/submarket/itemservice/ItemServiceApplication.java
@@ -3,9 +3,11 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
+@EnableFeignClients
public class ItemServiceApplication {
public static void main(String[] args) {
diff --git a/ItemService/src/main/java/com/submarket/itemservice/client/UserServiceClient.java b/ItemService/src/main/java/com/submarket/itemservice/client/UserServiceClient.java
new file mode 100644
index 0000000..1a3749e
--- /dev/null
+++ b/ItemService/src/main/java/com/submarket/itemservice/client/UserServiceClient.java
@@ -0,0 +1,16 @@
+package com.submarket.itemservice.client;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestHeader;
+
+@FeignClient(name = "USER-SERVICE")
+public interface UserServiceClient {
+
+ // Gateway 를 통과하지 않고 내부 통신으로 이동하기 때문에 "/user-service" 가 필요하지 않음
+ @GetMapping("/users/{userId}/items/{itemSeq}/liked")
+ ResponseEntity isLikedByUserId(@PathVariable int itemSeq, @PathVariable String userId);
+}
diff --git a/ItemService/src/main/java/com/submarket/itemservice/coinfig/Resilience4JConfig.java b/ItemService/src/main/java/com/submarket/itemservice/coinfig/Resilience4JConfig.java
new file mode 100644
index 0000000..5ac63fd
--- /dev/null
+++ b/ItemService/src/main/java/com/submarket/itemservice/coinfig/Resilience4JConfig.java
@@ -0,0 +1,32 @@
+package com.submarket.itemservice.coinfig;
+
+import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
+import io.github.resilience4j.timelimiter.TimeLimiterConfig;
+import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory;
+import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder;
+import org.springframework.cloud.client.circuitbreaker.Customizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.time.Duration;
+
+@Configuration
+public class Resilience4JConfig {
+
+ @Bean
+ public Customizer globalCustomConfiguration() {
+ CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
+ .failureRateThreshold(4) // Open or False 100 중 4 번 실패 시 Open
+ .waitDurationInOpenState(Duration.ofMillis(1000)) // Open time (1s)
+ .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED) // 수 or 시간 기반
+ .slidingWindowSize(2).build();
+
+ TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom()
+ .timeoutDuration(Duration.ofSeconds(4)).build();
+
+ return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
+ .timeLimiterConfig(timeLimiterConfig)
+ .circuitBreakerConfig(circuitBreakerConfig).build());
+
+ }
+}
diff --git a/ItemService/src/main/java/com/submarket/itemservice/coinfig/SwaggerConfig.java b/ItemService/src/main/java/com/submarket/itemservice/coinfig/SwaggerConfig.java
new file mode 100644
index 0000000..498dffc
--- /dev/null
+++ b/ItemService/src/main/java/com/submarket/itemservice/coinfig/SwaggerConfig.java
@@ -0,0 +1,44 @@
+package com.submarket.itemservice.coinfig;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import org.springdoc.core.GroupedOpenApi;
+import org.springdoc.core.customizers.OpenApiCustomiser;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SwaggerConfig {
+
+ @Bean
+ public GroupedOpenApi publicApi() {
+ return GroupedOpenApi.builder()
+ .group("ItemServiceAPI")
+ .pathsToMatch("/**")
+ .addOpenApiCustomiser(buildSecurityOpenApi()) // JWT Setting Config
+ .build();
+ }
+
+ /**
+ * JWT Token Setting Config
+ * @return
+ */
+ public OpenApiCustomiser buildSecurityOpenApi() {
+ return OpenApi -> OpenApi.addSecurityItem(new SecurityRequirement().addList("jwt token"))
+ .getComponents()
+ .addSecuritySchemes("jwt token", new SecurityScheme()
+ .name("Authorization")
+ .type(SecurityScheme.Type.HTTP)
+ .in(SecurityScheme.In.HEADER)
+ .bearerFormat("JWT")
+ .scheme("bearer"));
+ }
+ @Bean
+ public OpenAPI springShopOpenAPI() {
+ return new OpenAPI()
+ .info(new Info().title("SubMarket - ITEM-SERVICE API")
+ .description("SubMarket ItemService API 명세서").version("v2.0.0"));
+ }
+}
diff --git a/ItemService/src/main/java/com/submarket/itemservice/constants/S3Constants.java b/ItemService/src/main/java/com/submarket/itemservice/constants/S3Constants.java
new file mode 100644
index 0000000..fda4bf8
--- /dev/null
+++ b/ItemService/src/main/java/com/submarket/itemservice/constants/S3Constants.java
@@ -0,0 +1,11 @@
+package com.submarket.itemservice.constants;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class S3Constants {
+ public final static String IMAGE_FOLDER_PATH = "images";
+}
diff --git a/ItemService/src/main/java/com/submarket/itemservice/controller/CategoryController.java b/ItemService/src/main/java/com/submarket/itemservice/controller/CategoryController.java
index 64e46fe..224d5c6 100644
--- a/ItemService/src/main/java/com/submarket/itemservice/controller/CategoryController.java
+++ b/ItemService/src/main/java/com/submarket/itemservice/controller/CategoryController.java
@@ -1,12 +1,18 @@
package com.submarket.itemservice.controller;
import com.submarket.itemservice.dto.CategoryDto;
-import com.submarket.itemservice.service.impl.CategoryService;
+import com.submarket.itemservice.service.CategoryService;
+import io.micrometer.core.annotation.Timed;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
@@ -16,10 +22,17 @@
@Slf4j
@RestController
@RequiredArgsConstructor
+@Tag(name = "Category API", description = "상품 Category 정보 API")
public class CategoryController {
private final CategoryService categoryService;
- @GetMapping("/category")
+
+ @Operation(summary = "모드 Category List 조회", description = "상품 CategoryList 조회", tags = {"category"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "Category List 조회 성공")
+ })
+ @GetMapping("/categories")
+ @Timed(value = "category.findAll", longTask = true)
public ResponseEntity
diff --git a/OrderService/src/main/java/com/submarket/orderservice/OrderServiceApplication.java b/OrderService/src/main/java/com/submarket/orderservice/OrderServiceApplication.java
index e64b969..fbe8785 100644
--- a/OrderService/src/main/java/com/submarket/orderservice/OrderServiceApplication.java
+++ b/OrderService/src/main/java/com/submarket/orderservice/OrderServiceApplication.java
@@ -3,9 +3,11 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
+@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
diff --git a/OrderService/src/main/java/com/submarket/orderservice/config/SwaggerConfig.java b/OrderService/src/main/java/com/submarket/orderservice/config/SwaggerConfig.java
new file mode 100644
index 0000000..ecc9968
--- /dev/null
+++ b/OrderService/src/main/java/com/submarket/orderservice/config/SwaggerConfig.java
@@ -0,0 +1,44 @@
+package com.submarket.orderservice.config;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import org.springdoc.core.GroupedOpenApi;
+import org.springdoc.core.customizers.OpenApiCustomiser;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SwaggerConfig {
+
+ @Bean
+ public GroupedOpenApi publicApi() {
+ return GroupedOpenApi.builder()
+ .group("OrderService API")
+ .pathsToMatch("/**")
+ .addOpenApiCustomiser(buildSecurityOpenApi()) // JWT Setting Config
+ .build();
+ }
+
+ /**
+ * JWT Token Setting Config
+ * @return
+ */
+ public OpenApiCustomiser buildSecurityOpenApi() {
+ return OpenApi -> OpenApi.addSecurityItem(new SecurityRequirement().addList("jwt token"))
+ .getComponents()
+ .addSecuritySchemes("jwt token", new SecurityScheme()
+ .name("Authorization")
+ .type(SecurityScheme.Type.HTTP)
+ .in(SecurityScheme.In.HEADER)
+ .bearerFormat("JWT")
+ .scheme("bearer"));
+ }
+ @Bean
+ public OpenAPI springShopOpenAPI() {
+ return new OpenAPI()
+ .info(new Info().title("SubMarket - ORDER-SERVICE API")
+ .description("SubMarket OrderService API 명세서").version("v2.0.0"));
+ }
+}
diff --git a/OrderService/src/main/java/com/submarket/orderservice/controller/MainController.java b/OrderService/src/main/java/com/submarket/orderservice/controller/MainController.java
index 3a3fee2..fec4f4c 100644
--- a/OrderService/src/main/java/com/submarket/orderservice/controller/MainController.java
+++ b/OrderService/src/main/java/com/submarket/orderservice/controller/MainController.java
@@ -1,17 +1,31 @@
package com.submarket.orderservice.controller;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
@RequiredArgsConstructor
+@Tag(name = "Health API", description = "Service Health Check EndPoint")
public class MainController {
private final Environment env;
+
+ @Operation(summary = "상태 확인", description = "인증 정보 없이 접근할 수 있는 EndPoint")
+ @ApiResponses({
+ @ApiResponse(responseCode = "503", description = "Eureka 서버에 미 등록"),
+ @ApiResponse(responseCode = "401", description = "Token 인증 실패"),
+ @ApiResponse(responseCode = "403", description = "Spring Security 인증 실패")
+
+ })
@GetMapping("/health")
public String health() {
log.info("OrderService On");
diff --git a/OrderService/src/main/java/com/submarket/orderservice/controller/OrderController.java b/OrderService/src/main/java/com/submarket/orderservice/controller/OrderController.java
index ffc1ca0..a2c3b54 100644
--- a/OrderService/src/main/java/com/submarket/orderservice/controller/OrderController.java
+++ b/OrderService/src/main/java/com/submarket/orderservice/controller/OrderController.java
@@ -1,7 +1,12 @@
package com.submarket.orderservice.controller;
import com.submarket.orderservice.dto.OrderDto;
-import com.submarket.orderservice.service.impl.OrderService;
+import com.submarket.orderservice.service.impl.OrderServiceImpl;
+import com.submarket.orderservice.vo.OrderRequest;
+import io.micrometer.core.annotation.Timed;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
@@ -16,25 +21,45 @@
@Slf4j
@RequiredArgsConstructor
public class OrderController {
- private final OrderService orderService;
+ private final OrderServiceImpl orderServiceImpl;
- @PostMapping("/order")
- public ResponseEntity insertOrder(@RequestBody OrderDto orderDto) throws Exception {
+ @Operation(summary = "주문 생성", description = "주문 생성", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "201", description = "주문 생성 완료")
+ })
+ @PostMapping("/orders")
+ @Timed(value = "order.save", longTask = true)
+ public ResponseEntity insertOrder(@RequestBody OrderRequest request) throws Exception {
log.info(this.getClass().getName() + ".insertOrder Start!");
- orderService.insertOrder(orderDto);
+ orderServiceImpl.insertOrder(OrderDto.builder()
+ .orderId(request.getOrderId())
+ .itemSeq(request.getItemSeq())
+ .userId(request.getUserId())
+ .userAddress(request.getUserAddress())
+ .userAddress2(request.getUserAddress2())
+ .sellerId(request.getSellerId())
+ .orderDate(request.getOrderDate())
+ .orderDateDetails(request.getOrderDateDetails()).build());
+
log.info(this.getClass().getName() + ".insertOrder End!");
return ResponseEntity.status(HttpStatus.CREATED).body("주문 생성 완료");
}
- @GetMapping("/order/user/{userId}")
- public ResponseEntity> findOrderInfoByUserId(@PathVariable String userId) throws Exception {
+
+ @Operation(summary = "사용자 주문 목록 조회", description = "사용자 아이디를 사용하여 주문 목록 조회", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "주문 목록 조회 성공")
+ })
+ @GetMapping("/users/{userId}/orders")
+ @Timed(value = "user.order.findById", longTask = true)
+ public ResponseEntity> findOrderInfoByUserId(@PathVariable String userId) throws Exception {
log.info(this.getClass().getName() + ".findOrderInfoByUserId Start!");
Map rMap = new HashMap<>();
- List orderDtoList = orderService.findAllOrderByUserId(userId);
+ List orderDtoList = orderServiceImpl.findAllOrderByUserId(userId);
rMap.put("response", orderDtoList);
@@ -45,14 +70,20 @@ public ResponseEntity> findOrderInfoByUserId(@PathVariable S
return ResponseEntity.status(HttpStatus.OK).body(rMap);
}
- @GetMapping("/order/seller/{sellerId}")
+
+ @Operation(summary = "판매자 주문 목록 조회", description = "판매자 아이디를 사용하여 주문 목록 조회", tags = {"seller"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "주문 목록 조회 성공")
+ })
+ @GetMapping("sellers/{sellerId}/orders")
+ @Timed(value = "seller.order.findById", longTask = true)
public ResponseEntity> findOrderInfoBySellerId(@PathVariable String sellerId)
- throws Exception {
+ throws Exception {
log.info(this.getClass().getName() + ".findOrderInfoBySellerId Start!");
Map rMap = new HashMap<>();
- List orderDtoList = orderService.findAllOrderBySellerId(sellerId);
+ List orderDtoList = orderServiceImpl.findAllOrderBySellerId(sellerId);
rMap.put("response", orderDtoList);
@@ -63,14 +94,25 @@ public ResponseEntity> findOrderInfoBySellerId(@PathVariable
return ResponseEntity.status(HttpStatus.OK).body(rMap);
}
- @GetMapping("/order/order/{orderId}")
+
+ @Operation(summary = "주문 정보 상세 조회", description = "주문 번호를 사용하여 주문 번호 상세 조회", tags = {"seller", "user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "주문 목록 조회 성공")
+ })
+ @GetMapping("/orders/{orderId}")
+ @Timed(value = "order.findById", longTask = true)
public ResponseEntity> findOrderInfoByOrderId(@PathVariable String orderId) throws Exception {
Map rMap = new HashMap<>();
- OrderDto orderDto = orderService.findOneOrderByOrderId(orderId);
+ OrderDto orderDto = orderServiceImpl.findOneOrderByOrderId(orderId);
rMap.put("response", orderDto);
+ if (orderDto == null) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(rMap);
+ }
+
+
return ResponseEntity.ok().body(rMap);
}
}
diff --git a/OrderService/src/main/java/com/submarket/orderservice/dto/OrderDto.java b/OrderService/src/main/java/com/submarket/orderservice/dto/OrderDto.java
index e506c4c..a0a9178 100644
--- a/OrderService/src/main/java/com/submarket/orderservice/dto/OrderDto.java
+++ b/OrderService/src/main/java/com/submarket/orderservice/dto/OrderDto.java
@@ -1,10 +1,12 @@
package com.submarket.orderservice.dto;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
+@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderDto {
diff --git a/OrderService/src/main/java/com/submarket/orderservice/service/IKafkaConsumerService.java b/OrderService/src/main/java/com/submarket/orderservice/service/KafkaConsumerService.java
similarity index 82%
rename from OrderService/src/main/java/com/submarket/orderservice/service/IKafkaConsumerService.java
rename to OrderService/src/main/java/com/submarket/orderservice/service/KafkaConsumerService.java
index 538fdc1..95aa9fb 100644
--- a/OrderService/src/main/java/com/submarket/orderservice/service/IKafkaConsumerService.java
+++ b/OrderService/src/main/java/com/submarket/orderservice/service/KafkaConsumerService.java
@@ -1,6 +1,6 @@
package com.submarket.orderservice.service;
-public interface IKafkaConsumerService {
+public interface KafkaConsumerService {
void kafkaCreateOrder(String kafkaMessage) throws Exception;
void kafkaGetItemInfoFromItemService(String kafkaMessage) throws Exception;
diff --git a/OrderService/src/main/java/com/submarket/orderservice/service/IKafkaProducerService.java b/OrderService/src/main/java/com/submarket/orderservice/service/KafkaProducerService.java
similarity index 78%
rename from OrderService/src/main/java/com/submarket/orderservice/service/IKafkaProducerService.java
rename to OrderService/src/main/java/com/submarket/orderservice/service/KafkaProducerService.java
index c614255..01c059b 100644
--- a/OrderService/src/main/java/com/submarket/orderservice/service/IKafkaProducerService.java
+++ b/OrderService/src/main/java/com/submarket/orderservice/service/KafkaProducerService.java
@@ -1,5 +1,5 @@
package com.submarket.orderservice.service;
-public interface IKafkaProducerService {
+public interface KafkaProducerService {
void kafkaSendPriceToSellerService(int totalPrice, String date, String sellerId) throws Exception;
}
diff --git a/OrderService/src/main/java/com/submarket/orderservice/service/IOrderService.java b/OrderService/src/main/java/com/submarket/orderservice/service/OrderService.java
similarity index 93%
rename from OrderService/src/main/java/com/submarket/orderservice/service/IOrderService.java
rename to OrderService/src/main/java/com/submarket/orderservice/service/OrderService.java
index 2b006bb..20841cc 100644
--- a/OrderService/src/main/java/com/submarket/orderservice/service/IOrderService.java
+++ b/OrderService/src/main/java/com/submarket/orderservice/service/OrderService.java
@@ -4,7 +4,7 @@
import java.util.List;
-public interface IOrderService {
+public interface OrderService {
int insertOrder(OrderDto orderDto) throws Exception;
diff --git a/OrderService/src/main/java/com/submarket/orderservice/service/impl/KafkaConsumerService.java b/OrderService/src/main/java/com/submarket/orderservice/service/impl/KafkaConsumerServiceImpl.java
similarity index 84%
rename from OrderService/src/main/java/com/submarket/orderservice/service/impl/KafkaConsumerService.java
rename to OrderService/src/main/java/com/submarket/orderservice/service/impl/KafkaConsumerServiceImpl.java
index 1da4b01..5e806bc 100644
--- a/OrderService/src/main/java/com/submarket/orderservice/service/impl/KafkaConsumerService.java
+++ b/OrderService/src/main/java/com/submarket/orderservice/service/impl/KafkaConsumerServiceImpl.java
@@ -4,13 +4,12 @@
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.submarket.orderservice.dto.OrderDto;
-import com.submarket.orderservice.service.IKafkaConsumerService;
+import com.submarket.orderservice.service.KafkaConsumerService;
import com.submarket.orderservice.util.CmmUtil;
import com.submarket.orderservice.util.DateUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.annotation.KafkaListener;
-import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import java.util.HashMap;
@@ -19,9 +18,9 @@
@Service
@Slf4j
@RequiredArgsConstructor
-public class KafkaConsumerService implements IKafkaConsumerService {
- private final OrderService orderService;
- private final KafkaProducerService kafkaProducerService;
+public class KafkaConsumerServiceImpl implements KafkaConsumerService {
+ private final OrderServiceImpl orderServiceImpl;
+ private final KafkaProducerServiceImpl kafkaProducerServiceImpl;
@KafkaListener(topics = "sub")
@Override
@@ -48,7 +47,7 @@ public void kafkaCreateOrder(String kafkaMessage) throws Exception {
orderDto.setUserAddress(String.valueOf(map.get("userAddress")));
orderDto.setUserAddress2(CmmUtil.nvl(String.valueOf(map.get("userAddress2"))));
- orderService.insertOrder(orderDto);
+ orderServiceImpl.insertOrder(orderDto);
log.info(this.getClass().getName() + ".kafkaCreateOrder Start!");
}
@@ -76,10 +75,10 @@ public void kafkaGetItemInfoFromItemService(String kafkaMessage) throws Exceptio
OrderDto orderDto = new OrderDto();
orderDto.setItemSeq(itemSeq);
- int totalPrice = orderService.totalPriceByItemSeq(orderDto, itemPrice);
+ int totalPrice = orderServiceImpl.totalPriceByItemSeq(orderDto, itemPrice);
String date = DateUtil.getDateTime("yyyyMM");
- kafkaProducerService.kafkaSendPriceToSellerService(totalPrice, date, sellerId);
+ kafkaProducerServiceImpl.kafkaSendPriceToSellerService(totalPrice, date, sellerId);
log.info(this.getClass().getName() + ".kafkaGetItemInfoFromItemService End!");
diff --git a/OrderService/src/main/java/com/submarket/orderservice/service/impl/KafkaProducerService.java b/OrderService/src/main/java/com/submarket/orderservice/service/impl/KafkaProducerServiceImpl.java
similarity index 91%
rename from OrderService/src/main/java/com/submarket/orderservice/service/impl/KafkaProducerService.java
rename to OrderService/src/main/java/com/submarket/orderservice/service/impl/KafkaProducerServiceImpl.java
index afddff8..3d65bd4 100644
--- a/OrderService/src/main/java/com/submarket/orderservice/service/impl/KafkaProducerService.java
+++ b/OrderService/src/main/java/com/submarket/orderservice/service/impl/KafkaProducerServiceImpl.java
@@ -2,7 +2,7 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.submarket.orderservice.service.IKafkaProducerService;
+import com.submarket.orderservice.service.KafkaProducerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.core.KafkaTemplate;
@@ -14,7 +14,7 @@
@Service
@Slf4j
@RequiredArgsConstructor
-public class KafkaProducerService implements IKafkaProducerService {
+public class KafkaProducerServiceImpl implements KafkaProducerService {
private final KafkaTemplate kafkaTemplate;
diff --git a/OrderService/src/main/java/com/submarket/orderservice/service/impl/OrderService.java b/OrderService/src/main/java/com/submarket/orderservice/service/impl/OrderServiceImpl.java
similarity index 95%
rename from OrderService/src/main/java/com/submarket/orderservice/service/impl/OrderService.java
rename to OrderService/src/main/java/com/submarket/orderservice/service/impl/OrderServiceImpl.java
index 1ff047d..b85e40f 100644
--- a/OrderService/src/main/java/com/submarket/orderservice/service/impl/OrderService.java
+++ b/OrderService/src/main/java/com/submarket/orderservice/service/impl/OrderServiceImpl.java
@@ -2,9 +2,8 @@
import com.submarket.orderservice.dto.OrderDto;
import com.submarket.orderservice.mapper.impl.OrderMapper;
-import com.submarket.orderservice.service.IOrderService;
+import com.submarket.orderservice.service.OrderService;
import com.submarket.orderservice.util.DateUtil;
-import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -16,7 +15,7 @@
@Slf4j
@Service(value = "OrderService")
@RequiredArgsConstructor
-public class OrderService implements IOrderService {
+public class OrderServiceImpl implements OrderService {
private final OrderMapper orderMapper;
@Override
diff --git a/OrderService/src/main/java/com/submarket/orderservice/vo/OrderRequest.java b/OrderService/src/main/java/com/submarket/orderservice/vo/OrderRequest.java
new file mode 100644
index 0000000..1194bcb
--- /dev/null
+++ b/OrderService/src/main/java/com/submarket/orderservice/vo/OrderRequest.java
@@ -0,0 +1,29 @@
+package com.submarket.orderservice.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class OrderRequest {
+ private String orderId;
+
+ private int itemSeq;
+
+ private String userId;
+
+ private String sellerId;
+
+ private String userAddress;
+
+ private String userAddress2;
+
+ private String orderDateDetails;
+
+ private String orderDate;
+}
diff --git a/OrderService/src/test/java/com/submarket/orderservice/OrderServiceApplicationTests.java b/OrderService/src/test/java/com/submarket/orderservice/OrderServiceImplApplicationTests.java
similarity index 82%
rename from OrderService/src/test/java/com/submarket/orderservice/OrderServiceApplicationTests.java
rename to OrderService/src/test/java/com/submarket/orderservice/OrderServiceImplApplicationTests.java
index 4fa14a3..68ba36a 100644
--- a/OrderService/src/test/java/com/submarket/orderservice/OrderServiceApplicationTests.java
+++ b/OrderService/src/test/java/com/submarket/orderservice/OrderServiceImplApplicationTests.java
@@ -4,7 +4,7 @@
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
-class OrderServiceApplicationTests {
+class OrderServiceImplApplicationTests {
@Test
void contextLoads() {
diff --git a/README.md b/README.md
deleted file mode 100644
index cd60bb8..0000000
--- a/README.md
+++ /dev/null
@@ -1,69 +0,0 @@
-# Sub Market (e-commerce)
-
-### MSA기반의 구독 상품을 판매 및 구매할 수 있는 E-commerce 서비스입니다.
-
-## Description
-
-> 2022.05 - 2022.06
-
-### 적용 기술
-
-
-
-> _**Other : JWT, JPA, Load Balancer(Eureka), Gateway(Spring Cloud Gateway), REST-API, JSP, Spring Cloud Config**_
-
-
-
-https://user-images.githubusercontent.com/63443366/186517339-aa4913a6-1abe-4379-97b9-59f6e19896d8.mp4
-
-
-
-### Summary
-
-![Summary](https://user-images.githubusercontent.com/63443366/175762264-d15dfadd-e097-4dd9-8294-c86e65a15691.png)
-
-* **USER**
- * 구독 상품 구매
-
-* **SELLER**
- * 상품 판매, 매출 정보 확인 및 사용자 주문 확인
-
-* **Background**
- * 매달 사용자 구독을 갱신하는 기능
- * 판매자의 월별 매출 정보를 매월 말 저장
- * EDA (Event-driven architecture) with Kafka
-
-### Kafka
-
-![Kafka](https://user-images.githubusercontent.com/63443366/175763046-816a1b35-9df7-4249-965b-fa7ce7f31ccc.png)
-
-* **상품 구독**
- * 사용자가 상품 구독 시 상품 수량 감소 및 주문 생성
- * https://github.com/JeongSeonggil/SubMarketWithGit/issues/129
-
-* **상품 구독 취소**
- * 사용자가 상품 구독을 취소하면 수량 증가
- * https://github.com/JeongSeonggil/SubMarketWithGit/issues/132
-
-* **매출 정보 분석 및 적재**
- * 매월 말 판매자 서비스에 월 별 판매량을 적재 및 분석 시 사용
- * https://github.com/JeongSeonggil/SubMarketWithGit/issues/137
-
-* **사업자 탈퇴 시 판매 중인 상품 비활성화**
- * 판매자가 탈퇴한다면 판매자가 판매중이였던 상품 비활성화
- * https://github.com/JeongSeonggil/SubMarketWithGit/issues/141
-
-## ERD
-![image](https://user-images.githubusercontent.com/63443366/184500117-3e225474-5937-4399-8c10-ab70110219e3.png)
diff --git a/SellerService/pom.xml b/SellerService/pom.xml
index 8df3f1a..6d2828c 100644
--- a/SellerService/pom.xml
+++ b/SellerService/pom.xml
@@ -10,7 +10,7 @@
com.submarket
sellerservice
- 1.0.0
+ 2.0.0
SellerService
SellerService
@@ -133,6 +133,42 @@
org.springframework.kafka
spring-kafka
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-circuitbreaker-resilience4j
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-sleuth
+
+
+ org.springframework.cloud
+ spring-cloud-starter-zipkin
+ 2.2.3.RELEASE
+
+
+
+
+ io.micrometer
+ micrometer-registry-prometheus
+
+
+
+
+ org.springdoc
+ springdoc-openapi-ui
+ 1.6.6
+
diff --git a/SellerService/src/main/java/com/submarket/sellerservice/SellerServiceApplication.java b/SellerService/src/main/java/com/submarket/sellerservice/SellerServiceApplication.java
index 73517b1..a20771e 100644
--- a/SellerService/src/main/java/com/submarket/sellerservice/SellerServiceApplication.java
+++ b/SellerService/src/main/java/com/submarket/sellerservice/SellerServiceApplication.java
@@ -3,6 +3,7 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@@ -10,6 +11,7 @@
@SpringBootApplication
@EnableEurekaClient
+@EnableFeignClients
public class SellerServiceApplication {
public static void main(String[] args) {
diff --git a/SellerService/src/main/java/com/submarket/sellerservice/config/Resilience4JConfig.java b/SellerService/src/main/java/com/submarket/sellerservice/config/Resilience4JConfig.java
new file mode 100644
index 0000000..4cc42ff
--- /dev/null
+++ b/SellerService/src/main/java/com/submarket/sellerservice/config/Resilience4JConfig.java
@@ -0,0 +1,32 @@
+package com.submarket.sellerservice.config;
+
+import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
+import io.github.resilience4j.timelimiter.TimeLimiterConfig;
+import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory;
+import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder;
+import org.springframework.cloud.client.circuitbreaker.Customizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.time.Duration;
+
+@Configuration
+public class Resilience4JConfig {
+
+ @Bean
+ public Customizer globalCustomConfiguration() {
+ CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
+ .failureRateThreshold(4) // Open or False 100 중 4 번 실패 시 Open
+ .waitDurationInOpenState(Duration.ofMillis(1000)) // Open time (1s)
+ .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED) // 수 or 시간 기반
+ .slidingWindowSize(2).build();
+
+ TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom()
+ .timeoutDuration(Duration.ofSeconds(4)).build();
+
+ return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
+ .timeLimiterConfig(timeLimiterConfig)
+ .circuitBreakerConfig(circuitBreakerConfig).build());
+
+ }
+}
diff --git a/SellerService/src/main/java/com/submarket/sellerservice/config/SwaggerConfig.java b/SellerService/src/main/java/com/submarket/sellerservice/config/SwaggerConfig.java
new file mode 100644
index 0000000..6647c56
--- /dev/null
+++ b/SellerService/src/main/java/com/submarket/sellerservice/config/SwaggerConfig.java
@@ -0,0 +1,44 @@
+package com.submarket.sellerservice.config;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import org.springdoc.core.GroupedOpenApi;
+import org.springdoc.core.customizers.OpenApiCustomiser;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SwaggerConfig {
+
+ @Bean
+ public GroupedOpenApi publicApi() {
+ return GroupedOpenApi.builder()
+ .group("SellerServiceAPI")
+ .pathsToMatch("/**")
+ .addOpenApiCustomiser(buildSecurityOpenApi()) // JWT Setting Config
+ .build();
+ }
+
+ /**
+ * JWT Token Setting Config
+ * @return
+ */
+ public OpenApiCustomiser buildSecurityOpenApi() {
+ return OpenApi -> OpenApi.addSecurityItem(new SecurityRequirement().addList("jwt token"))
+ .getComponents()
+ .addSecuritySchemes("jwt token", new SecurityScheme()
+ .name("Authorization")
+ .type(SecurityScheme.Type.HTTP)
+ .in(SecurityScheme.In.HEADER)
+ .bearerFormat("JWT")
+ .scheme("bearer"));
+ }
+ @Bean
+ public OpenAPI springShopOpenAPI() {
+ return new OpenAPI()
+ .info(new Info().title("SubMarket - SELLER-SERVICE API")
+ .description("SubMarket SellerService 명세서").version("v2.0.0"));
+ }
+}
diff --git a/SellerService/src/main/java/com/submarket/sellerservice/controller/MainController.java b/SellerService/src/main/java/com/submarket/sellerservice/controller/MainController.java
index 4de6fbb..383a457 100644
--- a/SellerService/src/main/java/com/submarket/sellerservice/controller/MainController.java
+++ b/SellerService/src/main/java/com/submarket/sellerservice/controller/MainController.java
@@ -1,6 +1,11 @@
package com.submarket.sellerservice.controller;
import com.submarket.sellerservice.dto.BusinessIdApiDto;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
@@ -10,6 +15,7 @@
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@@ -17,14 +23,20 @@
@Slf4j
@RestController
+@RequiredArgsConstructor
+@Tag(name = "Health API", description = "서버 상태 확인")
public class MainController {
- private Environment env;
+ private final Environment env;
- @Autowired
- public MainController(Environment env) {
- this.env = env;
- }
+
+ @Operation(summary = "상태 확인", description = "인증 정보 없이 접근할 수 있는 EndPoint")
+ @ApiResponses({
+ @ApiResponse(responseCode = "503", description = "Eureka 서버에 미 등록"),
+ @ApiResponse(responseCode = "401", description = "Token 인증 실패"),
+ @ApiResponse(responseCode = "403", description = "Spring Security 인증 실패")
+
+ })
@GetMapping("/health")
public String health() {
log.info("SellerService On");
diff --git a/SellerService/src/main/java/com/submarket/sellerservice/controller/SalesController.java b/SellerService/src/main/java/com/submarket/sellerservice/controller/SalesController.java
index c602658..7d158aa 100644
--- a/SellerService/src/main/java/com/submarket/sellerservice/controller/SalesController.java
+++ b/SellerService/src/main/java/com/submarket/sellerservice/controller/SalesController.java
@@ -3,6 +3,11 @@
import com.submarket.sellerservice.dto.SalesDto;
import com.submarket.sellerservice.service.impl.SalesService;
import com.submarket.sellerservice.util.TokenUtil;
+import io.micrometer.core.annotation.Timed;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
@@ -10,6 +15,7 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
@@ -19,11 +25,17 @@
@RestController
@Slf4j
@RequiredArgsConstructor
+@Tag(name = "판매자 매출 정보 API", description = "사용자 매출 정보 관련 APi")
public class SalesController {
private final SalesService salesService;
private final TokenUtil tokenUtil;
- @GetMapping("/seller/sales")
+ @Operation(summary = "모든 매출 정보 조회", description = "판매자 아이디를 기준으로 매출 목록 조회", tags = {"sales"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "매출 정보 조회 성공")
+ })
+ @GetMapping("/sellers/sales")
+ @Timed(value = "seller.sales.findById", longTask = true)
public ResponseEntity> findAllSalesDtoBySellerId(@RequestHeader HttpHeaders headers) throws Exception {
log.info(this.getClass().getName() + ".findAllSalesDtoBySellerId Start!");
String sellerId = tokenUtil.getUserIdByToken(headers);
diff --git a/SellerService/src/main/java/com/submarket/sellerservice/controller/SellerController.java b/SellerService/src/main/java/com/submarket/sellerservice/controller/SellerController.java
index 14598dc..b3e5969 100644
--- a/SellerService/src/main/java/com/submarket/sellerservice/controller/SellerController.java
+++ b/SellerService/src/main/java/com/submarket/sellerservice/controller/SellerController.java
@@ -8,6 +8,11 @@
import com.submarket.sellerservice.vo.RequestChangePassword;
import com.submarket.sellerservice.vo.RequestSellerInfo;
import com.submarket.sellerservice.vo.ResponseSellerInfo;
+import io.micrometer.core.annotation.Timed;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
@@ -24,13 +29,19 @@
@RestController
@RequiredArgsConstructor
@Slf4j
+@Tag(name = "판매자 정보 API", description = "판매자 정보 관련 API")
public class SellerController {
private final SellerService sellerService;
private final TokenUtil tokenUtil;
private final SellerCheckService sellerCheckService;
+ @Operation(summary = "판매자 정보 조회", description = "Token 값을 사용하여 사용자 정보 조회", tags = {"seller"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "매출 정보 조회 성공")
+ })
@GetMapping("/seller")
+ @Timed(value = "seller.findById", longTask = true)
public ResponseEntity getSellerInfo(@RequestHeader HttpHeaders headers) throws Exception {
log.info(this.getClass().getName() + ".getSellerInfo Start!");
SellerDto pDto = new SellerDto();
@@ -55,7 +66,16 @@ public ResponseEntity getSellerInfo(@RequestHeader HttpHeade
return ResponseEntity.ok().body(sellerInfo);
}
+
+ @Operation(summary = "판매자 정보 등록", description = "판매자 정보 등록", tags = {"seller"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "201", description = "회원가입 성공"),
+ @ApiResponse(responseCode = "409", description = "중복된 아이디"),
+ @ApiResponse(responseCode = "409", description = "중복된 이메일"),
+ @ApiResponse(responseCode = "400", description = "회원가입 실패")
+ })
@PostMapping("/sellers")
+ @Timed(value = "seller.save", longTask = true)
public ResponseEntity createSeller(@RequestBody RequestSellerInfo sellerInfo) throws Exception {
log.info(this.getClass().getName() + ".createSeller Start!");
@@ -75,7 +95,14 @@ public ResponseEntity createSeller(@RequestBody RequestSellerInfo seller
}
}
+
+ @Operation(summary = "판매자 정보 수정", description = "판매자 정보 수정", tags = {"seller"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "판매자 정보 수정 성공"),
+ @ApiResponse(responseCode = "500", description = "판매자 정보 수정 실패")
+ })
@PostMapping("/sellers/modify")
+ @Timed(value = "seller.modify", longTask = true)
public ResponseEntity modifySellerInfo(@RequestBody SellerDto sellerDto,
@RequestHeader HttpHeaders headers) throws Exception {
log.info(this.getClass().getName() + ".modifySellerInfo Start!");
@@ -95,7 +122,13 @@ public ResponseEntity modifySellerInfo(@RequestBody SellerDto sellerDto
return ResponseEntity.ok().body("수정 실패 (500)");
}
+
+ @Operation(summary = "판매자 정보 삭제", description = "비밀번호 인증 후 판매자 정보 삭제", tags = {"seller"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "판매자 정보 삭제 성공")
+ })
@PostMapping("/sellers/drop")
+ @Timed(value = "seller.drop", longTask = true)
public ResponseEntity deleteSeller(@RequestHeader HttpHeaders headers,
@RequestBody RequestSellerInfo requestSellerInfo) throws Exception {
log.info(this.getClass().getName() + ".deleteSeller Start!");
@@ -117,7 +150,13 @@ public ResponseEntity deleteSeller(@RequestHeader HttpHeaders headers,
* <------------------------>아이디 찾기 with UserEmail ------------------------>
* 만약 Email 이 같다면 아이디 정보 일부를 제공
*/
+ @Operation(summary = "판매자 아이디 찾기", description = "이메일 인증 후 아이디 찾기", tags = {"seller"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "판매자 아이디 정보 성공"),
+ @ApiResponse(responseCode = "404", description = "이메일과 일치하는 판매자 정보를 찾을 수 없음"),
+ })
@GetMapping("/sellers/find-id/{sellerEmail}")
+ @Timed(value = "seller.find.id", longTask = true)
public ResponseEntity findSellerId(@PathVariable String sellerEmail) throws Exception {
log.info("-------------------- > " + this.getClass().getName() + "findSellerId Start!");
SellerDto sellerDto = new SellerDto();
@@ -135,7 +174,13 @@ public ResponseEntity findSellerId(@PathVariable String sellerEmail) thr
return ResponseEntity.status(HttpStatus.OK).body(sellerId);
}
+
+ @Operation(summary = "판매자 비밀번호 변경", description = "이전 비밀번호가 일치한다면 비밀번호 변경 진행", tags = {"seller"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "판매자 비밀번호 변경 성공")
+ })
@PatchMapping("/sellers/change-password")
+ @Timed(value = "seller.change.password", longTask = true)
public ResponseEntity changePassword(@RequestHeader HttpHeaders headers, @RequestBody RequestChangePassword
requestChangePassword) throws Exception {
log.info(this.getClass().getName() + ".changePassword Start!");
@@ -155,8 +200,15 @@ public ResponseEntity changePassword(@RequestHeader HttpHeaders headers,
return ResponseEntity.ok().body("비밀번호 변경 성공");
}
+
+ @Operation(summary = "사업자 번호 유효성 검사", description = "Open API를 이용하여 정보가 있다면 OK", tags = {"seller"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "유효한 사업자"),
+ @ApiResponse(responseCode = "400", description = "유효하지 않는 사업자 번호")
+ })
// 사업자 번호 유효성 검사
@GetMapping("/seller/business/{businessId}")
+ @Timed(value = "seller.check.businessId", longTask = true)
public ResponseEntity> checkBusinessId(@PathVariable String businessId) throws Exception {
log.info(this.getClass().getName() + ".checkBusinessId Start!");
diff --git a/SellerService/src/main/java/com/submarket/sellerservice/dto/BusinessIdApiDto.java b/SellerService/src/main/java/com/submarket/sellerservice/dto/BusinessIdApiDto.java
index ccd7523..b607311 100644
--- a/SellerService/src/main/java/com/submarket/sellerservice/dto/BusinessIdApiDto.java
+++ b/SellerService/src/main/java/com/submarket/sellerservice/dto/BusinessIdApiDto.java
@@ -9,5 +9,6 @@
public class BusinessIdApiDto {
private int request_cnt;
private String status_code;
+
private List> data;
}
diff --git a/SellerService/src/main/java/com/submarket/sellerservice/dto/SalesDto.java b/SellerService/src/main/java/com/submarket/sellerservice/dto/SalesDto.java
index 87cf0f7..cf1b491 100644
--- a/SellerService/src/main/java/com/submarket/sellerservice/dto/SalesDto.java
+++ b/SellerService/src/main/java/com/submarket/sellerservice/dto/SalesDto.java
@@ -6,6 +6,7 @@
import lombok.NoArgsConstructor;
import javax.persistence.*;
+import java.util.List;
@Data
@NoArgsConstructor
@@ -16,4 +17,6 @@ public class SalesDto {
private int value;
private SellerEntity seller;
+
+ private List response;
}
diff --git a/SellerService/src/main/java/com/submarket/sellerservice/jpa/entity/SalesEntity.java b/SellerService/src/main/java/com/submarket/sellerservice/jpa/entity/SalesEntity.java
index 3ed7d62..cf2cd09 100644
--- a/SellerService/src/main/java/com/submarket/sellerservice/jpa/entity/SalesEntity.java
+++ b/SellerService/src/main/java/com/submarket/sellerservice/jpa/entity/SalesEntity.java
@@ -14,7 +14,7 @@
@NoArgsConstructor
@AllArgsConstructor
@Builder
-@JsonIgnoreProperties({"seller"})
+@ToString(exclude={"seller"})
public class SalesEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
diff --git a/SellerService/src/main/java/com/submarket/sellerservice/mapper/SalesMapper.java b/SellerService/src/main/java/com/submarket/sellerservice/mapper/SalesMapper.java
index 4fe85ca..4325840 100644
--- a/SellerService/src/main/java/com/submarket/sellerservice/mapper/SalesMapper.java
+++ b/SellerService/src/main/java/com/submarket/sellerservice/mapper/SalesMapper.java
@@ -9,9 +9,7 @@
@Mapper
public interface SalesMapper {
SalesMapper INSTANCE = Mappers.getMapper(SalesMapper.class);
-
- SalesEntity salesDtoToSalesEntity(SalesDto salesDto);
-
@Mapping(target = "seller", ignore = true)
SalesDto salesEntityToSalesDto(SalesEntity salesEntity);
+ SalesEntity salesDtoToSalesEntity(SalesDto salesDto);
}
diff --git a/SellerService/src/main/java/com/submarket/sellerservice/mapper/SellerMapper.java b/SellerService/src/main/java/com/submarket/sellerservice/mapper/SellerMapper.java
index 3a8c263..d977c1e 100644
--- a/SellerService/src/main/java/com/submarket/sellerservice/mapper/SellerMapper.java
+++ b/SellerService/src/main/java/com/submarket/sellerservice/mapper/SellerMapper.java
@@ -12,13 +12,9 @@
@Mapper
public interface SellerMapper {
SellerMapper INSTANCE = Mappers.getMapper(SellerMapper.class);
-
@Mapping(source = "sellerEncPassword", target = "sellerPassword")
SellerEntity SellerDtoToSellerEntity(SellerDto SellerDto);
-
SellerDto sellerEntityToSellerDto(SellerEntity sellEntity);
-
SellerDto requestSellerInfoToSellerDto(RequestSellerInfo requestSellerInfo);
-
ResponseSellerInfo SellerDtoToResponseSellerInfo(SellerDto SellerDto);
}
diff --git a/SellerService/src/main/java/com/submarket/sellerservice/security/WebSecurity.java b/SellerService/src/main/java/com/submarket/sellerservice/security/WebSecurity.java
index deeff79..2501103 100644
--- a/SellerService/src/main/java/com/submarket/sellerservice/security/WebSecurity.java
+++ b/SellerService/src/main/java/com/submarket/sellerservice/security/WebSecurity.java
@@ -22,9 +22,7 @@ public class WebSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
-
- http.authorizeRequests().antMatchers("/**")
- .hasIpAddress(env.getProperty("gateway.ip")) // IP
+ http.authorizeRequests().antMatchers("/**").permitAll()
.and()
.addFilter(getAuthenticationFilter()); // Add Filter
diff --git a/SellerService/src/main/java/com/submarket/sellerservice/vo/RequestChangePassword.java b/SellerService/src/main/java/com/submarket/sellerservice/vo/RequestChangePassword.java
index 28109db..11bc7cf 100644
--- a/SellerService/src/main/java/com/submarket/sellerservice/vo/RequestChangePassword.java
+++ b/SellerService/src/main/java/com/submarket/sellerservice/vo/RequestChangePassword.java
@@ -1,5 +1,6 @@
package com.submarket.sellerservice.vo;
+import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
diff --git a/SellerService/src/main/java/com/submarket/sellerservice/vo/RequestLogin.java b/SellerService/src/main/java/com/submarket/sellerservice/vo/RequestLogin.java
index 421066b..3311a1b 100644
--- a/SellerService/src/main/java/com/submarket/sellerservice/vo/RequestLogin.java
+++ b/SellerService/src/main/java/com/submarket/sellerservice/vo/RequestLogin.java
@@ -1,5 +1,6 @@
package com.submarket.sellerservice.vo;
+import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
diff --git a/SellerService/src/main/java/com/submarket/sellerservice/vo/RequestSellerInfo.java b/SellerService/src/main/java/com/submarket/sellerservice/vo/RequestSellerInfo.java
index e4b71ad..284a65a 100644
--- a/SellerService/src/main/java/com/submarket/sellerservice/vo/RequestSellerInfo.java
+++ b/SellerService/src/main/java/com/submarket/sellerservice/vo/RequestSellerInfo.java
@@ -1,5 +1,6 @@
package com.submarket.sellerservice.vo;
+import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -12,30 +13,15 @@
@AllArgsConstructor
@NoArgsConstructor
public class RequestSellerInfo {
-
private int sellerSeq;
-
- @NotNull(message = "아이디를 입력해 주세요")
private String sellerId;
-
- @Size(min = 8, max = 40, message = "비밀번호는 8 ~ 40 글자 사이로 입력해주세요")
private String sellerPassword;
-
- @NotNull(message = "사업자 번호를 입력해주세요")
private String businessId;
-
- @NotNull(message = "연락처를 입력해주세요")
private String sellerPn;
-
- @Email(message = "Email 형식이 아닙니다")
private String sellerEmail;
-
- @NotNull(message = "주소를 입력해주세요")
private String sellerAddress;
private String sellerAddress2;
-
private String sellerHome;
-
private String sellerName;
}
diff --git a/UserService/.gitignore b/UserService/.gitignore
index 9fbbc11..21fcd4e 100644
--- a/UserService/.gitignore
+++ b/UserService/.gitignore
@@ -33,4 +33,4 @@ build/
.vscode/
/src/main/resources/application.yml
-/src/main/resources/bootstrap.yml
+/src/main/resources/bootstrap.yml
\ No newline at end of file
diff --git a/UserService/pom.xml b/UserService/pom.xml
index efb2dff..1df62f3 100644
--- a/UserService/pom.xml
+++ b/UserService/pom.xml
@@ -10,7 +10,7 @@
com.submarket
userservice
- 1.0.0
+ 2.0.0
UserService
UserService
@@ -175,6 +175,42 @@
spring-kafka
+
+
+ org.springframework.cloud
+ spring-cloud-starter-circuitbreaker-resilience4j
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-sleuth
+
+
+ org.springframework.cloud
+ spring-cloud-starter-zipkin
+ 2.2.3.RELEASE
+
+
+
+
+ io.micrometer
+ micrometer-registry-prometheus
+
+
+
+
+ org.springdoc
+ springdoc-openapi-ui
+ 1.6.6
+
+
diff --git a/UserService/src/main/java/com/submarket/userservice/UserServiceApplication.java b/UserService/src/main/java/com/submarket/userservice/UserServiceApplication.java
index 3715d6a..249a185 100644
--- a/UserService/src/main/java/com/submarket/userservice/UserServiceApplication.java
+++ b/UserService/src/main/java/com/submarket/userservice/UserServiceApplication.java
@@ -1,13 +1,17 @@
package com.submarket.userservice;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import feign.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@SpringBootApplication
@EnableEurekaClient
+@EnableFeignClients
public class UserServiceApplication {
public static void main(String[] args) {
@@ -19,4 +23,15 @@ public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
+ @Bean
+ public ObjectMapper objectMapper() {
+ return new ObjectMapper();
+ }
+
+
+ @Bean
+ public Logger.Level feignLoggerLevel() {
+ return Logger.Level.FULL;
+ }
+
}
diff --git a/UserService/src/main/java/com/submarket/userservice/client/ItemServiceClient.java b/UserService/src/main/java/com/submarket/userservice/client/ItemServiceClient.java
new file mode 100644
index 0000000..3ea1c92
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/client/ItemServiceClient.java
@@ -0,0 +1,20 @@
+package com.submarket.userservice.client;
+
+import com.submarket.userservice.dto.ItemDto;
+import com.submarket.userservice.vo.ItemInfoResponse;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+
+import java.util.Map;
+
+@FeignClient(name = "ITEM-SERVICE")
+public interface ItemServiceClient {
+ @GetMapping("/items/{itemSeq}") // 상품이 확인
+ ResponseEntity isItem(@PathVariable int itemSeq);
+
+
+ @GetMapping("/circuit/items/{itemSeq}") // 상품이 확인
+ ResponseEntity findOneItem(@PathVariable int itemSeq);
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/config/Resilience4JConfig.java b/UserService/src/main/java/com/submarket/userservice/config/Resilience4JConfig.java
new file mode 100644
index 0000000..db97d4c
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/config/Resilience4JConfig.java
@@ -0,0 +1,32 @@
+package com.submarket.userservice.config;
+
+import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
+import io.github.resilience4j.timelimiter.TimeLimiterConfig;
+import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory;
+import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder;
+import org.springframework.cloud.client.circuitbreaker.Customizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.time.Duration;
+
+@Configuration
+public class Resilience4JConfig {
+
+ @Bean
+ public Customizer globalCustomConfiguration() {
+ CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
+ .failureRateThreshold(4) // Open or False 100 중 4 번 실패 시 Open
+ .waitDurationInOpenState(Duration.ofMillis(1000)) // Open time (1s)
+ .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED) // 수 or 시간 기반
+ .slidingWindowSize(2).build();
+
+ TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom()
+ .timeoutDuration(Duration.ofSeconds(4)).build();
+
+ return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
+ .timeLimiterConfig(timeLimiterConfig)
+ .circuitBreakerConfig(circuitBreakerConfig).build());
+
+ }
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/config/SwaggerConfig.java b/UserService/src/main/java/com/submarket/userservice/config/SwaggerConfig.java
new file mode 100644
index 0000000..4d53cf3
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/config/SwaggerConfig.java
@@ -0,0 +1,44 @@
+package com.submarket.userservice.config;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import org.springdoc.core.GroupedOpenApi;
+import org.springdoc.core.customizers.OpenApiCustomiser;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SwaggerConfig {
+
+ @Bean
+ public GroupedOpenApi publicApi() {
+ return GroupedOpenApi.builder()
+ .group("UserServiceAPI")
+ .pathsToMatch("/**")
+ .addOpenApiCustomiser(buildSecurityOpenApi()) // JWT Setting Config
+ .build();
+ }
+
+ /**
+ * JWT Token Setting Config
+ * @return
+ */
+ public OpenApiCustomiser buildSecurityOpenApi() {
+ return OpenApi -> OpenApi.addSecurityItem(new SecurityRequirement().addList("jwt token"))
+ .getComponents()
+ .addSecuritySchemes("jwt token", new SecurityScheme()
+ .name("Authorization")
+ .type(SecurityScheme.Type.HTTP)
+ .in(SecurityScheme.In.HEADER)
+ .bearerFormat("JWT")
+ .scheme("bearer"));
+ }
+ @Bean
+ public OpenAPI springShopOpenAPI() {
+ return new OpenAPI()
+ .info(new Info().title("SubMarket - USER-SERVICE API")
+ .description("SubMarket UserService API 명세서").version("v2.0.0"));
+ }
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/constants/KafkaConstants.java b/UserService/src/main/java/com/submarket/userservice/constants/KafkaConstants.java
new file mode 100644
index 0000000..7ef7708
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/constants/KafkaConstants.java
@@ -0,0 +1,16 @@
+package com.submarket.userservice.constants;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class KafkaConstants {
+ public final static String TOPIC_NAME_SUB = "sub";
+ public final static String TOPIC_NAME_CANCEL_SUB = "sub-cancel";
+
+ public final static String TOPIC_NAME_ITEM_LIKED = "item-liked";
+
+ public final static String TOPIC_NAME_CANCEL_ITEM_LIKED = "item-liked-cancel";
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/controller/MainController.java b/UserService/src/main/java/com/submarket/userservice/controller/MainController.java
index 435abfd..a8dc0c8 100644
--- a/UserService/src/main/java/com/submarket/userservice/controller/MainController.java
+++ b/UserService/src/main/java/com/submarket/userservice/controller/MainController.java
@@ -1,34 +1,43 @@
package com.submarket.userservice.controller;
-import com.submarket.userservice.dto.SubDto;
import com.submarket.userservice.dto.UserDto;
+import com.submarket.userservice.jpa.LikeRepository;
import com.submarket.userservice.jpa.SubRepository;
import com.submarket.userservice.jpa.UserRepository;
-import com.submarket.userservice.jpa.entity.UserEntity;
-import com.submarket.userservice.mapper.UserMapper;
-import com.submarket.userservice.service.impl.KafkaProducerService;
-import com.submarket.userservice.service.impl.MailService;
+import com.submarket.userservice.jpa.entity.LikeEntity;
+import com.submarket.userservice.service.impl.KafkaProducerServiceImpl;
+import com.submarket.userservice.service.impl.MailServiceImpl;
+import io.micrometer.core.annotation.Timed;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.transaction.Transactional;
-import java.util.Optional;
@Slf4j
@RestController
@RequiredArgsConstructor
+@Tag(name = "Health API", description = "서버 상태 확인")
public class MainController {
private final Environment env;
- private final MailService mailService;
- private final UserRepository userRepository;
- private final SubRepository subRepository;
- private final KafkaProducerService kafkaProducerService;
+ @Operation(summary = "상태 확인", description = "인증 정보 없이 접근할 수 있는 EndPoint")
+ @ApiResponses({
+ @ApiResponse(responseCode = "503", description = "Eureka 서버에 미 등록"),
+ @ApiResponse(responseCode = "401", description = "Token 인증 실패"),
+ @ApiResponse(responseCode = "403", description = "Spring Security 인증 실패")
+
+ })
@GetMapping("/health")
+ @Timed(value = "user.health", longTask = true)
public String health() {
log.info("UserService On");
return env.getProperty("spring.application.name")
@@ -37,11 +46,4 @@ public String health() {
+ ", token secret : " + env.getProperty("token.secret")
+ ", token expiration time : " + env.getProperty("token.expiration_time");
}
-
- @GetMapping("/test")
- @Transactional
- public UserDto test() throws Exception {
-
- return null;
- }
}
diff --git a/UserService/src/main/java/com/submarket/userservice/controller/SubController.java b/UserService/src/main/java/com/submarket/userservice/controller/SubController.java
index 2f9597f..319bd95 100644
--- a/UserService/src/main/java/com/submarket/userservice/controller/SubController.java
+++ b/UserService/src/main/java/com/submarket/userservice/controller/SubController.java
@@ -3,9 +3,15 @@
import com.submarket.userservice.dto.SubDto;
import com.submarket.userservice.jpa.entity.SubEntity;
import com.submarket.userservice.mapper.SubMapper;
-import com.submarket.userservice.service.impl.SubService;
+import com.submarket.userservice.service.SubService;
+import com.submarket.userservice.service.impl.SubServiceImpl;
import com.submarket.userservice.util.TokenUtil;
-import com.submarket.userservice.vo.RequestSub;
+import com.submarket.userservice.vo.SubRequest;
+import io.micrometer.core.annotation.Timed;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
@@ -19,11 +25,17 @@
@RestController
@Slf4j
@RequiredArgsConstructor
+@Tag(name = "구독 API", description = "구독 관련 API")
public class SubController {
- private final SubService subService;
+ private final SubService subServiceImpl;
private final TokenUtil tokenUtil;
- @GetMapping("/sub")
+ @Operation(summary = "구독중인 상품 전체 조회", description = "사용자가 구독중인 모든 상품 점보를 조회", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "사용자 구독 정보 조회 성공")
+ })
+ @GetMapping("/subs")
+ @Timed(value = "user.sub.findAllSub", longTask = true)
public ResponseEntity> findAllSub(@RequestHeader HttpHeaders headers) throws Exception {
log.info(this.getClass().getName() + ".findSub Start!");
@@ -34,7 +46,7 @@ public ResponseEntity> findAllSub(@RequestHeader HttpHeaders
SubDto subDto = new SubDto();
subDto.setUserId(userId);
- List subEntityList = subService.findAllSub(subDto);
+ List subEntityList = subServiceImpl.findAllSub(subDto);
List subDtoList = new ArrayList<>();
@@ -47,17 +59,23 @@ public ResponseEntity> findAllSub(@RequestHeader HttpHeaders
return ResponseEntity.ok().body(rMap);
-
}
- @GetMapping("/sub/{subSeq}")
+
+ @Operation(summary = "구독중인 상품 상세 조회", description = "사용자가 가지고 있는 구독 상품 정보 상세 조회", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "사용자 구독 정보 조회 성공"),
+ @ApiResponse(responseCode = "404", description = "Seq 값과 일치하는 구독 정보 없음")
+ })
+ @GetMapping("/subs/{subSeq}")
+ @Timed(value = "user.sub.findOneSub", longTask = true)
public ResponseEntity findOneSub(@PathVariable int subSeq) throws Exception {
log.info(this.getClass().getName() + ".findOneSub Start!");
SubDto pDto = new SubDto();
pDto.setSubSeq(subSeq);
- SubDto subDto = subService.findOneSub(pDto);
+ SubDto subDto = subServiceImpl.findOneSub(pDto);
if (subDto == null) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
@@ -69,9 +87,16 @@ public ResponseEntity findOneSub(@PathVariable int subSeq) throws Except
return ResponseEntity.ok().body(subDto);
}
- @PostMapping("/sub")
+ @Operation(summary = "상품 구독 생성",
+ description = "사용자가 상품 주문 시 구독 생성 및 Kafka 를 통해 Item 수량 감소, Order 정보 생성", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "201", description = "사용자 구독 성공"),
+ @ApiResponse(responseCode = "400", description = "중복된 구독 생성")
+ })
+ @PostMapping("/subs")
+ @Timed(value = "user.sub.createSub", longTask = true)
public ResponseEntity createNewSub(@RequestHeader HttpHeaders headers,
- @RequestBody SubDto subDto) throws Exception{
+ @RequestBody SubDto subDto) throws Exception {
log.info(this.getClass().getName() + ".createNewSub Start!");
String userId = tokenUtil.getUserIdByToken(headers);
@@ -79,7 +104,7 @@ public ResponseEntity createNewSub(@RequestHeader HttpHeaders headers,
subDto.setUserId(userId);
- int res = subService.createNewSub(subDto);
+ int res = subServiceImpl.createNewSub(subDto);
if (res == 2) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("중복된 구독");
@@ -94,35 +119,48 @@ public ResponseEntity createNewSub(@RequestHeader HttpHeaders headers,
return ResponseEntity.status(HttpStatus.CREATED).body("구독 성공");
}
- @PostMapping("/sub/delete")
- public String cancelSub(@RequestBody RequestSub requestSub) throws Exception {
+ @Operation(summary = "상품 구독 취소",
+ description = "상품 구독 취소 및 Item 수량 복구", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "사용자 구독 취소 성공")
+ })
+ @PostMapping("/subs/delete")
+ @Timed(value = "user.sub.deleteSub", longTask = true)
+ public ResponseEntity cancelSub(@RequestBody SubRequest subRequest) throws Exception {
log.info(this.getClass().getName() + "cancel Sub Start!");
SubDto subDto = new SubDto();
- subDto.setSubSeq(requestSub.getSubSeq());
+ subDto.setSubSeq(subRequest.getSubSeq());
- int res = subService.cancelSub(subDto);
+ int res = subServiceImpl.cancelSub(subDto);
log.info(this.getClass().getName() + "cancel Sub End!");
if (res != 1) {
- return "구독 취소 실패";
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("구독 취소 실패");
}
- return "구독 취소 성공";
+ return ResponseEntity.status(HttpStatus.OK).body("구독 취소 성공");
}
- @PostMapping("/sub/update")
- public ResponseEntity updateSub(@RequestBody RequestSub requestSub) throws Exception {
+
+ @Operation(summary = "상품 구독 갱신",
+ description = "상품 구독 갱신 및 주문 생성 (월 단위 자동 호출)", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "사용자 구독 갱신 성공")
+ })
+ @PostMapping("/subs/update")
+ @Timed(value = "user.sub.updateUsb", longTask = true)
+ public ResponseEntity updateSub(@RequestBody SubRequest subRequest) throws Exception {
log.info(this.getClass().getName() + ".updateSub Start!");
SubDto subDto = new SubDto();
- subDto.setSubSeq(requestSub.getSubSeq());
+ subDto.setSubSeq(subRequest.getSubSeq());
- int res = subService.updateSub(subDto);
+ int res = subServiceImpl.updateSub(subDto);
if (res != 1) {
- return ResponseEntity.ok("갱신 실패");
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("갱신 실패");
}
log.info(this.getClass().getName() + "updateSub End!");
@@ -131,23 +169,36 @@ public ResponseEntity updateSub(@RequestBody RequestSub requestSub) thro
}
- @GetMapping("/seller/sub")
- public ResponseEntity findSubCount(@RequestBody Map request) throws Exception {
+
+ @Operation(summary = "판매자 상품 Count 조회",
+ description = "판매중인 상품 총 구독 수 조회", tags = {"seller"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "판매자 상품 조회 성공")
+ })
+ @GetMapping("/sellers/subs")
+ @Timed(value = "seller.sub.findSubCount", longTask = true)
+ public ResponseEntity findSubCount(@RequestBody Map request) throws Exception {
// Seller 가 보유하고 있는 상품의 SeqList 를 넘겨주면 총 구독 수를 표시
log.info(this.getClass().getName() + "findSubCount");
List itemSeqList = new LinkedList<>();
itemSeqList = (List) request.get("itemSeqList");
- int count = subService.findSubCount(itemSeqList);
+ int count = subServiceImpl.findSubCount(itemSeqList);
return ResponseEntity.status(HttpStatus.OK).body(count);
}
- @GetMapping("/seller/sub/{itemSeq}")
+ @Operation(summary = "판매자 단일 상품 구독 수 조회",
+ description = "판매중인 상품 별 구독 정보 조회", tags = {"seller"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "판매자 상품 조회 성공")
+ })
+ @GetMapping("/sellers/subs/{itemSeq}")
+ @Timed(value = "seller.sub.findOneSub", longTask = true)
public ResponseEntity findOneSubCount(@PathVariable int itemSeq) throws Exception {
log.info(this.getClass().getName() + "findOneSubCount Start!");
- int count = subService.findOneSubCount(itemSeq);
+ int count = subServiceImpl.findOneSubCount(itemSeq);
log.info(this.getClass().getName() + "findOneSubCount End!");
diff --git a/UserService/src/main/java/com/submarket/userservice/controller/UserController.java b/UserService/src/main/java/com/submarket/userservice/controller/UserController.java
index ad86f10..d1dbac5 100644
--- a/UserService/src/main/java/com/submarket/userservice/controller/UserController.java
+++ b/UserService/src/main/java/com/submarket/userservice/controller/UserController.java
@@ -1,52 +1,72 @@
package com.submarket.userservice.controller;
+import com.submarket.userservice.dto.ItemDto;
import com.submarket.userservice.dto.UserDto;
import com.submarket.userservice.mapper.UserMapper;
-import com.submarket.userservice.service.impl.MailService;
-import com.submarket.userservice.service.impl.UserCheckService;
-import com.submarket.userservice.service.impl.UserService;
+import com.submarket.userservice.service.UserCheckService;
+import com.submarket.userservice.service.UserItemService;
+import com.submarket.userservice.service.UserService;
+import com.submarket.userservice.service.impl.MailServiceImpl;
+import com.submarket.userservice.service.impl.UserCheckServiceImpl;
+import com.submarket.userservice.service.impl.UserServiceImpl;
import com.submarket.userservice.util.CmmUtil;
import com.submarket.userservice.util.TokenUtil;
-import com.submarket.userservice.vo.RequestChangePassword;
-import com.submarket.userservice.vo.RequestUser;
-import com.submarket.userservice.vo.ResponseUser;
+import com.submarket.userservice.vo.ItemLikedRequest;
+import com.submarket.userservice.vo.ChangePasswordRequest;
+import com.submarket.userservice.vo.UserRequest;
+import com.submarket.userservice.vo.UserResponse;
+import io.micrometer.core.annotation.Timed;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.apache.catalina.User;
-import org.springframework.core.env.Environment;
-import org.springframework.data.crossstore.ChangeSetPersister;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
+import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
+import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.UUID;
@Slf4j
@RestController
@RequiredArgsConstructor
-public class UserController {
- private final UserService userService;
- private final UserCheckService userCheckService;
- private final Environment env;
+@Tag(name = "사용자 API", description = "사용자 API")
+public class UserController {
+ private final UserService userServiceImpl;
+ private final UserCheckService userCheckServiceImpl;
private final TokenUtil tokenUtil;
- private final MailService mailService;
-
- /**<---------------------->회원가입---------------------->*/
+ private final MailServiceImpl mailServiceImpl;
+
+ private final UserItemService userItemService;
+
+ /**
+ * <---------------------->회원가입---------------------->
+ */
+ @Operation(summary = "사용자 회원가입", description = "사용자 회원가입 (인증 X)", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "201", description = "사용자 회원가입 성공"),
+ @ApiResponse(responseCode = "409", description = "사용자 아이디 또는 이메일 중복 발생")
+ })
@PostMapping("/users")
- public ResponseEntity createUser(@RequestBody RequestUser requestUser) throws Exception {
+ @Timed(value = "user.createUser", longTask = true)
+ public ResponseEntity createUser(@RequestBody UserRequest userRequest) throws Exception {
log.info("--------------> " + this.getClass().getName() + ".createUser Start!");
int res = 0;
- if (!userCheckService.checkUserByUserId(requestUser.getUserId())) {
+ if (!userCheckServiceImpl.checkUserByUserId(userRequest.getUserId())) {
// 아이디 중복
return ResponseEntity.status(HttpStatus.CONFLICT).body("중복된 아이디 입니다.");
}
- UserDto pDTO = UserMapper.INSTANCE.RequestUserToUserDto(requestUser);
+ UserDto pDTO = UserMapper.INSTANCE.RequestUserToUserDto(userRequest);
- res = userService.createUser(pDTO);
+ res = userServiceImpl.createUser(pDTO);
if (res == 0) { /** 아이디 중복 발생 */
return ResponseEntity.status(HttpStatus.CONFLICT).body("중복된 이메일 입니다"); // 충돌 발생
@@ -57,8 +77,13 @@ public ResponseEntity createUser(@RequestBody RequestUser requestUser) t
return ResponseEntity.status(HttpStatus.CREATED).body("회원가입 성공");
}
- @GetMapping("/user")
- public ResponseEntity getUserInfo(@RequestHeader HttpHeaders headers) throws Exception {
+ @Operation(summary = "사용자 정보 조회", description = "토큰 정보를 사용하여 사용자 정보 조회", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "사용자 정보 조회 성공")
+ })
+ @GetMapping("/users")
+ @Timed(value = "user.getUser", longTask = true)
+ public ResponseEntity getUserInfo(@RequestHeader HttpHeaders headers) throws Exception {
log.info(this.getClass().getName() + "getUserInfo Start!");
// 사용자 토큰을 사용하여 사용자 정보 조회
String userId = tokenUtil.getUserIdByToken(headers);
@@ -67,19 +92,26 @@ public ResponseEntity getUserInfo(@RequestHeader HttpHeaders heade
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
- UserDto userDto = userService.getUserInfoByUserId(userId);
+ UserDto userDto = userServiceImpl.getUserInfoByUserId(userId);
- ResponseUser responseUser = UserMapper.INSTANCE.UserDtoToResponseUser(userDto);
+ UserResponse userResponse = UserMapper.INSTANCE.UserDtoToResponseUser(userDto);
log.info(this.getClass().getName() + "getUserInfo End!");
- return ResponseEntity.ok().body(responseUser);
+ return ResponseEntity.ok().body(userResponse);
}
-
- /**<------------------------>아이디 중복 확인------------------------>*/
+ @Operation(summary = "사용자 아이디 중복 확인", description = "회원가입 전 사용자 아이디 중복 확인", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "사용 가능한 아이디"),
+ @ApiResponse(responseCode = "409", description = "중복된 아이디")
+ })
+ /**
+ * <------------------------>아이디 중복 확인------------------------>
+ */
@GetMapping("/users/check-id/{userId}")
+ @Timed(value = "user.check.id", longTask = true)
public ResponseEntity checkUserById(@PathVariable String userId) throws Exception {
log.info("-------------------- > " + this.getClass().getName() + "checkId Start!");
- boolean checkId = userCheckService.checkUserByUserId(userId);
+ boolean checkId = userCheckServiceImpl.checkUserByUserId(userId);
if (checkId) {
log.info("-------------------- > " + this.getClass().getName() + "checkId End!");
@@ -89,11 +121,19 @@ public ResponseEntity checkUserById(@PathVariable String userId) throws
return ResponseEntity.status(HttpStatus.CONFLICT).body("아이디 중복 입니다");
}
- /**<------------------------>이메일 중복 확인------------------------>*/
+ @Operation(summary = "사용자 이메일 중복 확인", description = "회원가입 전 사용자 이메일 중복 확인", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "사용 가능한 이메일"),
+ @ApiResponse(responseCode = "409", description = "중복된 이메일")
+ })
+ /**
+ * <------------------------>이메일 중복 확인------------------------>
+ */
@GetMapping("/users/check-email/{userEmail}")
+ @Timed(value = "user.check.email", longTask = true)
public ResponseEntity checkUserByEmail(@PathVariable String userEmail) throws Exception {
log.info("-------------------- > " + this.getClass().getSimpleName() + "checkEmail Start!");
- boolean checkEmail = userCheckService.checkUserByUserEmail(userEmail);
+ boolean checkEmail = userCheckServiceImpl.checkUserByUserEmail(userEmail);
if (checkEmail) {
log.info("-------------------- > " + this.getClass().getName() + "checkEmail End!");
@@ -105,12 +145,20 @@ public ResponseEntity checkUserByEmail(@PathVariable String userEmail) t
}
- /**<------------------------>아이디 찾기 with UserEmail ------------------------>
- * 만약 Email 이 같다면 아이디 정보 일부를 제공*/
+ /**
+ * <------------------------>아이디 찾기 with UserEmail ------------------------>
+ * 만약 Email 이 같다면 아이디 정보 일부를 제공
+ */
+ @Operation(summary = "사용자 아이디 찾기", description = "Email을 기반으로 사용자 아이디 찾기", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "사용 가능한 아이디"),
+ @ApiResponse(responseCode = "404", description = "사용자 정보를 찾을 수 없음")
+ })
@GetMapping("/users/find-id/{userEmail}")
+ @Timed(value = "user.find.id", longTask = true)
public ResponseEntity findUserId(@PathVariable String userEmail) throws Exception {
log.info("-------------------- > " + this.getClass().getName() + "findUserId Start!");
- UserDto rDTO = userService.getUserInfoByUserEmail(userEmail);
+ UserDto rDTO = userServiceImpl.getUserInfoByUserEmail(userEmail);
String userId;
if (rDTO == null) { /** 유저 정보가 없을 경우 Not Found return */
@@ -122,10 +170,18 @@ public ResponseEntity findUserId(@PathVariable String userEmail) throws
return ResponseEntity.status(HttpStatus.OK).body(userId);
}
- /**<------------------------>비밀번호 변경------------------------>*/
+ /**
+ * <------------------------>비밀번호 변경------------------------>
+ */
+ @Operation(summary = "사용자 비밀번호 변경", description = "이전 비밀번호 일치 시 비밀번호 변경", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "비밀번호 변경 성공"),
+ @ApiResponse(responseCode = "400", description = "이전 비밀번호가 일치하지 않습니다")
+ })
@PostMapping("/users/changePassword")
+ @Timed(value = "user.change.password", longTask = true)
public ResponseEntity changePassword(@RequestHeader HttpHeaders headers,
- @RequestBody RequestChangePassword request) throws Exception {
+ @RequestBody ChangePasswordRequest request) throws Exception {
String userId = tokenUtil.getUserIdByToken(headers);
log.info("userId : " + userId);
@@ -133,7 +189,7 @@ public ResponseEntity changePassword(@RequestHeader HttpHeaders headers,
pDTO.setUserId(userId);
pDTO.setUserPassword(request.getOldPassword());
- int check = userService.changeUserPassword(pDTO, request.getNewPassword());
+ int check = userServiceImpl.changeUserPassword(pDTO, request.getNewPassword());
if (check == 1) { // 변경 성공
return ResponseEntity.status(HttpStatus.OK).body("비밀번호 변경 성공");
@@ -142,16 +198,22 @@ public ResponseEntity changePassword(@RequestHeader HttpHeaders headers,
}
- @PostMapping("/user/modify")
+ @Operation(summary = "사용자 정보 변경", description = "사용자 정보를 변경", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "사용자 정보 변경 성공"),
+ @ApiResponse(responseCode = "400", description = "사용자 정보 변경 실패")
+ })
+ @PostMapping("/users/modify")
+ @Timed(value = "user.change.userInfo", longTask = true)
public ResponseEntity modifyUserInfo(@RequestHeader HttpHeaders headers, @RequestBody UserDto body)
- throws Exception {
+ throws Exception {
log.info(this.getClass().getName() + ".modifyUserInfo Start!");
String userId = tokenUtil.getUserIdByToken(headers);
log.info("userEmail in Controller : " + body.getUserEmail());
body.setUserId(userId);
- int res = userService.modifyUserInfo(body);
+ int res = userServiceImpl.modifyUserInfo(body);
if (res == 1) {
return ResponseEntity.ok().body("변경 성공");
} else {
@@ -159,22 +221,30 @@ public ResponseEntity modifyUserInfo(@RequestHeader HttpHeaders headers,
}
}
- @PostMapping("/user/fix/find-password")
+
+ @Operation(summary = "사용자 비밀번호 찾기", description = "인증 후 사용자 임시 비밀번호를 Mail로 전송", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "Email 로 임시 비밀번호 전송 성공"),
+ @ApiResponse(responseCode = "400", description = "이메일 정보가 일치하지 않음"),
+ @ApiResponse(responseCode = "400", description = "아이디로 사용자 정보를 찾을 수 없음")
+ })
+ @PostMapping("/users/fix/find-password")
+ @Timed(value = "user.find.password", longTask = true)
public ResponseEntity findPassword(@RequestBody UserDto userDto) throws Exception {
log.info(this.getClass().getName() + ".findPassword Start");
String userId = CmmUtil.nvl(userDto.getUserId());
String userEmail = CmmUtil.nvl(userDto.getUserEmail());
- if (!userCheckService.checkUserByUserId(userId)) {
+ if (!userCheckServiceImpl.checkUserByUserId(userId)) {
// 아이디가 중복 = DB 에 있음
- UserDto checkDto = userService.getUserInfoByUserId(userId);
+ UserDto checkDto = userServiceImpl.getUserInfoByUserId(userId);
if (checkDto.getUserEmail().equals(userEmail)) {
// Id로 조회한 Email in DB 값과 넘어온 값이 같으면 Mail 전송
String exPassword = String.valueOf(UUID.randomUUID());
- userService.changeUserPasswordNoAuthorization(userId, exPassword);
+ userServiceImpl.changeUserPasswordNoAuthorization(userId, exPassword);
- mailService.sendMail(userDto.getUserEmail(), "비밀번호 변경", "임시 비밀번호 : " + exPassword + "입니다.");
+ mailServiceImpl.sendMail(userDto.getUserEmail(), "비밀번호 변경", "임시 비밀번호 : " + exPassword + "입니다.");
} else {
@@ -189,8 +259,16 @@ public ResponseEntity findPassword(@RequestBody UserDto userDto) throws
return ResponseEntity.ok().body(userEmail + "로 임시 비밀번호를 발송 했습니다");
}
- @PostMapping("/user/delete")
- public ResponseEntity deleteUser(@RequestHeader HttpHeaders headers, @RequestBody RequestUser requestUser) throws Exception {
+
+ @Operation(summary = "사용자 삭제 (비활성화)", description = "인증 후 사용자 정보를 비활성화", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "사용자 정보 비활성화 (탈퇴) 성공"),
+ @ApiResponse(responseCode = "400", description = "이메일 정보가 일치하지 않음"),
+ @ApiResponse(responseCode = "400", description = "사용자 비밀번호가 일치하지 않음")
+ })
+ @PostMapping("/users/delete")
+ @Timed(value = "user.deleteUser", longTask = true)
+ public ResponseEntity deleteUser(@RequestHeader HttpHeaders headers, @RequestBody UserRequest userRequest) throws Exception {
/**
* 비밀번호가 일치한다면
* 사용자 Status 0으로 변경
@@ -200,13 +278,85 @@ public ResponseEntity deleteUser(@RequestHeader HttpHeaders headers, @Re
// GetUserId from Token
String userId = tokenUtil.getUserIdByToken(headers);
UserDto pDto = new UserDto();
- pDto.setUserPassword(requestUser.getUserPassword());
+ pDto.setUserPassword(userRequest.getUserPassword());
pDto.setUserId(userId);
- userService.deleteUser(pDto);
+ userServiceImpl.deleteUser(pDto);
log.info(this.getClass().getName() + ".deleteUser Start!");
return ResponseEntity.ok().body("회원탈퇴 완료");
}
+
+ /**
+ * 좋아요 생성 or 삭제 (이미 있다면 삭제)
+ *
+ * @param headers Token
+ * @param request itemSeq
+ * @return String 결과
+ * @throws Exception
+ */
+ @Operation(summary = "사용자 상품 좋아요", description = "사용자 상품 좋아요", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "상품 좋아요 성공"),
+ @ApiResponse(responseCode = "200", description = "이미 좋아요를 누른 상태라면, 좋아요 취소"),
+ @ApiResponse(responseCode = "400", description = "상품 번호와 일치하는 상품 정보가 없음")
+ })
+ @PostMapping("/users/items/liked")
+ @Timed(value = "user.like", longTask = true)
+ public ResponseEntity itemLiked(@RequestHeader final HttpHeaders headers,
+ @RequestBody @Validated final ItemLikedRequest request) throws Exception {
+
+ final String userId = tokenUtil.getUserIdByToken(headers);
+
+ log.debug("userId : " + userId);
+
+ return ResponseEntity.ok().body(userItemService.itemLikedOrDelete(userId, request.getItemSeq()));
+ }
+
+ @Operation(summary = "사용자 상품 좋아요 확인", description = "사용자 상품 좋아요 유무 확인", tags = {"user"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "사용자 상품 좋아요 유무 확인 성공")
+ })
+ @GetMapping("/users/{userId}/items/{itemSeq}/liked")
+ @Timed(value = "user.like", longTask = true)
+ public ResponseEntity isItemLiked(@PathVariable int itemSeq, @PathVariable String userId) throws Exception {
+ log.info("isItemLiked Start!");
+
+ log.info("테스트 로그 사용자 상품 좋아요 확인하기");
+ final int result = userItemService.likedItemByUserId(userId, itemSeq);
+
+ log.info("result : " + result);
+
+ log.info("isItemLiked Start! ");
+
+
+ return ResponseEntity.ok().body(result);
+
+ }
+
+
+ @Operation(summary = "좋아요한 상품 목록 조회", description = "사용자가 좋아요한 상품 정보 조회", tags = {"user", "item"})
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "좋아요한 상품 목록 조회 성공")
+ })
+ @GetMapping("/users/items/liked")
+ public ResponseEntity> findAllLikedItems(@RequestHeader final HttpHeaders headers) throws Exception {
+ log.info(this.getClass().getName() + ".findAllLikedItems Start!");
+
+ Map responseBody = new HashMap<>();
+
+
+ List result = userItemService.findAllLikedItems(tokenUtil.getUserIdByToken(headers));
+
+ responseBody.put("userId", tokenUtil.getUserIdByToken(headers));
+ responseBody.put("response", result);
+
+
+ log.info(this.getClass().getName() + ".findAllLikedItems End!");
+
+
+ return ResponseEntity.ok().body(responseBody);
+ }
+
}
diff --git a/UserService/src/main/java/com/submarket/userservice/dto/ItemDto.java b/UserService/src/main/java/com/submarket/userservice/dto/ItemDto.java
new file mode 100644
index 0000000..5ff76c3
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/dto/ItemDto.java
@@ -0,0 +1,37 @@
+package com.submarket.userservice.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ItemDto {
+ private int itemSeq;
+ private String sellerId;
+ private String itemTitle;
+ private String itemContents;
+ private int itemPrice;
+ private int itemCount; // 상품 수
+ private int categorySeq;
+ private int itemStatus; // 활성화
+ private int readCount20;
+ private int readCount30;
+ private int readCount40;
+ private int readCountOther;
+ private int userAge;
+ private String mainImagePath; // DB에 저장되어 있는 이미지 정보
+ private String subImagePath;
+ private int isUserLiked;
+
+
+ private MultipartFile mainImage; // Front 에서 넘어온 이미지
+ private MultipartFile subImage; // Image 2
+
+}
\ No newline at end of file
diff --git a/UserService/src/main/java/com/submarket/userservice/dto/LikeDto.java b/UserService/src/main/java/com/submarket/userservice/dto/LikeDto.java
new file mode 100644
index 0000000..2268191
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/dto/LikeDto.java
@@ -0,0 +1,21 @@
+package com.submarket.userservice.dto;
+
+import com.submarket.userservice.jpa.entity.UserEntity;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.minidev.json.annotate.JsonIgnore;
+
+import javax.persistence.*;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class LikeDto {
+ private long likeSeq;
+ private int itemSeq;
+
+ private String userId;
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/exception/ErrorResponse.java b/UserService/src/main/java/com/submarket/userservice/exception/ErrorResponse.java
new file mode 100644
index 0000000..652dbf5
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/exception/ErrorResponse.java
@@ -0,0 +1,13 @@
+package com.submarket.userservice.exception;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+@Builder
+public class ErrorResponse {
+ private final String code;
+ private final String message;
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/exception/ItemException.java b/UserService/src/main/java/com/submarket/userservice/exception/ItemException.java
new file mode 100644
index 0000000..7b937e8
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/exception/ItemException.java
@@ -0,0 +1,11 @@
+package com.submarket.userservice.exception;
+
+import com.submarket.userservice.exception.result.ItemExceptionResult;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+public class ItemException extends RuntimeException{
+ private final ItemExceptionResult exceptionResult;
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/exception/SubException.java b/UserService/src/main/java/com/submarket/userservice/exception/SubException.java
new file mode 100644
index 0000000..ca977cb
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/exception/SubException.java
@@ -0,0 +1,13 @@
+package com.submarket.userservice.exception;
+
+import com.submarket.userservice.exception.result.SubExceptionResult;
+import com.submarket.userservice.exception.result.UserExceptionResult;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Getter
+public class SubException extends RuntimeException {
+
+ private final SubExceptionResult exceptionResult;
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/exception/UserException.java b/UserService/src/main/java/com/submarket/userservice/exception/UserException.java
new file mode 100644
index 0000000..254e591
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/exception/UserException.java
@@ -0,0 +1,12 @@
+package com.submarket.userservice.exception;
+
+import com.submarket.userservice.exception.result.UserExceptionResult;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Getter
+public class UserException extends RuntimeException {
+
+ private final UserExceptionResult exceptionResult;
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/exception/UserServiceExceptionHandler.java b/UserService/src/main/java/com/submarket/userservice/exception/UserServiceExceptionHandler.java
new file mode 100644
index 0000000..13ad59a
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/exception/UserServiceExceptionHandler.java
@@ -0,0 +1,51 @@
+package com.submarket.userservice.exception;
+
+import com.submarket.userservice.exception.result.ItemExceptionResult;
+import com.submarket.userservice.exception.result.SubExceptionResult;
+import com.submarket.userservice.exception.result.UserExceptionResult;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+
+@RestControllerAdvice
+@Slf4j
+public class UserServiceExceptionHandler extends ResponseEntityExceptionHandler {
+
+ @ExceptionHandler(UserException.class)
+ public ResponseEntity handleUserException(final UserException exception) {
+ log.warn("UserException occur : ", exception);
+ return this.makeErrorResponseEntity(exception.getExceptionResult());
+
+ }
+
+ @ExceptionHandler(SubException.class)
+ public ResponseEntity handleSubException(final SubException exception) {
+ log.warn("SubException occur : ", exception);
+ return this.makeErrorResponseEntity(exception.getExceptionResult());
+
+ }
+
+ @ExceptionHandler(ItemException.class)
+ public ResponseEntity handleItemException(final ItemException exception) {
+ log.warn("ItemException occur : ", exception);
+ return this.makeErrorResponseEntity(exception.getExceptionResult());
+
+ }
+
+ private ResponseEntity makeErrorResponseEntity(final UserExceptionResult exceptionResult) {
+ return ResponseEntity.status(exceptionResult.getStatus())
+ .body(new ErrorResponse(exceptionResult.name(), exceptionResult.getMessage()));
+ }
+
+ private ResponseEntity makeErrorResponseEntity(final SubExceptionResult exceptionResult) {
+ return ResponseEntity.status(exceptionResult.getStatus())
+ .body(new ErrorResponse(exceptionResult.name(), exceptionResult.getMessage()));
+ }
+
+ private ResponseEntity makeErrorResponseEntity(final ItemExceptionResult exceptionResult) {
+ return ResponseEntity.status(exceptionResult.getStatus())
+ .body(new ErrorResponse(exceptionResult.name(), exceptionResult.getMessage()));
+ }
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/exception/result/ItemExceptionResult.java b/UserService/src/main/java/com/submarket/userservice/exception/result/ItemExceptionResult.java
new file mode 100644
index 0000000..12083d6
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/exception/result/ItemExceptionResult.java
@@ -0,0 +1,14 @@
+package com.submarket.userservice.exception.result;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+
+@Getter
+@RequiredArgsConstructor
+public enum ItemExceptionResult {
+ NOT_MATCHED_ITEM_SEQ(HttpStatus.BAD_REQUEST, "잘못된 상품 번호 입니다"),
+ ;
+ private final HttpStatus status;
+ private final String message;
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/exception/result/SubExceptionResult.java b/UserService/src/main/java/com/submarket/userservice/exception/result/SubExceptionResult.java
new file mode 100644
index 0000000..153fe1d
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/exception/result/SubExceptionResult.java
@@ -0,0 +1,15 @@
+package com.submarket.userservice.exception.result;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+
+@RequiredArgsConstructor
+@Getter
+public enum SubExceptionResult {
+ CAN_NOT_FOUND_SUB_INFO(HttpStatus.NOT_FOUND, "일치하는 구독 정보를 찾을 수 없습니다"),
+ ;
+
+ private final HttpStatus status;
+ private final String message;
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/exception/result/UserExceptionResult.java b/UserService/src/main/java/com/submarket/userservice/exception/result/UserExceptionResult.java
new file mode 100644
index 0000000..5ac297a
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/exception/result/UserExceptionResult.java
@@ -0,0 +1,18 @@
+package com.submarket.userservice.exception.result;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+
+@Getter
+@RequiredArgsConstructor
+public enum UserExceptionResult {
+ USER_NOT_FOUNT(HttpStatus.NOT_FOUND, "사용자 정보를 찾을 수 없습니다"),
+ CAN_NOT_CREATE_KAFKA_TOPIC(HttpStatus.INTERNAL_SERVER_ERROR, "Exception in Kafka"),
+ USER_PASSWORD_NOT_MATCHED(HttpStatus.BAD_REQUEST, "사용자 비밀번호가 일치하지 않습니다"),
+ ;
+
+
+ private final HttpStatus status;
+ private final String message;
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/jpa/LikeRepository.java b/UserService/src/main/java/com/submarket/userservice/jpa/LikeRepository.java
new file mode 100644
index 0000000..b3c6b5f
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/jpa/LikeRepository.java
@@ -0,0 +1,19 @@
+package com.submarket.userservice.jpa;
+
+import com.submarket.userservice.jpa.entity.LikeEntity;
+import com.submarket.userservice.jpa.entity.UserEntity;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Optional;
+
+@Repository
+public interface LikeRepository extends CrudRepository {
+
+
+ Optional findByUserAndItemSeq(UserEntity user, int itemSeq);
+
+ Optional> findAllByUser(UserEntity user);
+
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/jpa/SubRepository.java b/UserService/src/main/java/com/submarket/userservice/jpa/SubRepository.java
index 6153aef..1f87901 100644
--- a/UserService/src/main/java/com/submarket/userservice/jpa/SubRepository.java
+++ b/UserService/src/main/java/com/submarket/userservice/jpa/SubRepository.java
@@ -12,7 +12,6 @@
import java.util.List;
@Repository
-@Transactional
public interface SubRepository extends CrudRepository {
// 구독 갱신 (Count += 1, Date 변경)
diff --git a/UserService/src/main/java/com/submarket/userservice/jpa/entity/LikeEntity.java b/UserService/src/main/java/com/submarket/userservice/jpa/entity/LikeEntity.java
new file mode 100644
index 0000000..f1c5b2b
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/jpa/entity/LikeEntity.java
@@ -0,0 +1,29 @@
+package com.submarket.userservice.jpa.entity;
+
+import com.fasterxml.jackson.annotation.JsonBackReference;
+import lombok.*;
+import net.minidev.json.annotate.JsonIgnore;
+
+import javax.persistence.*;
+
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Entity
+@Table(name = "likeInfo")
+@ToString(exclude = "user")
+@Builder
+public class LikeEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Integer likeSeq;
+
+ @Column(nullable = false)
+ private int itemSeq;
+
+ @JsonBackReference
+ @ManyToOne(fetch = FetchType.LAZY, optional = false)
+ @JsonIgnore
+ private UserEntity user;
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/jpa/entity/SubEntity.java b/UserService/src/main/java/com/submarket/userservice/jpa/entity/SubEntity.java
index 99fcd78..48d1b88 100644
--- a/UserService/src/main/java/com/submarket/userservice/jpa/entity/SubEntity.java
+++ b/UserService/src/main/java/com/submarket/userservice/jpa/entity/SubEntity.java
@@ -1,10 +1,8 @@
package com.submarket.userservice.jpa.entity;
+import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
+import lombok.*;
import net.minidev.json.annotate.JsonIgnore;
import javax.persistence.*;
@@ -14,7 +12,7 @@
@NoArgsConstructor
@Entity
@Table(name = "subInfo")
-@JsonIgnoreProperties({"user"})
+@ToString(exclude = "user")
@Builder
public class SubEntity {
@@ -31,6 +29,7 @@ public class SubEntity {
@Column(nullable = false)
private int subCount;
+ @JsonBackReference
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JsonIgnore
private UserEntity user;
diff --git a/UserService/src/main/java/com/submarket/userservice/jpa/entity/UserEntity.java b/UserService/src/main/java/com/submarket/userservice/jpa/entity/UserEntity.java
index 994c05d..650c193 100644
--- a/UserService/src/main/java/com/submarket/userservice/jpa/entity/UserEntity.java
+++ b/UserService/src/main/java/com/submarket/userservice/jpa/entity/UserEntity.java
@@ -1,5 +1,6 @@
package com.submarket.userservice.jpa.entity;
+import com.fasterxml.jackson.annotation.JsonManagedReference;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
@@ -7,6 +8,7 @@
import javax.persistence.*;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
@Entity
@@ -47,6 +49,11 @@ public class UserEntity {
@Column(length = 80)
private String userAddress2;
+ @JsonManagedReference
@OneToMany(mappedBy = "user")
- private List subEntityList = new ArrayList<>();
+ private List subEntityList;
+
+ @JsonManagedReference
+ @OneToMany(mappedBy = "user")
+ private List likeEntityList;
}
diff --git a/UserService/src/main/java/com/submarket/userservice/mapper/SubMapper.java b/UserService/src/main/java/com/submarket/userservice/mapper/SubMapper.java
index a73caca..f68e9ea 100644
--- a/UserService/src/main/java/com/submarket/userservice/mapper/SubMapper.java
+++ b/UserService/src/main/java/com/submarket/userservice/mapper/SubMapper.java
@@ -2,7 +2,6 @@
import com.submarket.userservice.dto.SubDto;
import com.submarket.userservice.jpa.entity.SubEntity;
-import com.submarket.userservice.vo.ResponseSub;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@@ -10,11 +9,7 @@
@Mapper
public interface SubMapper {
SubMapper INSTANCE = Mappers.getMapper(SubMapper.class);
-
- SubEntity subDtoToSubEntity(SubDto subDto);
-
@Mapping(target = "user", ignore = true) // Entity 를 DTO 에 담을 때 user 정보 무시
SubDto subEntityToSubDto(SubEntity subEntity);
-
- ResponseSub responseSubToSubDto(SubDto subDto);
+ SubEntity subDtoToSubEntity(SubDto subDto);
}
diff --git a/UserService/src/main/java/com/submarket/userservice/mapper/UserMapper.java b/UserService/src/main/java/com/submarket/userservice/mapper/UserMapper.java
index b64e83e..1783527 100644
--- a/UserService/src/main/java/com/submarket/userservice/mapper/UserMapper.java
+++ b/UserService/src/main/java/com/submarket/userservice/mapper/UserMapper.java
@@ -2,8 +2,8 @@
import com.submarket.userservice.dto.UserDto;
import com.submarket.userservice.jpa.entity.UserEntity;
-import com.submarket.userservice.vo.RequestUser;
-import com.submarket.userservice.vo.ResponseUser;
+import com.submarket.userservice.vo.UserRequest;
+import com.submarket.userservice.vo.UserResponse;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@@ -21,8 +21,8 @@ public interface UserMapper{
UserDto userEntityToUserDto(UserEntity userEntity);
- UserDto RequestUserToUserDto(RequestUser requestUser);
+ UserDto RequestUserToUserDto(UserRequest userRequest);
- ResponseUser UserDtoToResponseUser(UserDto userDto);
+ UserResponse UserDtoToResponseUser(UserDto userDto);
}
diff --git a/UserService/src/main/java/com/submarket/userservice/security/AuthenticationFilter.java b/UserService/src/main/java/com/submarket/userservice/security/AuthenticationFilter.java
index 549eaf8..02418d3 100644
--- a/UserService/src/main/java/com/submarket/userservice/security/AuthenticationFilter.java
+++ b/UserService/src/main/java/com/submarket/userservice/security/AuthenticationFilter.java
@@ -2,8 +2,9 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.submarket.userservice.dto.UserDto;
-import com.submarket.userservice.service.impl.UserService;
-import com.submarket.userservice.vo.RequestLogin;
+import com.submarket.userservice.service.UserService;
+import com.submarket.userservice.service.impl.UserServiceImpl;
+import com.submarket.userservice.vo.LoginRequest;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
@@ -29,7 +30,7 @@ public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private Environment env;
public AuthenticationFilter(AuthenticationManager authenticationManager,
- UserService userService, Environment env) {
+ UserServiceImpl userService, Environment env) {
super.setAuthenticationManager(authenticationManager);
this.userService = userService;
this.env = env;
@@ -38,7 +39,7 @@ public AuthenticationFilter(AuthenticationManager authenticationManager,
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
try {
- RequestLogin creds = new ObjectMapper().readValue(request.getInputStream(), RequestLogin.class);
+ LoginRequest creds = new ObjectMapper().readValue(request.getInputStream(), LoginRequest.class);
return getAuthenticationManager().authenticate(
new UsernamePasswordAuthenticationToken(
diff --git a/UserService/src/main/java/com/submarket/userservice/security/WebSecurity.java b/UserService/src/main/java/com/submarket/userservice/security/WebSecurity.java
index 3365be9..c8b9331 100644
--- a/UserService/src/main/java/com/submarket/userservice/security/WebSecurity.java
+++ b/UserService/src/main/java/com/submarket/userservice/security/WebSecurity.java
@@ -1,13 +1,15 @@
package com.submarket.userservice.security;
-import com.submarket.userservice.service.impl.UserService;
+import com.submarket.userservice.service.impl.UserServiceImpl;
import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@@ -15,24 +17,27 @@
@EnableWebSecurity
@RequiredArgsConstructor
public class WebSecurity extends WebSecurityConfigurerAdapter {
- private final UserService userService;
+ private final UserServiceImpl userServiceImpl;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final Environment env;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
- http.authorizeRequests().antMatchers("/**")
- .hasIpAddress(env.getProperty("gateway.ip")) // IP
+
+ http.authorizeRequests()
+// .antMatchers("/user-service/**", "/actuator/**").hasIpAddress("20.39.193.121") // IP
+ .antMatchers("/**").permitAll()
.and()
.addFilter(getAuthenticationFilter()); // Add Filter
http.headers().frameOptions().disable();
}
+
private AuthenticationFilter getAuthenticationFilter() throws Exception {
AuthenticationFilter authenticationFilter =
- new AuthenticationFilter(authenticationManager(), userService, env);
+ new AuthenticationFilter(authenticationManager(), userServiceImpl, env);
return authenticationFilter;
}
@@ -40,6 +45,6 @@ private AuthenticationFilter getAuthenticationFilter() throws Exception {
// Check Password
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
- auth.userDetailsService(userService).passwordEncoder(bCryptPasswordEncoder);
+ auth.userDetailsService(userServiceImpl).passwordEncoder(bCryptPasswordEncoder);
}
}
\ No newline at end of file
diff --git a/UserService/src/main/java/com/submarket/userservice/service/IKafkaProducerService.java b/UserService/src/main/java/com/submarket/userservice/service/IKafkaProducerService.java
deleted file mode 100644
index 35a6699..0000000
--- a/UserService/src/main/java/com/submarket/userservice/service/IKafkaProducerService.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.submarket.userservice.service;
-
-import com.submarket.userservice.dto.SubDto;
-
-public interface IKafkaProducerService {
- void createNewSub(SubDto subDto) throws Exception;
-
- void cancelSub(SubDto subDto) throws Exception;
-}
diff --git a/UserService/src/main/java/com/submarket/userservice/service/KafkaProducerService.java b/UserService/src/main/java/com/submarket/userservice/service/KafkaProducerService.java
new file mode 100644
index 0000000..40580e9
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/service/KafkaProducerService.java
@@ -0,0 +1,15 @@
+package com.submarket.userservice.service;
+
+import com.submarket.userservice.dto.LikeDto;
+import com.submarket.userservice.dto.SubDto;
+
+public interface KafkaProducerService {
+ void createNewSub(SubDto subDto) throws Exception;
+
+ void cancelSub(SubDto subDto) throws Exception;
+
+
+ void createItemLike(LikeDto likeDto) throws Exception;
+
+ void cancelItemLike(LikeDto likeDto) throws Exception;
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/service/ISubCheckService.java b/UserService/src/main/java/com/submarket/userservice/service/SubCheckService.java
similarity index 84%
rename from UserService/src/main/java/com/submarket/userservice/service/ISubCheckService.java
rename to UserService/src/main/java/com/submarket/userservice/service/SubCheckService.java
index 6fe70c0..e93e63e 100644
--- a/UserService/src/main/java/com/submarket/userservice/service/ISubCheckService.java
+++ b/UserService/src/main/java/com/submarket/userservice/service/SubCheckService.java
@@ -1,6 +1,6 @@
package com.submarket.userservice.service;
-public interface ISubCheckService {
+public interface SubCheckService {
boolean SubCheck(Integer subSeq) throws Exception;
boolean checkHasSubByItemSeqAndUserId(Integer itemSeq, String userId) throws Exception;
diff --git a/UserService/src/main/java/com/submarket/userservice/service/ISubService.java b/UserService/src/main/java/com/submarket/userservice/service/SubService.java
similarity index 94%
rename from UserService/src/main/java/com/submarket/userservice/service/ISubService.java
rename to UserService/src/main/java/com/submarket/userservice/service/SubService.java
index b842464..142d4f1 100644
--- a/UserService/src/main/java/com/submarket/userservice/service/ISubService.java
+++ b/UserService/src/main/java/com/submarket/userservice/service/SubService.java
@@ -5,7 +5,7 @@
import java.util.List;
-public interface ISubService {
+public interface SubService {
List findAllSub(SubDto subDto) throws Exception;
SubDto findOneSub(SubDto subDto) throws Exception;
diff --git a/UserService/src/main/java/com/submarket/userservice/service/IUserCheckService.java b/UserService/src/main/java/com/submarket/userservice/service/UserCheckService.java
similarity index 86%
rename from UserService/src/main/java/com/submarket/userservice/service/IUserCheckService.java
rename to UserService/src/main/java/com/submarket/userservice/service/UserCheckService.java
index 4851fd7..b422485 100644
--- a/UserService/src/main/java/com/submarket/userservice/service/IUserCheckService.java
+++ b/UserService/src/main/java/com/submarket/userservice/service/UserCheckService.java
@@ -1,6 +1,6 @@
package com.submarket.userservice.service;
-public interface IUserCheckService {
+public interface UserCheckService {
boolean checkUserByUserId(String userId);
diff --git a/UserService/src/main/java/com/submarket/userservice/service/UserItemService.java b/UserService/src/main/java/com/submarket/userservice/service/UserItemService.java
new file mode 100644
index 0000000..e09a63f
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/service/UserItemService.java
@@ -0,0 +1,16 @@
+package com.submarket.userservice.service;
+
+import com.submarket.userservice.dto.ItemDto;
+import com.submarket.userservice.dto.LikeDto;
+
+import java.util.List;
+
+public interface UserItemService {
+ String itemLikedOrDelete(final String userId, final int itemSeq) throws Exception;
+
+ int likedItemByUserId(final String userId, final int itemSeq) throws Exception;
+
+
+ List findAllLikedItems(final String userId) throws Exception;
+
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/service/IUserService.java b/UserService/src/main/java/com/submarket/userservice/service/UserService.java
similarity index 91%
rename from UserService/src/main/java/com/submarket/userservice/service/IUserService.java
rename to UserService/src/main/java/com/submarket/userservice/service/UserService.java
index c7954ff..ea85e71 100644
--- a/UserService/src/main/java/com/submarket/userservice/service/IUserService.java
+++ b/UserService/src/main/java/com/submarket/userservice/service/UserService.java
@@ -3,7 +3,7 @@
import com.submarket.userservice.dto.UserDto;
import org.springframework.security.core.userdetails.UserDetailsService;
-public interface IUserService extends UserDetailsService {
+public interface UserService extends UserDetailsService {
int createUser(UserDto pDTO) throws Exception;
diff --git a/UserService/src/main/java/com/submarket/userservice/service/impl/KafkaProducerService.java b/UserService/src/main/java/com/submarket/userservice/service/impl/KafkaProducerService.java
deleted file mode 100644
index 3341c33..0000000
--- a/UserService/src/main/java/com/submarket/userservice/service/impl/KafkaProducerService.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.submarket.userservice.service.impl;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.submarket.userservice.dto.SubDto;
-import com.submarket.userservice.service.IKafkaProducerService;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.kafka.core.KafkaProducerException;
-import org.springframework.kafka.core.KafkaTemplate;
-import org.springframework.stereotype.Service;
-
-import javax.transaction.Transactional;
-import java.util.HashMap;
-import java.util.Map;
-
-@Service
-@Slf4j
-@RequiredArgsConstructor
-public class KafkaProducerService implements IKafkaProducerService {
- private final KafkaTemplate kafkaTemplate;
-
- @Override
- public void createNewSub(SubDto subDto) throws Exception {
- // 구독 생성 시 Sub Topic 에 구독 정보 전송 --> itemService = 상품 수량 감소, orderService = 새로운 구독 정보 생성
- log.info(this.getClass().getName() + ".createNewSub Start!");
- ObjectMapper mapper = new ObjectMapper();
- String kafkaMessage = "";
-
- try {
- kafkaMessage = mapper.writeValueAsString(subDto);
- } catch (JsonProcessingException ex) {
- log.info("JsonProcessingException : " + ex);
- ex.printStackTrace();
- }
-
- kafkaTemplate.send("sub", kafkaMessage);
- log.info(this.getClass().getName() + ".createNewSub End!");
- }
-
- @Override
- public void cancelSub(SubDto subDto) throws Exception {
- log.info(this.getClass().getName() + ".cancelSub Start!");
- ObjectMapper mapper = new ObjectMapper();
- String kafkaMessage = "";
-
- try {
- kafkaMessage = mapper.writeValueAsString(subDto);
-
- } catch (JsonProcessingException exception) {
- log.info("JsonProcessingException : " + exception);
- exception.printStackTrace();
-
- }
-
- kafkaTemplate.send("sub-cancel", kafkaMessage);
-
- log.info(this.getClass().getName() + ".cancelSub End!");
- }
-}
diff --git a/UserService/src/main/java/com/submarket/userservice/service/impl/KafkaProducerServiceImpl.java b/UserService/src/main/java/com/submarket/userservice/service/impl/KafkaProducerServiceImpl.java
new file mode 100644
index 0000000..2a76a65
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/service/impl/KafkaProducerServiceImpl.java
@@ -0,0 +1,105 @@
+package com.submarket.userservice.service.impl;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.submarket.userservice.dto.LikeDto;
+import com.submarket.userservice.dto.SubDto;
+import com.submarket.userservice.exception.UserException;
+import com.submarket.userservice.exception.result.UserExceptionResult;
+import com.submarket.userservice.service.KafkaProducerService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.stereotype.Service;
+
+import static com.submarket.userservice.constants.KafkaConstants.*;
+
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class KafkaProducerServiceImpl implements KafkaProducerService {
+ private final KafkaTemplate kafkaTemplate;
+ private final ObjectMapper objectMapper;
+
+ @Override
+ public void createNewSub(SubDto subDto) throws Exception {
+ // 구독 생성 시 Sub Topic 에 구독 정보 전송 --> itemService = 상품 수량 감소, orderService = 새로운 구독 정보 생성
+ log.debug(this.getClass().getName() + ".createNewSub Start!");
+ String kafkaMessage = subDtoToString(subDto);
+
+ kafkaTemplate.send(TOPIC_NAME_SUB, kafkaMessage);
+ log.info(this.getClass().getName() + ".createNewSub End!");
+ }
+
+ @Override
+ public void cancelSub(SubDto subDto) throws Exception {
+ log.debug(this.getClass().getName() + ".cancelSub Start!");
+ String kafkaMessage = subDtoToString(subDto);
+
+ kafkaTemplate.send(TOPIC_NAME_CANCEL_SUB, kafkaMessage);
+
+ log.info(this.getClass().getName() + ".cancelSub End!");
+ }
+
+ private String subDtoToString(final SubDto subDto) throws Exception {
+ try {
+ return objectMapper.writeValueAsString(subDto);
+
+ } catch (JsonProcessingException exception) {
+ log.info("JsonProcessingException : " + exception);
+ exception.printStackTrace();
+
+ throw new UserException(UserExceptionResult.CAN_NOT_CREATE_KAFKA_TOPIC);
+
+ }
+
+ }
+
+
+ /**
+ * 상품 좋아요 성공 -> (새로운 좋아요 생성 시) itemService 에 정보 전송
+ *
+ * @param likeDto
+ * @throws Exception
+ */
+ @Override
+ public void createItemLike(final LikeDto likeDto) throws Exception {
+ log.debug(this.getClass().getName() + ".createItemLike Start!");
+ String kafkaMessage = likeDtoToString(likeDto);
+
+ kafkaTemplate.send(TOPIC_NAME_ITEM_LIKED, kafkaMessage);
+
+ log.info(this.getClass().getName() + ".createNewSub End!");
+
+ }
+
+ /**
+ * 상품 좋아요 취소 -> (이미 좋아요 상태 시) itemService 에 전송
+ *
+ * @param likeDto
+ * @throws Exception
+ */
+
+ @Override
+ public void cancelItemLike(LikeDto likeDto) throws Exception {
+ log.debug(this.getClass().getName() + ".cancelItemLike Start!");
+ String kafkaMessage = likeDtoToString(likeDto);
+
+ kafkaTemplate.send(TOPIC_NAME_CANCEL_ITEM_LIKED, kafkaMessage);
+
+ log.info(this.getClass().getName() + ".createNewSub End!");
+
+ }
+
+
+ private String likeDtoToString(final LikeDto likeDto) throws Exception { // Dto -> String
+ try {
+ return objectMapper.writeValueAsString(likeDto);
+ } catch (JsonProcessingException ex) {
+ log.info("JsonProcessingException : " + ex);
+ ex.printStackTrace();
+ throw new UserException(UserExceptionResult.CAN_NOT_CREATE_KAFKA_TOPIC);
+ }
+ }
+
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/service/impl/MailService.java b/UserService/src/main/java/com/submarket/userservice/service/impl/MailServiceImpl.java
similarity index 87%
rename from UserService/src/main/java/com/submarket/userservice/service/impl/MailService.java
rename to UserService/src/main/java/com/submarket/userservice/service/impl/MailServiceImpl.java
index 02bac7e..45a123c 100644
--- a/UserService/src/main/java/com/submarket/userservice/service/impl/MailService.java
+++ b/UserService/src/main/java/com/submarket/userservice/service/impl/MailServiceImpl.java
@@ -1,9 +1,7 @@
package com.submarket.userservice.service.impl;
-import com.submarket.userservice.jpa.SubRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
@@ -13,7 +11,7 @@
@Slf4j
@Service(value = "MailService")
@RequiredArgsConstructor
-public class MailService {
+public class MailServiceImpl {
private final Environment env;
private final JavaMailSender javaMailSender;
diff --git a/UserService/src/main/java/com/submarket/userservice/service/impl/SchedulerService.java b/UserService/src/main/java/com/submarket/userservice/service/impl/SchedulerServiceImpl.java
similarity index 92%
rename from UserService/src/main/java/com/submarket/userservice/service/impl/SchedulerService.java
rename to UserService/src/main/java/com/submarket/userservice/service/impl/SchedulerServiceImpl.java
index 7ecdaa1..1c4e1e2 100644
--- a/UserService/src/main/java/com/submarket/userservice/service/impl/SchedulerService.java
+++ b/UserService/src/main/java/com/submarket/userservice/service/impl/SchedulerServiceImpl.java
@@ -13,11 +13,11 @@
@Component
@Slf4j
@RequiredArgsConstructor
-public class SchedulerService {
+public class SchedulerServiceImpl {
/**
* 특정 시간에 실행 Batch, and if (day == new Date()) == 결제 + 구독 정보 업데이트 로직 실행
*/
- private final SubService subService;
+ private final SubServiceImpl subServiceImpl;
private final SubRepository subRepository;
// @Scheduled // 특정 시간에 실행
@@ -40,7 +40,7 @@ public void checkSub() throws Exception {
subDto.setSubSeq(subEntity.getSubSeq());
// 구독 업데이트
- subService.updateSub(subDto);
+ subServiceImpl.updateSub(subDto);
});
diff --git a/UserService/src/main/java/com/submarket/userservice/service/impl/SubCheckService.java b/UserService/src/main/java/com/submarket/userservice/service/impl/SubCheckServiceImpl.java
similarity index 94%
rename from UserService/src/main/java/com/submarket/userservice/service/impl/SubCheckService.java
rename to UserService/src/main/java/com/submarket/userservice/service/impl/SubCheckServiceImpl.java
index 9d6a1e1..8c26597 100644
--- a/UserService/src/main/java/com/submarket/userservice/service/impl/SubCheckService.java
+++ b/UserService/src/main/java/com/submarket/userservice/service/impl/SubCheckServiceImpl.java
@@ -4,7 +4,6 @@
import com.submarket.userservice.jpa.UserRepository;
import com.submarket.userservice.jpa.entity.SubEntity;
import com.submarket.userservice.jpa.entity.UserEntity;
-import com.submarket.userservice.service.ISubCheckService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -15,7 +14,7 @@
@Service
@RequiredArgsConstructor
@Slf4j
-public class SubCheckService implements ISubCheckService {
+public class SubCheckServiceImpl implements com.submarket.userservice.service.SubCheckService {
private final SubRepository subRepository;
private final UserRepository userRepository;
diff --git a/UserService/src/main/java/com/submarket/userservice/service/impl/SubService.java b/UserService/src/main/java/com/submarket/userservice/service/impl/SubServiceImpl.java
similarity index 85%
rename from UserService/src/main/java/com/submarket/userservice/service/impl/SubService.java
rename to UserService/src/main/java/com/submarket/userservice/service/impl/SubServiceImpl.java
index 2017f87..cf5294c 100644
--- a/UserService/src/main/java/com/submarket/userservice/service/impl/SubService.java
+++ b/UserService/src/main/java/com/submarket/userservice/service/impl/SubServiceImpl.java
@@ -1,12 +1,13 @@
package com.submarket.userservice.service.impl;
import com.submarket.userservice.dto.SubDto;
+import com.submarket.userservice.exception.SubException;
+import com.submarket.userservice.exception.result.SubExceptionResult;
import com.submarket.userservice.jpa.SubRepository;
import com.submarket.userservice.jpa.UserRepository;
import com.submarket.userservice.jpa.entity.SubEntity;
import com.submarket.userservice.jpa.entity.UserEntity;
import com.submarket.userservice.mapper.SubMapper;
-import com.submarket.userservice.service.ISubService;
import com.submarket.userservice.util.CmmUtil;
import com.submarket.userservice.util.DateUtil;
import lombok.RequiredArgsConstructor;
@@ -23,13 +24,13 @@
@Service(value = "SubService")
@Slf4j
@RequiredArgsConstructor
-public class SubService implements ISubService {
+public class SubServiceImpl implements com.submarket.userservice.service.SubService {
private final SubRepository subRepository;
private final UserRepository userRepository;
- private final UserService userService;
- private final SubCheckService subCheckService;
- private final MailService mailService;
- private final KafkaProducerService kafkaProducerService;
+ private final UserServiceImpl userServiceImpl;
+ private final SubCheckServiceImpl subCheckServiceImpl;
+ private final MailServiceImpl mailServiceImpl;
+ private final KafkaProducerServiceImpl kafkaProducerServiceImpl;
/** ------------------------- 구독 조회 ------------------------------*/
@Override
@@ -55,7 +56,7 @@ public List findAllSub(SubDto subDto) throws RuntimeException{
@Override // 구독 상세 조회
- @Transactional
+ @Transactional(rollbackOn = Exception.class)
public SubDto findOneSub(SubDto subDto) throws Exception {
log.info(this.getClass().getName() + "findOne Sub Start!");
int subSeq = subDto.getSubSeq();
@@ -70,7 +71,7 @@ public SubDto findOneSub(SubDto subDto) throws Exception {
log.info("subCount : " + subEntity.getSubCount());
if (subEntity == null) {
- throw new RuntimeException("SubEntity Null");
+ throw new SubException(SubExceptionResult.CAN_NOT_FOUND_SUB_INFO);
}
pDto = SubMapper.INSTANCE.subEntityToSubDto(subEntity);
@@ -96,15 +97,15 @@ public int createNewSub(SubDto subDto) throws Exception{
log.info("itemSeq : " + subDto.getItemSeq());
// 이미 구독 여부 확인
- if (subCheckService.checkHasSubByItemSeqAndUserId(subDto.getItemSeq(), subDto.getUserId())) {
+ if (subCheckServiceImpl.checkHasSubByItemSeqAndUserId(subDto.getItemSeq(), subDto.getUserId())) {
SubEntity subEntity = SubMapper.INSTANCE.subDtoToSubEntity(subDto);
log.info("subEntity (itemSeq) : " + subEntity.getItemSeq());
subRepository.save(subEntity);
- mailService.sendMail(subDto.getUser().getUserEmail(), "구독 성공", subDto.getUser().getUserName() + "님 구독이 완료 됐습니다!!");
+ mailServiceImpl.sendMail(subDto.getUser().getUserEmail(), "구독 성공", subDto.getUser().getUserName() + "님 구독이 완료 됐습니다!!");
// kafka (구독 성공 시 Item Count - 1)
- kafkaProducerService.createNewSub(subDto);
+ kafkaProducerServiceImpl.createNewSub(subDto);
res = 1;
} else {
@@ -136,7 +137,7 @@ public int updateSub(SubDto subDto) {
@Transactional
public int cancelSub(SubDto subDto) throws Exception{
log.info(this.getClass().getName() + ".cancelSub Start!");
- if (subCheckService.SubCheck(subDto.getSubSeq())) {
+ if (subCheckServiceImpl.SubCheck(subDto.getSubSeq())) {
Optional subEntity = subRepository.findById(subDto.getSubSeq());
subDto.setItemSeq(subEntity.get().getItemSeq());
@@ -144,7 +145,7 @@ public int cancelSub(SubDto subDto) throws Exception{
// not null 삭제 실행
subRepository.deleteById(subDto.getSubSeq());
- kafkaProducerService.cancelSub(subDto);
+ kafkaProducerServiceImpl.cancelSub(subDto);
} else {
log.info("구독 정보 찾기 실패");
diff --git a/UserService/src/main/java/com/submarket/userservice/service/impl/UserCheckService.java b/UserService/src/main/java/com/submarket/userservice/service/impl/UserCheckServiceImpl.java
similarity index 94%
rename from UserService/src/main/java/com/submarket/userservice/service/impl/UserCheckService.java
rename to UserService/src/main/java/com/submarket/userservice/service/impl/UserCheckServiceImpl.java
index 2494bdb..2107abb 100644
--- a/UserService/src/main/java/com/submarket/userservice/service/impl/UserCheckService.java
+++ b/UserService/src/main/java/com/submarket/userservice/service/impl/UserCheckServiceImpl.java
@@ -2,7 +2,6 @@
import com.submarket.userservice.jpa.UserRepository;
import com.submarket.userservice.jpa.entity.UserEntity;
-import com.submarket.userservice.service.IUserCheckService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@@ -12,7 +11,7 @@
@Service
@Slf4j
@RequiredArgsConstructor
-public class UserCheckService implements IUserCheckService {
+public class UserCheckServiceImpl implements com.submarket.userservice.service.UserCheckService {
private final UserRepository userRepository;
private final BCryptPasswordEncoder passwordEncoder;
diff --git a/UserService/src/main/java/com/submarket/userservice/service/impl/UserItemServiceImpl.java b/UserService/src/main/java/com/submarket/userservice/service/impl/UserItemServiceImpl.java
new file mode 100644
index 0000000..df95a63
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/service/impl/UserItemServiceImpl.java
@@ -0,0 +1,152 @@
+package com.submarket.userservice.service.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.submarket.userservice.client.ItemServiceClient;
+import com.submarket.userservice.dto.ItemDto;
+import com.submarket.userservice.dto.LikeDto;
+import com.submarket.userservice.exception.ItemException;
+import com.submarket.userservice.exception.UserException;
+import com.submarket.userservice.exception.result.ItemExceptionResult;
+import com.submarket.userservice.exception.result.UserExceptionResult;
+import com.submarket.userservice.jpa.LikeRepository;
+import com.submarket.userservice.jpa.UserRepository;
+import com.submarket.userservice.jpa.entity.LikeEntity;
+import com.submarket.userservice.jpa.entity.UserEntity;
+import com.submarket.userservice.service.KafkaProducerService;
+import com.submarket.userservice.service.UserItemService;
+import com.submarket.userservice.vo.ItemInfoResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
+import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+
+import javax.transaction.Transactional;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class UserItemServiceImpl implements UserItemService {
+ private final LikeRepository likeRepository;
+ private final UserRepository userRepository;
+ private final KafkaProducerService kafkaProducerService;
+ private final ItemServiceClient itemServiceClient;
+
+ private final CircuitBreakerFactory circuitBreakerFactory;
+
+
+ /**
+ * 상품 좋아요 및 좋아요 취소 -> 값이 있다면 delete or create
+ *
+ * @param userId
+ * @param itemSeq
+ * @return
+ * @throws Exception
+ */
+ @Override
+ @Transactional(rollbackOn = Exception.class)
+ public String itemLikedOrDelete(final String userId, final int itemSeq) throws Exception {
+ log.debug("item Liked Start!");
+ Optional user = Optional.of(userRepository.findByUserId(userId));
+
+ // 상품 유효성 검사
+ log.info("Before call checking item");
+
+ CircuitBreaker circuitBreaker = circuitBreakerFactory.create("itemCircuit");
+ ItemDto itemDto = circuitBreaker.run(() -> itemServiceClient.isItem(itemSeq).getBody(),
+ throwable -> ItemDto.builder().itemSeq(-1).build());
+
+ log.info("After call checking item");
+ log.info("itemSeq : " + itemDto.getItemSeq());
+
+
+ if (itemDto == null) {
+ throw new ItemException(ItemExceptionResult.NOT_MATCHED_ITEM_SEQ);
+ }
+
+ Optional result = likeRepository.findByUserAndItemSeq(user
+ .orElseThrow(() -> new UserException(UserExceptionResult.USER_NOT_FOUNT))
+ , itemSeq);
+
+
+ if (result.isPresent()) { // 있을 경우 삭제
+
+ likeRepository.deleteById(result.get().getLikeSeq());
+
+ kafkaProducerService.cancelItemLike(LikeDto.builder().itemSeq(itemSeq).userId(userId).build());
+
+ return "좋아요 취소 성공";
+
+ } else { // 없을 경우 생성
+
+ likeRepository.save(LikeEntity.builder()
+ .user(user.get())
+ .itemSeq(itemSeq).build());
+
+ kafkaProducerService.createItemLike(LikeDto.builder().itemSeq(itemSeq).userId(userId).build());
+
+
+ return "좋아요 성공";
+ }
+ }
+
+ /**
+ * 상품 좋아요 유무를 확인
+ *
+ * @param userId 사용자 아이디
+ * @param itemSeq 상품 번호
+ * @return 1, 0
+ * @throws Exception
+ */
+ @Override
+ public int likedItemByUserId(String userId, int itemSeq) throws Exception {
+ log.info(this.getClass().getName() + ".likedItemByUserId Start!");
+
+ UserEntity user = userRepository.findByUserId(userId);
+
+ Optional result = likeRepository.findByUserAndItemSeq(user, itemSeq);
+
+ log.info(this.getClass().getName() + ".likedItemByUserId End!");
+ // 일치하는 정보가 있을 경우 1 상품 좋아요 유 , Else 0 좋아요 무
+ return result.isPresent() ? 1 : 0;
+ }
+
+
+ /**
+ * 사용자가 좋아요한 상품 목록 조회
+ *
+ * @param userId 사용자 아이디
+ * @return 좋아요한 상품 목록
+ * @throws Exception
+ */
+ @Override
+ public List findAllLikedItems(String userId) throws Exception {
+ log.info("Service Start!");
+
+ List result = new LinkedList<>();
+ UserEntity user = userRepository.findByUserId(userId);
+ if (user == null) { // 사용자 정보를 찾을 수 없음
+ throw new UserException(UserExceptionResult.USER_NOT_FOUNT);
+ }
+
+ CircuitBreaker circuitBreaker = circuitBreakerFactory.create("findItemInfo");
+ Optional> likeEntities = likeRepository.findAllByUser(user);
+
+ if (likeEntities.isPresent()) { // 값이 있다면 상품 정보 조회 시작
+ likeEntities.get().forEach(likeEntity -> {
+ ItemInfoResponse response = circuitBreaker.run(() -> itemServiceClient.findOneItem(likeEntity.getItemSeq()).getBody(),
+ throwable -> new ItemInfoResponse());
+
+ result.add(new ObjectMapper().convertValue(response, ItemDto.class));
+ });
+ }
+
+ log.info("Service End!");
+ return result;
+ }
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/service/impl/UserService.java b/UserService/src/main/java/com/submarket/userservice/service/impl/UserServiceImpl.java
similarity index 87%
rename from UserService/src/main/java/com/submarket/userservice/service/impl/UserService.java
rename to UserService/src/main/java/com/submarket/userservice/service/impl/UserServiceImpl.java
index 23a5f1e..ca68568 100644
--- a/UserService/src/main/java/com/submarket/userservice/service/impl/UserService.java
+++ b/UserService/src/main/java/com/submarket/userservice/service/impl/UserServiceImpl.java
@@ -1,10 +1,12 @@
package com.submarket.userservice.service.impl;
import com.submarket.userservice.dto.UserDto;
+import com.submarket.userservice.exception.UserException;
+import com.submarket.userservice.exception.result.UserExceptionResult;
import com.submarket.userservice.jpa.UserRepository;
import com.submarket.userservice.jpa.entity.UserEntity;
import com.submarket.userservice.mapper.UserMapper;
-import com.submarket.userservice.service.IUserService;
+import com.submarket.userservice.service.UserService;
import com.submarket.userservice.util.CmmUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -21,11 +23,12 @@
@Service("UserService")
@Slf4j
@RequiredArgsConstructor
-public class UserService implements IUserService {
+public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final BCryptPasswordEncoder passwordEncoder;
- private final UserCheckService userCheckService;
- private final MailService mailService;
+ private final UserCheckServiceImpl userCheckServiceImpl;
+ private final MailServiceImpl mailServiceImpl;
+
//####################################### 회원가입 #######################################//
@Override
@@ -33,8 +36,9 @@ public int createUser(UserDto pDTO) throws Exception {
log.info("--------------> " + this.getClass().getName() + ".createUser Start !");
/** 아이디 중복 확인 (1 = 중복, 0 = pass)*/
- boolean checkId = userCheckService.checkUserByUserId(pDTO.getUserId());
- boolean checkEmail = userCheckService.checkUserByUserEmail(pDTO.getUserEmail());
+ boolean checkId = userCheckServiceImpl.checkUserByUserId(pDTO.getUserId());
+ boolean checkEmail = userCheckServiceImpl.checkUserByUserEmail(pDTO.getUserEmail());
+
if (checkId && checkEmail) { /** ID or Email 에서 중복확인 완료 실행 가능 */ // 둘 다 0이 넘어와야지만 아래 코드 실행
pDTO.setUserStatus(1); // 사용자 활성화 / (이메일 체크 후 활성화 로직 추가)
@@ -43,7 +47,7 @@ public int createUser(UserDto pDTO) throws Exception {
userRepository.save(pEntity);
// 환영 메일 전송
- mailService.sendMail(pDTO.getUserEmail(), "Welcome!!", pDTO.getUserName() + "님 SubMarket 가입을 환영합니다!");
+ mailServiceImpl.sendMail(pDTO.getUserEmail(), "Welcome!!", pDTO.getUserName() + "님 SubMarket 가입을 환영합니다!");
} else { /** 중복 발생 실패 */
@@ -85,7 +89,7 @@ public int changeUserPassword(UserDto pDTO, String newPassword) throws Exception
String userPassword = pDTO.getUserPassword();
// 비밀번호가 일치하는지 확인
- boolean checkPassword = userCheckService.isTruePassword(userId, userPassword);
+ boolean checkPassword = userCheckServiceImpl.isTruePassword(userId, userPassword);
// 만약 비밀번호가 일치한다면
if (checkPassword) {
@@ -121,11 +125,11 @@ public int changeUserPasswordNoAuthorization(String userId, String newPassword)
public int deleteUser(UserDto userDto) throws Exception {
log.info(this.getClass().getName() + ".deleteUser Start!");
// 비밀번호 일치 확인
- if (userCheckService.isTruePassword(userDto.getUserId(), userDto.getUserPassword())) {
+ if (userCheckServiceImpl.isTruePassword(userDto.getUserId(), userDto.getUserPassword())) {
// 비밀번호가 일치한다면
userRepository.deleteUserInfo(userDto.getUserId());
} else {
- throw new RuntimeException("사용자 비밀번호가 일치하지 않습니다");
+ throw new UserException(UserExceptionResult.USER_PASSWORD_NOT_MATCHED);
}
diff --git a/UserService/src/main/java/com/submarket/userservice/vo/RequestChangePassword.java b/UserService/src/main/java/com/submarket/userservice/vo/ChangePasswordRequest.java
similarity index 60%
rename from UserService/src/main/java/com/submarket/userservice/vo/RequestChangePassword.java
rename to UserService/src/main/java/com/submarket/userservice/vo/ChangePasswordRequest.java
index 78b54f9..baff30c 100644
--- a/UserService/src/main/java/com/submarket/userservice/vo/RequestChangePassword.java
+++ b/UserService/src/main/java/com/submarket/userservice/vo/ChangePasswordRequest.java
@@ -1,9 +1,10 @@
package com.submarket.userservice.vo;
+import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
-public class RequestChangePassword {
+public class ChangePasswordRequest {
private String oldPassword;
private String newPassword;
}
diff --git a/UserService/src/main/java/com/submarket/userservice/vo/ItemInfoResponse.java b/UserService/src/main/java/com/submarket/userservice/vo/ItemInfoResponse.java
new file mode 100644
index 0000000..22cc8d4
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/vo/ItemInfoResponse.java
@@ -0,0 +1,34 @@
+package com.submarket.userservice.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.web.multipart.MultipartFile;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class ItemInfoResponse {
+ private int itemSeq;
+ private String sellerId;
+ private String itemTitle;
+ private String itemContents;
+ private int itemPrice;
+ private int itemCount; // 상품 수
+ private int categorySeq;
+ private int itemStatus; // 활성화
+ private int readCount20;
+ private int readCount30;
+ private int readCount40;
+ private int readCountOther;
+ private int userAge;
+ private String mainImagePath; // DB에 저장되어 있는 이미지 정보
+ private String subImagePath;
+ private int isUserLiked;
+
+
+ private MultipartFile mainImage; // Front 에서 넘어온 이미지
+ private MultipartFile subImage; // Image 2
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/vo/ItemLikedRequest.java b/UserService/src/main/java/com/submarket/userservice/vo/ItemLikedRequest.java
new file mode 100644
index 0000000..62dd4a1
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/vo/ItemLikedRequest.java
@@ -0,0 +1,17 @@
+package com.submarket.userservice.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotNull;
+
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ItemLikedRequest {
+ private Integer itemSeq;
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/vo/LoginRequest.java b/UserService/src/main/java/com/submarket/userservice/vo/LoginRequest.java
new file mode 100644
index 0000000..8ba3727
--- /dev/null
+++ b/UserService/src/main/java/com/submarket/userservice/vo/LoginRequest.java
@@ -0,0 +1,17 @@
+package com.submarket.userservice.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class LoginRequest {
+ private String userId;
+
+ private String userPassword;
+}
diff --git a/UserService/src/main/java/com/submarket/userservice/vo/RequestLogin.java b/UserService/src/main/java/com/submarket/userservice/vo/RequestLogin.java
deleted file mode 100644
index 154db8b..0000000
--- a/UserService/src/main/java/com/submarket/userservice/vo/RequestLogin.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.submarket.userservice.vo;
-
-import lombok.Data;
-
-@Data
-public class RequestLogin {
- private String userId;
- private String userPassword;
-}
diff --git a/UserService/src/main/java/com/submarket/userservice/vo/RequestSub.java b/UserService/src/main/java/com/submarket/userservice/vo/SubRequest.java
similarity index 65%
rename from UserService/src/main/java/com/submarket/userservice/vo/RequestSub.java
rename to UserService/src/main/java/com/submarket/userservice/vo/SubRequest.java
index 77f25d9..c8bf8fd 100644
--- a/UserService/src/main/java/com/submarket/userservice/vo/RequestSub.java
+++ b/UserService/src/main/java/com/submarket/userservice/vo/SubRequest.java
@@ -1,9 +1,10 @@
package com.submarket.userservice.vo;
+import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
-public class RequestSub {
+public class SubRequest {
private int itemSeq;
diff --git a/UserService/src/main/java/com/submarket/userservice/vo/ResponseSub.java b/UserService/src/main/java/com/submarket/userservice/vo/SubResponse.java
similarity index 72%
rename from UserService/src/main/java/com/submarket/userservice/vo/ResponseSub.java
rename to UserService/src/main/java/com/submarket/userservice/vo/SubResponse.java
index 0fa5d23..74eb110 100644
--- a/UserService/src/main/java/com/submarket/userservice/vo/ResponseSub.java
+++ b/UserService/src/main/java/com/submarket/userservice/vo/SubResponse.java
@@ -1,6 +1,8 @@
package com.submarket.userservice.vo;
import com.submarket.userservice.jpa.entity.UserEntity;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -8,7 +10,8 @@
@Data
@NoArgsConstructor
@AllArgsConstructor
-public class ResponseSub {
+public class SubResponse {
+
private Integer subSeq;
private int itemSeq;
private String subDate;
diff --git a/UserService/src/main/java/com/submarket/userservice/vo/ResponseUser.java b/UserService/src/main/java/com/submarket/userservice/vo/UserRequest.java
similarity index 88%
rename from UserService/src/main/java/com/submarket/userservice/vo/ResponseUser.java
rename to UserService/src/main/java/com/submarket/userservice/vo/UserRequest.java
index 0845a8a..7ef5c9c 100644
--- a/UserService/src/main/java/com/submarket/userservice/vo/ResponseUser.java
+++ b/UserService/src/main/java/com/submarket/userservice/vo/UserRequest.java
@@ -10,8 +10,9 @@
@Data
@AllArgsConstructor
@NoArgsConstructor
-public class ResponseUser {
+public class UserRequest {
private String userId;
+ private String userPassword;
private String userName;
private String userEmail;
private String userAge;
diff --git a/UserService/src/main/java/com/submarket/userservice/vo/RequestUser.java b/UserService/src/main/java/com/submarket/userservice/vo/UserResponse.java
similarity index 54%
rename from UserService/src/main/java/com/submarket/userservice/vo/RequestUser.java
rename to UserService/src/main/java/com/submarket/userservice/vo/UserResponse.java
index 1a0a42e..cc4b282 100644
--- a/UserService/src/main/java/com/submarket/userservice/vo/RequestUser.java
+++ b/UserService/src/main/java/com/submarket/userservice/vo/UserResponse.java
@@ -4,33 +4,15 @@
import lombok.Data;
import lombok.NoArgsConstructor;
-import javax.validation.constraints.Email;
-import javax.validation.constraints.NotNull;
-
@Data
@AllArgsConstructor
@NoArgsConstructor
-public class RequestUser {
- @NotNull(message = "userId cannot be null")
+public class UserResponse {
private String userId;
-
- @NotNull
- private String userPassword;
-
- @NotNull
private String userName;
-
- @Email(message = "이메일이 아닙니다.")
private String userEmail;
-
- @NotNull
private String userAge;
-
- @NotNull
private String userPn;
-
- @NotNull
private String userAddress;
-
private String userAddress2;
}
diff --git a/UserService/src/test/java/com/submarket/userservice/UserServiceApplicationTests.java b/UserService/src/test/java/com/submarket/userservice/UserServiceImplApplicationTests.java
similarity index 82%
rename from UserService/src/test/java/com/submarket/userservice/UserServiceApplicationTests.java
rename to UserService/src/test/java/com/submarket/userservice/UserServiceImplApplicationTests.java
index 6721bb7..d38e686 100644
--- a/UserService/src/test/java/com/submarket/userservice/UserServiceApplicationTests.java
+++ b/UserService/src/test/java/com/submarket/userservice/UserServiceImplApplicationTests.java
@@ -4,7 +4,7 @@
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
-class UserServiceApplicationTests {
+class UserServiceImplApplicationTests {
@Test
void contextLoads() {