Merge remote-tracking branch 'origin/main'

This commit is contained in:
jooho
2021-10-28 14:40:17 +09:00
127 changed files with 3051 additions and 1793 deletions

View File

@@ -1,8 +1,8 @@
# openjdk8 base image
FROM openjdk:8-jre-alpine
# config server uri: dockder run --e 로 변경 가능
ENV SPRING_CLOUD_CONFIG_URI https://egov-config.paas-ta.org
# directory 생성
RUN mkdir -p /usr/app/msa-attach-volume/messages
# jar 파일이 복사되는 위치
ENV APP_HOME=/usr/app/
# 작업 시작 위치
@@ -11,5 +11,5 @@ WORKDIR $APP_HOME
COPY build/libs/*.jar apigateway.jar
# application port
EXPOSE 8000
# 실행 (application-cf.yml 프로필이 기본값)
CMD ["java", "-Dspring.profiles.active=${profile:cf}", "-jar", "apigateway.jar"]
# 실행
CMD ["java", "-Dspring.profiles.active=${profile:default}", "-jar", "apigateway.jar"]

View File

@@ -10,7 +10,7 @@ applications:
- egov-discovery-provided-service # discovery service binding
env:
spring_profiles_active: cf
spring_cloud_config_uri: https://egov-config.paas-ta.org
spring_cloud_config_uri: http://localhost:8888
app_name: egov-apigateway # logstash custom app name
TZ: Asia/Seoul
JAVA_OPTS: -Xss349k

View File

@@ -36,7 +36,7 @@ import java.nio.file.Paths;
@Configuration
public class MessageSourceConfig {
@Value("${messages.directory}")
@Value("${messages.directory:${user.home}/msa-attach-volume/messages}")
private String messagesDirectory;
@Value("${spring.profiles.active:default}")

View File

@@ -65,3 +65,6 @@ management:
web:
exposure:
include: refresh, health, beans
messages:
directory: ${user.dir}/msa-attach-volume/messages

View File

@@ -2,4 +2,4 @@ spring:
cloud:
config:
uri: http://localhost:8888
name: apigateway
name: application

View File

@@ -15,7 +15,7 @@
</springProfile>
<springProfile name="!default">
<!-- java -Ddestination="localhost:5001" 와 같이 변경할 수 있다. cf 환경에서는 manifest.yml 파일에 환경변수로 추가 -->
<property name="destination" value="${destination:-localhost:5001}" />
<property name="destination" value="${logstash_hostname:-localhost:5001}" />
<property name="app_name" value="${app_name:-apigateway}" />
<!-- ELK - Logstash 로 로그를 전송하기 위한 appender -->

View File

@@ -1,8 +1,8 @@
# openjdk8 base image
FROM openjdk:8-jre-alpine
# config server uri: dockder run --e 로 변경 가능
ENV SPRING_CLOUD_CONFIG_URI https://egov-config.paas-ta.org
# directory 생성
RUN mkdir -p /usr/app/msa-attach-volume/messages
# jar 파일이 복사되는 위치
ENV APP_HOME=/usr/app/
# 작업 시작 위치
@@ -11,5 +11,5 @@ WORKDIR $APP_HOME
COPY build/libs/*.jar app.jar
# application port
#EXPOSE 8000
# 실행 (application-cf.yml 프로필이 기본값)
CMD ["java", "-Dspring.profiles.active=${profile:cf}", "-jar", "app.jar"]
# 실행
CMD ["java", "-Dspring.profiles.active=${profile:default}", "-jar", "app.jar"]

View File

@@ -10,7 +10,7 @@ applications:
- egov-discovery-provided-service # discovery service binding
env:
spring_profiles_active: cf
spring_cloud_config_uri: https://egov-config.paas-ta.org
spring_cloud_config_uri: http://localhost:8888
app_name: egov-board-service # logstash custom app name
TZ: Asia/Seoul
JAVA_OPTS: -Xss349k

View File

@@ -1,15 +1,13 @@
package org.egovframe.cloud.boardservice.api.posts.dto;
import com.querydsl.core.annotations.QueryProjection;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.egovframe.cloud.boardservice.api.board.dto.BoardResponseDto;
import java.io.Serializable;
import java.time.LocalDateTime;
import org.egovframe.cloud.boardservice.api.board.dto.BoardResponseDto;
import com.querydsl.core.annotations.QueryProjection;
import lombok.Getter;
import lombok.NoArgsConstructor;
/**
* org.egovframe.cloud.boardservice.api.posts.dto.PostsSimpleResponseDto
* <p>

View File

@@ -1,17 +1,5 @@
package org.egovframe.cloud.boardservice.domain.board;
import java.util.List;
import org.egovframe.cloud.boardservice.api.board.dto.BoardListResponseDto;
import org.egovframe.cloud.boardservice.api.board.dto.BoardResponseDto;
import org.egovframe.cloud.boardservice.api.board.dto.QBoardListResponseDto;
import org.egovframe.cloud.boardservice.api.board.dto.QBoardResponseDto;
import org.egovframe.cloud.boardservice.domain.code.QCode;
import org.egovframe.cloud.common.dto.RequestDto;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import com.google.common.base.CaseFormat;
import com.querydsl.core.QueryResults;
import com.querydsl.core.types.Order;
@@ -21,8 +9,18 @@ import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.JPQLQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.egovframe.cloud.boardservice.api.board.dto.BoardListResponseDto;
import org.egovframe.cloud.boardservice.api.board.dto.BoardResponseDto;
import org.egovframe.cloud.boardservice.api.board.dto.QBoardListResponseDto;
import org.egovframe.cloud.boardservice.api.board.dto.QBoardResponseDto;
import org.egovframe.cloud.boardservice.domain.code.QCode;
import org.egovframe.cloud.common.dto.RequestDto;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import java.util.List;
/**
* org.egovframe.cloud.boardservice.domain.board.BoardRepositoryImpl

View File

@@ -1,25 +1,5 @@
package org.egovframe.cloud.boardservice.domain.posts;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.egovframe.cloud.boardservice.api.board.dto.QBoardResponseDto;
import org.egovframe.cloud.boardservice.api.posts.dto.PostsListResponseDto;
import org.egovframe.cloud.boardservice.api.posts.dto.PostsResponseDto;
import org.egovframe.cloud.boardservice.api.posts.dto.PostsSimpleResponseDto;
import org.egovframe.cloud.boardservice.api.posts.dto.QPostsListResponseDto;
import org.egovframe.cloud.boardservice.api.posts.dto.QPostsResponseDto;
import org.egovframe.cloud.boardservice.api.posts.dto.QPostsSimpleResponseDto;
import org.egovframe.cloud.boardservice.domain.board.QBoard;
import org.egovframe.cloud.boardservice.domain.comment.QComment;
import org.egovframe.cloud.boardservice.domain.user.QUser;
import org.egovframe.cloud.common.dto.RequestDto;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import com.google.common.base.CaseFormat;
import com.querydsl.core.QueryResults;
import com.querydsl.core.Tuple;
@@ -27,20 +7,28 @@ import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Order;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.CaseBuilder;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.NumberPath;
import com.querydsl.core.types.dsl.SimpleExpression;
import com.querydsl.core.types.dsl.StringPath;
import com.querydsl.core.types.dsl.*;
import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.JPQLQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.querydsl.sql.SQLExpressions;
import com.querydsl.sql.SQLQuery;
import com.querydsl.sql.SQLQueryFactory;
import lombok.RequiredArgsConstructor;
import org.egovframe.cloud.boardservice.api.board.dto.QBoardResponseDto;
import org.egovframe.cloud.boardservice.api.posts.dto.*;
import org.egovframe.cloud.boardservice.domain.board.QBoard;
import org.egovframe.cloud.boardservice.domain.comment.QComment;
import org.egovframe.cloud.boardservice.domain.user.QUser;
import org.egovframe.cloud.common.dto.RequestDto;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* org.egovframe.cloud.boardservice.domain.posts.PostsRepositoryImpl

View File

@@ -1,23 +1,9 @@
package org.egovframe.cloud.boardservice.service.posts;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.egovframe.cloud.boardservice.api.board.dto.BoardResponseDto;
import org.egovframe.cloud.boardservice.api.posts.dto.PostsDeleteRequestDto;
import org.egovframe.cloud.boardservice.api.posts.dto.PostsListResponseDto;
import org.egovframe.cloud.boardservice.api.posts.dto.PostsResponseDto;
import org.egovframe.cloud.boardservice.api.posts.dto.PostsSaveRequestDto;
import org.egovframe.cloud.boardservice.api.posts.dto.PostsSimpleResponseDto;
import org.egovframe.cloud.boardservice.api.posts.dto.PostsSimpleSaveRequestDto;
import org.egovframe.cloud.boardservice.api.posts.dto.PostsUpdateRequestDto;
import org.egovframe.cloud.boardservice.domain.posts.Posts;
import org.egovframe.cloud.boardservice.domain.posts.PostsId;
import org.egovframe.cloud.boardservice.domain.posts.PostsRead;
import org.egovframe.cloud.boardservice.domain.posts.PostsReadRepository;
import org.egovframe.cloud.boardservice.domain.posts.PostsRepository;
import org.egovframe.cloud.boardservice.api.posts.dto.*;
import org.egovframe.cloud.boardservice.domain.posts.*;
import org.egovframe.cloud.boardservice.service.board.BoardService;
import org.egovframe.cloud.common.dto.AttachmentEntityMessage;
import org.egovframe.cloud.common.dto.RequestDto;
@@ -32,7 +18,10 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import lombok.RequiredArgsConstructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* org.egovframe.cloud.postsservice.service.posts.PostsService

View File

@@ -15,7 +15,7 @@
</springProfile>
<springProfile name="!default">
<!-- java -Ddestination="localhost:5001" 와 같이 변경할 수 있다. cf 환경에서는 manifest.yml 파일에 환경변수로 추가 -->
<property name="destination" value="${destination:-localhost:5001}" />
<property name="destination" value="${logstash_hostname:-localhost:5001}" />
<property name="app_name" value="${app_name:-board-service}" />
<!-- ELK - Logstash 로 로그를 전송하기 위한 appender -->

View File

@@ -1,14 +1,6 @@
package org.egovframe.cloud.boardservice.api.board;
import static org.assertj.core.api.Assertions.assertThat;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.api.Condition;
import org.egovframe.cloud.boardservice.api.board.dto.BoardListResponseDto;
import org.egovframe.cloud.boardservice.api.board.dto.BoardResponseDto;
@@ -30,7 +22,10 @@ import org.springframework.http.ResponseEntity;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.util.*;
import static org.assertj.core.api.Assertions.assertThat;
/**
* org.egovframe.cloud.boardservice.api.board.BoardApiControllerTest

View File

@@ -1,6 +1,9 @@
# docker run --name egov-config -d -p 8888:8888 -e profile=prod -e ENCRYPT_KEY=??? egovframework/egov-config
# base image - openjdk8
FROM openjdk:8-jre-alpine
# directory 생성
RUN mkdir -p /usr/app/config
# jar 파일이 복사되는 위치
ENV APP_HOME=/usr/app/
# 작업 시작 위치
@@ -9,5 +12,5 @@ WORKDIR $APP_HOME
COPY build/libs/*.jar config.jar
# application port
EXPOSE 8888
# 실행 (ARG 아니고 ENV 값이다)
CMD ["java", "-Dspring.profiles.active=${profile:prod}", "-jar", "config.jar"]
# 실행
CMD ["java", "-Dsearch.location=/usr/app/config", "-jar", "config.jar"]

View File

@@ -10,7 +10,7 @@ spring:
config:
server:
native:
search-locations: file:///${user.home}/workspace.edu/egovframe-msa-edu/config # Windows
search-locations: ${search.location:file:///${user.home}/workspace.edu/egovframe-msa-edu/config} # Windows
# search-locations: file://${user.home}/workspace.edu/egovframe-msa-edu/config # MacOS
rabbitmq:
host: localhost

View File

@@ -8,14 +8,14 @@
</appender>
<!-- 로컬에서는 로그를 전송하지 않도록 설정 -->
<springProfile name="default">
<springProfile name="native">
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</springProfile>
<springProfile name="!default">
<!-- java -Ddestination="localhost:5001" 와 같이 변경할 수 있다. cf 환경에서는 manifest.yml 파일에 환경변수로 추가 -->
<property name="destination" value="${destination:-localhost:5001}" />
<springProfile name="!native">
<!-- java -Dlogstash_hostname="localhost:5001" 와 같이 변경할 수 있다. cf 환경에서는 manifest.yml 파일에 환경변수로 추가 -->
<property name="destination" value="${logstash_hostname:-localhost:5001}" />
<property name="app_name" value="${app_name:-config-server}" />
<!-- ELK - Logstash 로 로그를 전송하기 위한 appender -->

View File

@@ -8,7 +8,7 @@ applications:
buildpack: java_buildpack # cf buildpacks 명령어로 java buildpack 이름 확인
env:
spring_profiles_active: cf
spring_cloud_config_uri: https://egov-config.paas-ta.org
spring_cloud_config_uri: http://localhost:8888
eureka_server_enable_self_preservation: true
server_port: 80
TZ: Asia/Seoul

View File

@@ -14,5 +14,7 @@ eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@${eureka.instance.hostname:localhost}:8761/eureka
server:
peer-node-read-timeout-ms: 10000

View File

@@ -1,8 +1,8 @@
# openjdk8 base image
FROM openjdk:8-jre-alpine
# config server uri: dockder run --e 로 변경 가능
ENV SPRING_CLOUD_CONFIG_URI https://egov-config.paas-ta.org
# directory 생성
RUN mkdir -p /usr/app/msa-attach-volume/messages
# jar 파일이 복사되는 위치
ENV APP_HOME=/usr/app/
# 작업 시작 위치
@@ -11,5 +11,5 @@ WORKDIR $APP_HOME
COPY build/libs/*.jar app.jar
# application port
#EXPOSE 8000
# 실행 (application-cf.yml 프로필이 기본값)
CMD ["java", "-Dspring.profiles.active=${profile:cf}", "-jar", "app.jar"]
# 실행
CMD ["java", "-Dspring.profiles.active=${profile:default}", "-jar", "app.jar"]

View File

@@ -10,7 +10,7 @@ applications:
- egov-discovery-provided-service # discovery service binding
env:
spring_profiles_active: cf
spring_cloud_config_uri: https://egov-config.paas-ta.org
spring_cloud_config_uri: http://localhost:8888
app_name: egov-portal-service # logstash custom app name
TZ: Asia/Seoul
JAVA_OPTS: -Xss349k

View File

@@ -33,16 +33,10 @@ public class PortalApiController {
*
* @return
*/
@GetMapping("/actuator/health-portal")
@GetMapping("/actuator/health-info")
public String status() {
return String.format("GET Portal Service on" +
"\n local.server.port :" + env.getProperty("local.server.port")
+ "\n token expiration time :" + env.getProperty("token.expiration_time")
+ "\n egov.server.ip :" + env.getProperty("egov.server.ip")
+ "\n spring.datasource.username :" + env.getProperty("spring.datasource.username")
+ "\n spring.profiles.active :" + env.getProperty("spring.profiles.active")
+ "\n spring.cloud.config.label :" + env.getProperty("spring.cloud.config.label")
+ "\n spring.cloud.config.uri :" + env.getProperty("spring.cloud.config.uri")
+ "\n egov.message :" + env.getProperty("egov.message")
);
}
@@ -52,13 +46,10 @@ public class PortalApiController {
*
* @return
*/
@PostMapping("/actuator/health-portal")
@PostMapping("/actuator/health-info")
public String poststatus() {
return String.format("POST Portal Service on" +
"\n local.server.port :" + env.getProperty("local.server.port")
+ "\n token expiration time :" + env.getProperty("token.expiration_time")
+ "\n egov.server.ip :" + env.getProperty("egov.server.ip")
+ "\n spring.datasource.username :" + env.getProperty("spring.datasource.username")
+ "\n egov.message :" + env.getProperty("egov.message")
);
}

View File

@@ -1,30 +1,17 @@
package org.egovframe.cloud.portalservice.api.banner;
import java.util.List;
import java.util.Map;
import javax.validation.Valid;
import org.egovframe.cloud.portalservice.api.banner.dto.BannerImageResponseDto;
import org.egovframe.cloud.portalservice.api.banner.dto.BannerListResponseDto;
import org.egovframe.cloud.portalservice.api.banner.dto.BannerRequestDto;
import org.egovframe.cloud.portalservice.api.banner.dto.BannerResponseDto;
import org.egovframe.cloud.portalservice.api.banner.dto.BannerSaveRequestDto;
import org.egovframe.cloud.portalservice.api.banner.dto.BannerUpdateRequestDto;
import lombok.RequiredArgsConstructor;
import org.egovframe.cloud.portalservice.api.banner.dto.*;
import org.egovframe.cloud.portalservice.service.banner.BannerService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import lombok.RequiredArgsConstructor;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
/**
* org.egovframe.cloud.portalservice.api.banner.BannerApiController

View File

@@ -1,13 +1,12 @@
package org.egovframe.cloud.portalservice.api.banner.dto;
import com.querydsl.core.annotations.QueryProjection;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.querydsl.core.annotations.QueryProjection;
import lombok.Getter;
import lombok.NoArgsConstructor;
/**
* org.egovframe.cloud.portalservice.api.content.dto.BannerListResponseDto
* <p>

View File

@@ -1,11 +1,10 @@
package org.egovframe.cloud.portalservice.api.banner.dto;
import javax.validation.constraints.NotBlank;
import lombok.Getter;
import org.egovframe.cloud.portalservice.domain.banner.Banner;
import org.egovframe.cloud.portalservice.domain.menu.Site;
import lombok.Getter;
import javax.validation.constraints.NotBlank;
/**
* org.egovframe.cloud.portalservice.api.content.dto.BannerSaveRequestDto

View File

@@ -1,7 +1,6 @@
package org.egovframe.cloud.portalservice.api.content;
import javax.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.egovframe.cloud.common.dto.RequestDto;
import org.egovframe.cloud.portalservice.api.content.dto.ContentListResponseDto;
import org.egovframe.cloud.portalservice.api.content.dto.ContentResponseDto;
@@ -12,15 +11,9 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import lombok.RequiredArgsConstructor;
import javax.validation.Valid;
/**
* org.egovframe.cloud.portalservice.api.content.ContentApiController

View File

@@ -77,7 +77,6 @@ public class PolicyApiController {
*/
@PostMapping("/api/v1/policies")
public Long save(@RequestBody PolicySaveRequestDto saveRequestDto) {
System.out.println(saveRequestDto.toString());
return policyService.save(saveRequestDto);
}

View File

@@ -1,9 +1,6 @@
package org.egovframe.cloud.portalservice.api.privacy;
import java.util.List;
import javax.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.egovframe.cloud.common.dto.RequestDto;
import org.egovframe.cloud.portalservice.api.privacy.dto.PrivacyListResponseDto;
import org.egovframe.cloud.portalservice.api.privacy.dto.PrivacyResponseDto;
@@ -14,15 +11,10 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import lombok.RequiredArgsConstructor;
import javax.validation.Valid;
import java.util.List;
/**
* org.egovframe.cloud.portalservice.api.privacy.PrivacyApiController

View File

@@ -34,10 +34,9 @@ public class Resilience4JConfig {
@Bean
public Customizer<Resilience4JCircuitBreakerFactory> resilience4JCircuitBreakerFactoryCustomizer() {
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
.failureRateThreshold(50) // Circuit 열지 말지 결정하는 실패 threshold 퍼센테이지
.waitDurationInOpenState(Duration.ofSeconds(5)) // (half closed 전에) circuitBreaker가 open 되기 전에 기다리
.slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED) // circuit breaker count 기반 처리
.slidingWindowSize(10) // 통계 대상 건수 -> N건의 요청중..
.slidingWindowType(CircuitBreakerConfig.SlidingWindowType.TIME_BASED) // circuit breaker time 기반 처리
.slowCallDurationThreshold(Duration.ofSeconds(10)) // 요청 지연으로 간주하
.minimumNumberOfCalls(10) // 통계 최소 요청 건
.build();
return circuitBreakerFactory -> circuitBreakerFactory.configureDefault(

View File

@@ -428,8 +428,6 @@ public class AttachmentService extends AbstractService {
* @return
*/
public String updateEntity(String attachmentCode, AttachmentUploadRequestDto uploadRequestDto) {
System.out.println(" ====attachmentCode : " + attachmentCode);
System.out.println(" ====uploadRequestDto : " + uploadRequestDto);
List<Attachment> attachments = attachmentRepository.findByCode(attachmentCode);
for (Attachment attachment : attachments) {
attachment.updateEntity(uploadRequestDto.getEntityName(), uploadRequestDto.getEntityId());
@@ -455,7 +453,7 @@ public class AttachmentService extends AbstractService {
for (Attachment attachment: attachmentList) {
// 첨부파일 저장 후 기능 저장 시 오류 날 경우에만 첨부파일 전체 삭제를 하므로
// entity 정보가 있는 경우에는 삭제하지 못하도록 한다.
if (attachment.getEntityId() != null || StringUtils.hasText(attachment.getEntityId())) {
if ((attachment.getEntityId() != null || StringUtils.hasText(attachment.getEntityId())) && !attachment.getEntityId().equals("-1")) {
throw new BusinessMessageException(getMessage("valid.file.not_deleted"));
}
// 물리적 파일 삭제

View File

@@ -118,7 +118,6 @@ public class BannerService extends AbstractService {
*/
@Transactional
public BannerResponseDto save(BannerSaveRequestDto requestDto) {
System.out.println("@@@@@@@@requestDto:"+requestDto);
//site 정보 조회
Site site = siteRepository.findById(requestDto.getSiteId())
.orElseThrow(() ->

View File

@@ -15,7 +15,7 @@
</springProfile>
<springProfile name="!default">
<!-- java -Ddestination="localhost:5001" 와 같이 변경할 수 있다. cf 환경에서는 manifest.yml 파일에 환경변수로 추가 -->
<property name="destination" value="${destination:-localhost:5001}" />
<property name="destination" value="${logstash_hostname:-localhost:5001}" />
<property name="app_name" value="${app_name:-portal-service}" />
<!-- ELK - Logstash 로 로그를 전송하기 위한 appender -->

View File

@@ -1,6 +1,32 @@
package org.egovframe.cloud.portalservice.api.attachment;
import static org.assertj.core.api.Assertions.assertThat;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.encoders.Base64;
import org.egovframe.cloud.portalservice.api.attachment.dto.*;
import org.egovframe.cloud.portalservice.domain.attachment.Attachment;
import org.egovframe.cloud.portalservice.domain.attachment.AttachmentRepository;
import org.egovframe.cloud.portalservice.service.attachment.AttachmentService;
import org.egovframe.cloud.portalservice.util.RestResponsePage;
import org.egovframe.cloud.portalservice.utils.FileStorageUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
@@ -11,46 +37,9 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.bouncycastle.util.encoders.Base64;
import org.egovframe.cloud.portalservice.api.attachment.dto.AttachmentBase64RequestDto;
import org.egovframe.cloud.portalservice.api.attachment.dto.AttachmentEditorResponseDto;
import org.egovframe.cloud.portalservice.api.attachment.dto.AttachmentFileResponseDto;
import org.egovframe.cloud.portalservice.api.attachment.dto.AttachmentResponseDto;
import org.egovframe.cloud.portalservice.api.attachment.dto.AttachmentTempSaveRequestDto;
import org.egovframe.cloud.portalservice.api.attachment.dto.AttachmentUpdateRequestDto;
import org.egovframe.cloud.portalservice.api.attachment.dto.AttachmentUploadRequestDto;
import org.egovframe.cloud.portalservice.domain.attachment.Attachment;
import org.egovframe.cloud.portalservice.domain.attachment.AttachmentRepository;
import org.egovframe.cloud.portalservice.service.attachment.AttachmentService;
import org.egovframe.cloud.portalservice.util.RestResponsePage;
import org.egovframe.cloud.portalservice.utils.FileStorageUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import static org.assertj.core.api.Assertions.assertThat;
@Slf4j
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@@ -83,6 +72,7 @@ class AttachmentApiControllerTest {
}
}
/**
* file to byte[]
*
@@ -182,16 +172,15 @@ class AttachmentApiControllerTest {
//given
String url = "/api/v1/upload/editor";
Path testFile = Paths.get("/Users/violet/Desktop/test/300.jpg")
.toAbsolutePath().normalize();
Resource testFile = getTestFile();
String base64data = Base64.toBase64String(getByteFile(testFile.toFile()));
String base64data = Base64.toBase64String(getByteFile(testFile.getFile()));
AttachmentBase64RequestDto requestDto = AttachmentBase64RequestDto.builder()
.fieldName("upload")
.fileType("image/jpg")
.fileType("text")
.fileBase64(base64data)
.originalName("300.jpg")
.size(testFile.toFile().length())
.originalName(testFile.getFilename())
.size(testFile.getFile().length())
.build();
@@ -199,7 +188,7 @@ class AttachmentApiControllerTest {
restTemplate.postForEntity(url, requestDto, AttachmentEditorResponseDto.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(responseEntity.getBody().getOriginalFileName()).isEqualTo("300.jpg");
assertThat(responseEntity.getBody().getOriginalFileName()).isEqualTo(testFile.getFilename());
}
@Test
@@ -252,16 +241,15 @@ class AttachmentApiControllerTest {
@Test
public void 에디터이미지업로드_후_이미지태그에서_이미지파일_조회_정상() throws Exception {
//given
Path testFile = Paths.get("/Users/violet/Desktop/test/300.jpg")
.toAbsolutePath().normalize();
Resource testFile = getTestFile();
String base64data = Base64.toBase64String(getByteFile(testFile.toFile()));
String base64data = Base64.toBase64String(getByteFile(testFile.getFile()));
AttachmentBase64RequestDto requestDto = AttachmentBase64RequestDto.builder()
.fieldName("upload")
.fileType("image/jpg")
.fileType("text")
.fileBase64(base64data)
.originalName("300.jpg")
.size(testFile.toFile().length())
.originalName(testFile.getFilename())
.size(testFile.contentLength())
.build();
AttachmentEditorResponseDto responseDto = attachmentService.uploadEditor(requestDto);
@@ -279,7 +267,7 @@ class AttachmentApiControllerTest {
//given
List<AttachmentTempSaveRequestDto> saveRequestDtoList = getTempSaveDto(2);
String url = "/api/v1/attachments/temp";
String url = "/api/v1/attachments/file";
//when
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, saveRequestDtoList, String.class);
@@ -337,7 +325,7 @@ class AttachmentApiControllerTest {
HttpEntity<List<AttachmentTempSaveRequestDto>> requestEntity = new HttpEntity<>(updateRequestDtoList);
//when
String url = "/api/v1/attachments/temp/"+attachmentCode;
String url = "/api/v1/attachments/file/"+attachmentCode;
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.PUT, requestEntity, String.class);
@@ -354,7 +342,7 @@ class AttachmentApiControllerTest {
List<AttachmentTempSaveRequestDto> saveRequestDtoList2 = getTempSaveDto(3);
attachmentService.save(saveRequestDtoList2);
String url = "/api/v1/attachments/admin";
String url = "/api/v1/attachments";
//when
ResponseEntity<RestResponsePage<AttachmentResponseDto>> responseEntity = restTemplate.exchange(
@@ -383,7 +371,7 @@ class AttachmentApiControllerTest {
List<AttachmentTempSaveRequestDto> saveRequestDtoList2 = getTempSaveDto(3);
String attachmentCode = attachmentService.save(saveRequestDtoList2);
String url = "/api/v1/attachments/admin?keywordType=id&keyword="+attachmentCode;
String url = "/api/v1/attachments?keywordType=id&keyword="+attachmentCode;
//when
ResponseEntity<RestResponsePage<AttachmentResponseDto>> responseEntity = restTemplate.exchange(
@@ -412,7 +400,7 @@ class AttachmentApiControllerTest {
List<AttachmentResponseDto> results = attachmentService.findByCode(attachmentCode);
String uniqueId = results.get(1).getId();
String url = "/api/v1/attachments/admin/"+uniqueId+"/true";
String url = "/api/v1/attachments/"+uniqueId+"/true";
//when
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.PUT, null, String.class);
@@ -420,10 +408,10 @@ class AttachmentApiControllerTest {
//then
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
List<AttachmentResponseDto> saved = attachmentService.findByCode(attachmentCode);
AttachmentResponseDto updated = saved.stream()
.filter(attachmentResponseDto -> attachmentResponseDto.getId().equals(uniqueId))
.findAny().get();
assertThat(updated.getIsDelete()).isTrue();
Optional<AttachmentResponseDto> any = saved.stream()
.filter(attachmentResponseDto -> attachmentResponseDto.getId().equals(uniqueId))
.findAny();
assertThat(any.isPresent()).isFalse();
}
@Test
@@ -433,7 +421,7 @@ class AttachmentApiControllerTest {
String attachmentCode = attachmentService.save(saveRequestDtoList2);
List<AttachmentResponseDto> results = attachmentService.findByCode(attachmentCode);
String url = "/api/v1/attachments/admin/"+results.get(1).getId();
String url = "/api/v1/attachments/"+results.get(1).getId();
//when
restTemplate.delete(url);
@@ -500,7 +488,6 @@ class AttachmentApiControllerTest {
);
}
saveRequestDtoList.stream().forEach(System.out::println);
//2개 첨부파일 더하기
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
@@ -570,24 +557,4 @@ class AttachmentApiControllerTest {
}
//
// @Test
// public void 첨부파일_다운로드_정상() throws Exception {
// //given
// List<AttachmentSaveRequestDto> saveRequestDtoList2 = getTempSaveDto(1);
// String attachmentCode = attachmentService.save(saveRequestDtoList2);
//
// List<AttachmentResponseDto> byCode = attachmentService.findByCode(attachmentCode);
//
// String uniqueId = byCode.get(0).getUniqueId();
// String url = "/api/v1/download/"+uniqueId;
//
// //when
// ResponseEntity<ResponseEntity> responseEntity = restTemplate.getForEntity(url, ResponseEntity.class);
//
// //then
// re
//
// }
}

View File

@@ -37,7 +37,6 @@ import org.springframework.test.context.TestPropertySource;
@ActiveProfiles(profiles = "test")
class MenuApiControllerTest {
@Autowired
private TestRestTemplate restTemplate;
@@ -51,9 +50,9 @@ class MenuApiControllerTest {
@BeforeEach
public void setup() throws Exception {
siteRepository.save(Site.builder()
.name("site")
.isUse(true)
.build()
.name("site")
.isUse(true)
.build()
);
}
@@ -68,24 +67,24 @@ class MenuApiControllerTest {
Site site = siteRepository.findAll().get(0);
Menu parentMenu = menuRepository.save(Menu.builder()
.menuKorName("parent")
.sortSeq(1)
.site(site)
.build());
.menuKorName("parent")
.sortSeq(1)
.site(site)
.build());
for (int i = 0; i < 3; i++) {
Menu childMenu = Menu.builder()
.menuKorName("child_" + i)
.site(site)
.parent(parentMenu)
.sortSeq(i + 1)
.build();
.menuKorName("child_" + i)
.site(site)
.parent(parentMenu)
.sortSeq(i + 1)
.build();
childMenu.setParentMenu(parentMenu);
menuRepository.save(childMenu);
}
//when
ResponseEntity<List<MenuTreeResponseDto>> responseEntity = restTemplate.exchange("/api/v1/"+site.getId()+"/menus", HttpMethod.GET, null, new ParameterizedTypeReference<List<MenuTreeResponseDto>>(){});
ResponseEntity<List<MenuTreeResponseDto>> responseEntity = restTemplate.exchange("/api/v1/menus/"+site.getId()+"/tree", HttpMethod.GET, null, new ParameterizedTypeReference<List<MenuTreeResponseDto>>(){});
//then
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
@@ -102,14 +101,14 @@ class MenuApiControllerTest {
public void 메뉴관리_사이트콤보_목록_조회한다() throws Exception {
//given
siteRepository.save(Site.builder()
.name("portal")
.isUse(true)
.build()
.name("portal")
.isUse(true)
.build()
);
siteRepository.save(Site.builder()
.name("admin")
.isUse(true)
.build()
.name("admin")
.isUse(true)
.build()
);
//when
@@ -127,50 +126,50 @@ class MenuApiControllerTest {
Site site = siteRepository.findAll().get(0);
Menu parentMenu1 = menuRepository.save(Menu.builder()
.menuKorName("parent_1")
.sortSeq(1)
.site(site)
.build());
.menuKorName("parent_1")
.sortSeq(1)
.site(site)
.build());
Menu parentMenu2 = menuRepository.save(Menu.builder()
.menuKorName("parent_2")
.sortSeq(2)
.site(site)
.build());
.menuKorName("parent_2")
.sortSeq(2)
.site(site)
.build());
for (int i = 0; i < 3; i++) {
Menu childMenu1 = Menu.builder()
.menuKorName("child_1_" + i)
.site(site)
.parent(parentMenu1)
.sortSeq(i + 1)
.build();
.menuKorName("child_1_" + i)
.site(site)
.parent(parentMenu1)
.sortSeq(i + 1)
.build();
childMenu1.setParentMenu(parentMenu1);
menuRepository.save(childMenu1);
if (i == 1) {
Menu childChildMenu = Menu.builder()
.menuKorName("child_child_1")
.site(site)
.parent(childMenu1)
.sortSeq(1)
.build();
.menuKorName("child_child_1")
.site(site)
.parent(childMenu1)
.sortSeq(1)
.build();
childChildMenu.setParentMenu(childMenu1);
menuRepository.save(childChildMenu);
Menu childChildMenu2 = Menu.builder()
.menuKorName("child_child_1")
.site(site)
.parent(childMenu1)
.sortSeq(2)
.build();
.menuKorName("child_child_1")
.site(site)
.parent(childMenu1)
.sortSeq(2)
.build();
childChildMenu2.setParentMenu(childMenu1);
menuRepository.save(childChildMenu2);
}
Menu childMenu2 = Menu.builder()
.menuKorName("child_2_" + i)
.site(site)
.parent(parentMenu2)
.sortSeq(i + 1)
.build();
.menuKorName("child_2_" + i)
.site(site)
.parent(parentMenu2)
.sortSeq(i + 1)
.build();
childMenu1.setParentMenu(parentMenu2);
menuRepository.save(childMenu2);
}
@@ -197,18 +196,19 @@ class MenuApiControllerTest {
Site site = siteRepository.findAll().get(0);
Menu parentMenu = menuRepository.save(Menu.builder()
.menuKorName("parent")
.sortSeq(1)
.site(site)
.build());
.menuKorName("parent")
.menuKorName("parenteng")
.sortSeq(1)
.site(site)
.build());
//when
String url = "/api/v1/manager/menus/"+parentMenu.getId();
String url = "/api/v1/menus/"+parentMenu.getId();
ResponseEntity<MenuResponseDto> responseEntity = restTemplate.getForEntity(url, MenuResponseDto.class);
//then
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(responseEntity.getBody()).extracting("name").isEqualTo(parentMenu.getMenuKorName());
assertThat(responseEntity.getBody()).extracting("menuKorName").isEqualTo(parentMenu.getMenuKorName());
System.out.println(responseEntity.getBody());
}
@@ -219,11 +219,11 @@ class MenuApiControllerTest {
Site site = siteRepository.findAll().get(0);
MenuTreeRequestDto menuTreeRequestDto = MenuTreeRequestDto.builder()
.parentId(null)
.siteId(site.getId())
.name("parent")
.sortSeq(1)
.build();
.parentId(null)
.siteId(site.getId())
.name("parent")
.sortSeq(1)
.build();
String url = "/api/v1/menus";
@@ -237,35 +237,30 @@ class MenuApiControllerTest {
}
/**
* @TODO
* bulk update 수정 필요
* @throws Exception
*/
@Test
public void 메뉴관리_트리_드래그앤드랍_순서_및_부모메뉴_변경() throws Exception {
//given
Site site = siteRepository.findAll().get(0);
Menu parentMenu1 = menuRepository.save(Menu.builder()
.menuKorName("parent_1")
.sortSeq(1)
.site(site)
.build());
.menuKorName("parent_1")
.sortSeq(1)
.site(site)
.build());
Menu parentMenu2 = menuRepository.save(Menu.builder()
.menuKorName("parent_2")
.sortSeq(2)
.site(site)
.build());
.menuKorName("parent_2")
.sortSeq(2)
.site(site)
.build());
Long menuId = 0L;
for (int i = 0; i < 3; i++) {
Menu childMenu1 = Menu.builder()
.menuKorName("child_1_" + i)
.site(site)
.parent(parentMenu1)
.sortSeq(i + 1)
.build();
.menuKorName("child_1_" + i)
.site(site)
.parent(parentMenu1)
.sortSeq(i + 1)
.build();
childMenu1.setParentMenu(parentMenu1);
Menu save = menuRepository.save(childMenu1);
menuId = save.getId();
@@ -274,25 +269,24 @@ class MenuApiControllerTest {
List<MenuDnDRequestDto> updateList = new ArrayList<>();
updateList.add(MenuDnDRequestDto.builder()
.menuId(menuId)
.sortSeq(1)
.parentId(parentMenu2.getId())
.build());
.menuId(menuId)
.sortSeq(1)
.parentId(parentMenu2.getId())
.build());
HttpEntity<List<MenuDnDRequestDto>> httpEntity = new HttpEntity<>(
updateList
updateList
);
String url = "/api/v1/menus/"+site.getId()+"/tree";
//when
ResponseEntity<List<MenuTreeResponseDto>> responseEntity =
restTemplate.exchange(url, HttpMethod.PUT, httpEntity, new ParameterizedTypeReference<List<MenuTreeResponseDto>>(){});
ResponseEntity<Long> responseEntity =
restTemplate.exchange(url, HttpMethod.PUT, httpEntity, Long.class);
//then
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
responseEntity.getBody().stream().forEach(System.out::println);
}
@@ -301,19 +295,19 @@ class MenuApiControllerTest {
Site site = siteRepository.findAll().get(0);
Menu parentMenu1 = menuRepository.save(Menu.builder()
.menuKorName("parent_1")
.sortSeq(1)
.site(site)
.build());
.menuKorName("parent_1")
.sortSeq(1)
.site(site)
.build());
Long menuId = 0L;
for (int i = 0; i < 3; i++) {
Menu childMenu1 = Menu.builder()
.menuKorName("child_1_" + i)
.site(site)
.parent(parentMenu1)
.sortSeq(i + 1)
.build();
.menuKorName("child_1_" + i)
.site(site)
.parent(parentMenu1)
.sortSeq(i + 1)
.build();
childMenu1.setParentMenu(parentMenu1);
Menu save = menuRepository.save(childMenu1);
menuId = save.getId();
@@ -323,7 +317,7 @@ class MenuApiControllerTest {
//when
ResponseEntity<MenuTreeResponseDto> responseEntity =
restTemplate.exchange(url, HttpMethod.PUT, null, MenuTreeResponseDto.class);
restTemplate.exchange(url, HttpMethod.PUT, null, MenuTreeResponseDto.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(responseEntity.getBody().getName()).isEqualTo("updateName");
@@ -336,31 +330,31 @@ class MenuApiControllerTest {
Site site = siteRepository.findAll().get(0);
Menu parentMenu1 = menuRepository.save(Menu.builder()
.menuKorName("parent_1")
.sortSeq(1)
.site(site)
.build());
.menuKorName("parent_1")
.sortSeq(1)
.site(site)
.build());
String url = "/api/v1/menus/"+parentMenu1.getId();
HttpEntity<MenuUpdateRequestDto> httpEntity = new HttpEntity<>(
MenuUpdateRequestDto.builder()
.description("상위메뉴")
.connectId(1)
.menuType("menuType")
.urlPath("/index")
.subName("subname")
.isUse(true)
.isShow(true)
.isBlank(false)
.icon("icon")
MenuUpdateRequestDto.builder()
.description("상위메뉴")
.connectId(1)
.menuType("menuType")
.urlPath("/index")
.subName("subname")
.isUse(true)
.isShow(true)
.isBlank(false)
.icon("icon")
.build()
);
//when
ResponseEntity<MenuResponseDto> responseEntity =
restTemplate.exchange(url, HttpMethod.PUT, httpEntity, MenuResponseDto.class);
restTemplate.exchange(url, HttpMethod.PUT, httpEntity, MenuResponseDto.class);
//then
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
@@ -375,19 +369,19 @@ class MenuApiControllerTest {
Site site = siteRepository.findAll().get(0);
Menu parentMenu1 = menuRepository.save(Menu.builder()
.menuKorName("parent_1")
.sortSeq(1)
.site(site)
.build());
.menuKorName("parent_1")
.sortSeq(1)
.site(site)
.build());
Long menuId = 0L;
for (int i = 0; i < 3; i++) {
Menu childMenu1 = Menu.builder()
.menuKorName("child_1_" + i)
.site(site)
.parent(parentMenu1)
.sortSeq(i + 1)
.build();
.menuKorName("child_1_" + i)
.site(site)
.parent(parentMenu1)
.sortSeq(i + 1)
.build();
childMenu1.setParentMenu(parentMenu1);
Menu save = menuRepository.save(childMenu1);
menuId = save.getId();
@@ -409,19 +403,19 @@ class MenuApiControllerTest {
Site site = siteRepository.findAll().get(0);
Menu parentMenu1 = menuRepository.save(Menu.builder()
.menuKorName("parent_1")
.sortSeq(1)
.site(site)
.build());
.menuKorName("parent_1")
.sortSeq(1)
.site(site)
.build());
Long menuId = 0L;
for (int i = 0; i < 3; i++) {
Menu childMenu1 = Menu.builder()
.menuKorName("child_1_" + i)
.site(site)
.parent(parentMenu1)
.sortSeq(i + 1)
.build();
.menuKorName("child_1_" + i)
.site(site)
.parent(parentMenu1)
.sortSeq(i + 1)
.build();
childMenu1.setParentMenu(parentMenu1);
Menu save = menuRepository.save(childMenu1);
menuId = save.getId();

View File

@@ -15,6 +15,7 @@ import org.egovframe.cloud.portalservice.domain.menu.MenuRole;
import org.egovframe.cloud.portalservice.domain.menu.MenuRoleRepository;
import org.egovframe.cloud.portalservice.domain.menu.Site;
import org.egovframe.cloud.portalservice.domain.menu.SiteRepository;
import org.egovframe.cloud.portalservice.domain.user.Role;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -36,7 +37,6 @@ import org.springframework.test.context.TestPropertySource;
@ActiveProfiles(profiles = "test")
class MenuRoleApiControllerTest {
@Autowired
private TestRestTemplate restTemplate;
@@ -52,24 +52,24 @@ class MenuRoleApiControllerTest {
@BeforeEach
public void setup() throws Exception {
Site site = Site.builder()
.name("site")
.isUse(true)
.build();
.name("site")
.isUse(true)
.build();
siteRepository.save(site);
Menu parentMenu = menuRepository.save(Menu.builder()
.menuKorName("parent")
.sortSeq(1)
.site(site)
.build());
.menuKorName("parent")
.sortSeq(1)
.site(site)
.build());
for (int i = 0; i < 3; i++) {
Menu childMenu = Menu.builder()
.menuKorName("child_" + i)
.site(site)
.parent(parentMenu)
.sortSeq(i + 1)
.build();
.menuKorName("child_" + i)
.site(site)
.parent(parentMenu)
.sortSeq(i + 1)
.build();
childMenu.setParentMenu(parentMenu);
menuRepository.save(childMenu);
}
@@ -87,7 +87,7 @@ class MenuRoleApiControllerTest {
Site site = siteRepository.findAll().get(0);
//when
ResponseEntity<List<MenuRoleResponseDto>> responseEntity =
restTemplate.exchange("/api/v1/menu-roles/role/"+site.getId(), HttpMethod.GET, null, new ParameterizedTypeReference<List<MenuRoleResponseDto>>(){});
restTemplate.exchange("/api/v1/menu-roles/role/"+site.getId(), HttpMethod.GET, null, new ParameterizedTypeReference<List<MenuRoleResponseDto>>(){});
//then
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
@@ -108,22 +108,25 @@ class MenuRoleApiControllerTest {
Menu child1 = menus.stream().filter(menu -> menu.getMenuKorName().equals("child_1")).collect(Collectors.toList()).get(0);
List<MenuRole> menuRoles = new ArrayList<>();
menuRoles.add(MenuRole.builder().roleId("role").menu(parent).build());
menuRoles.add(MenuRole.builder().roleId("role").menu(child1).build());
MenuRole menuRole1 = MenuRole.builder().roleId("ROLE").menu(parent).build();
menuRoles.add(menuRole1);
MenuRole menuRole2 = MenuRole.builder().roleId("ROLE").menu(child1).build();
menuRoles.add(menuRole2);
menuRoleRepository.saveAll(menuRoles);
Site site = siteRepository.findAll().get(0);
//when
ResponseEntity<List<MenuRoleResponseDto>> responseEntity =
restTemplate.exchange("/api/v1/menu-roles/role/"+site.getId(), HttpMethod.GET, null, new ParameterizedTypeReference<List<MenuRoleResponseDto>>(){});
restTemplate.exchange("/api/v1/menu-roles/role/"+site.getId(), HttpMethod.GET, null, new ParameterizedTypeReference<List<MenuRoleResponseDto>>(){});
//then
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
List<MenuRoleResponseDto> body = responseEntity.getBody();
assertThat(body.size()).isEqualTo(1);
assertThat(body.get(0).getIsChecked()).isTrue();
body.stream().forEach(System.out::println);
assertThat(body.get(0).getIsChecked()).isTrue();
assertThat(body.get(0).getChildren().size()).isEqualTo(3);
body.stream().forEach(menuTreeResponseDto -> {
menuTreeResponseDto.getChildren().stream().forEach(child -> {
@@ -149,38 +152,39 @@ class MenuRoleApiControllerTest {
list.get(0).getChildren().stream().forEach(menuRoleResponseDto -> {
if (menuRoleResponseDto.getKorName().equals("child_1")) {
children.add(MenuRoleRequestDto.builder()
.menuRoleId(menuRoleResponseDto.getMenuRoleId())
.isChecked(true)
.roleId("role")
.id(menuRoleResponseDto.getId())
.build());
.menuRoleId(menuRoleResponseDto.getMenuRoleId())
.isChecked(true)
.roleId("ROLE")
.id(menuRoleResponseDto.getId())
.build());
}else {
children.add(MenuRoleRequestDto.builder()
.menuRoleId(menuRoleResponseDto.getMenuRoleId())
.isChecked(false)
.roleId("role")
.id(menuRoleResponseDto.getId())
.build());
.menuRoleId(menuRoleResponseDto.getMenuRoleId())
.isChecked(false)
.roleId("ROLE")
.id(menuRoleResponseDto.getId())
.build());
}
});
requestDtoList.add(MenuRoleRequestDto.builder()
.menuRoleId(list.get(0).getMenuRoleId())
.isChecked(true)
.id(list.get(0).getId())
.children(children)
.build());
.menuRoleId(list.get(0).getMenuRoleId())
.isChecked(true)
.roleId("ROLE")
.id(list.get(0).getId())
.children(children)
.build());
HttpEntity<List<MenuRoleRequestDto>> httpEntity = new HttpEntity<>(
requestDtoList
requestDtoList
);
//when
ResponseEntity<String> responseEntity =
restTemplate.exchange("/api/v1/menu-roles", HttpMethod.POST, httpEntity, String.class);
restTemplate.exchange("/api/v1/menu-roles", HttpMethod.POST, httpEntity, String.class);
//then
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
@@ -197,36 +201,38 @@ class MenuRoleApiControllerTest {
//given
Site site = siteRepository.findAll().get(0);
Menu parentMenu = menuRepository.save(Menu.builder()
.menuKorName("parent-any")
.sortSeq(1)
.site(site)
.build());
.menuKorName("parent-any")
.sortSeq(1)
.site(site)
.isUse(true)
.build());
MenuRole parentMenuRole = MenuRole.builder()
.roleId("ROLE_ANONYMOUS")
.menu(parentMenu)
.build();
.roleId(Role.ANONYMOUS.getKey())
.menu(parentMenu)
.build();
parentMenuRole.setMenu(parentMenu);
menuRoleRepository.save(parentMenuRole);
for (int i = 0; i < 3; i++) {
Menu childMenu = Menu.builder()
.menuKorName("child-any_" + i)
.site(site)
.parent(parentMenu)
.sortSeq(i + 1)
.build();
.menuKorName("child-any_" + i)
.site(site)
.parent(parentMenu)
.sortSeq(i + 1)
.isUse(true)
.build();
childMenu.setParentMenu(parentMenu);
menuRepository.save(childMenu);
MenuRole role_any = MenuRole.builder()
.roleId("ROLE_ANONYMOUS")
.menu(childMenu)
.build();
.roleId(Role.ANONYMOUS.getKey())
.menu(childMenu)
.build();
role_any.setMenu(childMenu);
menuRoleRepository.save(role_any);
}
//when
ResponseEntity<List<MenuSideResponseDto>> responseEntity =
restTemplate.exchange("/api/v1/menu-roles/"+site.getId(), HttpMethod.GET, null, new ParameterizedTypeReference<List<MenuSideResponseDto>>(){});
restTemplate.exchange("/api/v1/menu-roles/"+site.getId(), HttpMethod.GET, null, new ParameterizedTypeReference<List<MenuSideResponseDto>>(){});
//then

View File

@@ -59,12 +59,12 @@ class PolicyApiControllerTest {
}
policyRepository.save(Policy.builder()
.type(type)
.title(title)
.isUse(true)
.regDate(ZonedDateTime.now())
.contents(contents)
.build());
.type(type)
.title(title)
.isUse(true)
.regDate(ZonedDateTime.now())
.contents(contents)
.build());
}
}
@@ -81,17 +81,16 @@ class PolicyApiControllerTest {
String contents = "test contents";
PolicySaveRequestDto requestDto = PolicySaveRequestDto.builder()
.type(type)
.title(title)
.isUse(true)
.regDate(ZonedDateTime.now())
.contents(contents)
.build();
.type(type)
.title(title)
.isUse(true)
.regDate(ZonedDateTime.now())
.contents(contents)
.build();
String url = "http://localhost:"+port+API_URL;
//when
ResponseEntity<Long> responseEntity = restTemplate.postForEntity(url, requestDto, Long.class);
ResponseEntity<Long> responseEntity = restTemplate.postForEntity(API_URL, requestDto, Long.class);
//then
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
@@ -104,10 +103,10 @@ class PolicyApiControllerTest {
@Test
public void 목록조회한다() throws Exception {
String url = "http://localhost:"+port+API_URL+"?size=3%page=0";
String url = API_URL+"?size=3%page=0";
//when
ResponseEntity<RestResponsePage<PolicyResponseDto>> responseEntity =
restTemplate.exchange(url, HttpMethod.GET, null, new ParameterizedTypeReference<RestResponsePage<PolicyResponseDto>>() {});
restTemplate.exchange(url, HttpMethod.GET, null, new ParameterizedTypeReference<RestResponsePage<PolicyResponseDto>>() {});
//then
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
@@ -134,7 +133,7 @@ class PolicyApiControllerTest {
@Test
public void ID로_한건조회_정상() throws Exception {
String url = "http://localhost:"+port+API_URL +"/9";
String url = API_URL +"/9";
//when
ResponseEntity<PolicyResponseDto> responseEntity = restTemplate.getForEntity(url, PolicyResponseDto.class);
@@ -148,17 +147,17 @@ class PolicyApiControllerTest {
public void 이용약관_수정_된다() throws Exception {
//given
Long id = policyRepository.save(Policy.builder()
.type("TOS")
.title("title")
.contents("contents!!!!")
.build()
.type("TOS")
.title("title")
.contents("contents!!!!")
.build()
).getId();
String url = "http://localhost:"+port+API_URL +"/"+id;
String url = API_URL +"/"+id;
PolicyUpdateRequestDto requestDto = PolicyUpdateRequestDto.builder()
.title("update title")
.contents("update Details")
.build();
.title("update title")
.contents("update Details")
.build();
//when
HttpEntity<PolicyUpdateRequestDto> requestEntity = new HttpEntity<>(requestDto);
@@ -178,12 +177,12 @@ class PolicyApiControllerTest {
public void 이용약관_삭제_한다() {
//given
Long id = policyRepository.save(Policy.builder()
.type("TOS")
.title("title")
.contents("contents!!!!")
.build()
.type("TOS")
.title("title")
.contents("contents!!!!")
.build()
).getId();
String url = "http://localhost:"+port+API_URL +"/"+id;
String url = API_URL +"/"+id;
//when
restTemplate.delete(url);
@@ -197,13 +196,13 @@ class PolicyApiControllerTest {
public void 사용여부_수정_한다() throws Exception {
//given
Long id = policyRepository.save(Policy.builder()
.type("TOS")
.title("title")
.isUse(true)
.contents("contents!!!")
.build()
.type("TOS")
.title("title")
.isUse(true)
.contents("contents!!!")
.build()
).getId();
String url = "http://localhost:"+port+API_URL +"/"+id+"/"+false;
String url = API_URL +"/"+id+"/"+false;
//when
ResponseEntity<Long> responseEntity = restTemplate.exchange(url, HttpMethod.PUT, null, Long.class);

View File

@@ -2,6 +2,7 @@ package org.egovframe.cloud.portalservice.api.statistics;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.LocalDate;
import java.util.List;
import org.egovframe.cloud.portalservice.api.statistics.dto.StatisticsResponseDto;
@@ -33,14 +34,13 @@ class StatisticsApiControllerTest {
@Autowired
private StatisticsRepository statisticsRepository;
@BeforeEach
public void setup() {
for (int i = 0; i < 10; i++) {
statisticsRepository.save(Statistics.builder()
.siteId(1L)
.remoteIp("testip")
.build());
.siteId(1L)
.remoteIp("testip")
.build());
}
}
@@ -55,10 +55,10 @@ class StatisticsApiControllerTest {
Long siteId = 1L;
// when
ResponseEntity< List<StatisticsResponseDto>> responseEntity =
restTemplate.exchange("/api/v1/statistics/monthly/"+siteId,
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<StatisticsResponseDto>>(){});
restTemplate.exchange("/api/v1/statistics/monthly/"+siteId,
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<StatisticsResponseDto>>(){});
responseEntity.getBody().forEach(System.out::println);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
@@ -70,12 +70,14 @@ class StatisticsApiControllerTest {
public void 일별접속통계_조회_성공() throws Exception {
Long siteId = 1L;
LocalDate now = LocalDate.now();
// when
ResponseEntity< List<StatisticsResponseDto>> responseEntity =
restTemplate.exchange("/api/v1/statistics/daily/"+siteId+"?year=2021&month=9",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<StatisticsResponseDto>>(){});
restTemplate.exchange("/api/v1/statistics/daily/"+siteId+"?year="+now.getYear()+"&month="+now.getMonthValue(),
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<StatisticsResponseDto>>(){});
responseEntity.getBody().forEach(System.out::println);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);

View File

@@ -1,8 +1,6 @@
# openjdk8 base image
FROM openjdk:8-jre-alpine
# config server uri: dockder run --e 로 변경 가능
ENV SPRING_CLOUD_CONFIG_URI https://egov-config.paas-ta.org
# jar 파일이 복사되는 위치
ENV APP_HOME=/usr/app/
# 작업 시작 위치

View File

@@ -10,7 +10,7 @@ applications:
- egov-discovery-provided-service # discovery service binding
env:
spring_profiles_active: cf
spring_cloud_config_uri: https://egov-config.paas-ta.org
spring_cloud_config_uri: http://localhost:8888
app_name: egov-reserve-check-service # logstash custom app name
TZ: Asia/Seoul
JAVA_OPTS: -Xss349k

View File

@@ -1,36 +1,36 @@
package org.egovframe.cloud.reservechecksevice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;
import reactivefeign.spring.config.EnableReactiveFeignClients;
import reactor.blockhound.BlockHound;
import java.security.Security;
@ComponentScan({"org.egovframe.cloud.common", "org.egovframe.cloud.reactive", "org.egovframe.cloud.reservechecksevice"}) // org.egovframe.cloud.common package 포함하기 위해
@EnableDiscoveryClient
@EnableReactiveFeignClients
@SpringBootApplication
public class ReserveCheckSeviceApplication {
public static void main(String[] args) {
// TLSv1/v1.1 No longer works after upgrade, "No appropriate protocol" error
String property = Security.getProperty("jdk.tls.disabledAlgorithms").replace(", TLSv1", "").replace(", TLSv1.1", "");
Security.setProperty("jdk.tls.disabledAlgorithms", property);
//blocking 코드 감지
BlockHound.builder()
//mysql r2dbc 에서 호출되는 FileInputStream.readBytes() 가 블로킹코드인데 이를 허용해주도록 한다.
//해당 코드가 어디서 호출되는지 알지 못하는 상태에서 FileInputStream.readBytes() 자체를 허용해주는 것은 좋지 않다.
// 누군가 무분별하게 사용하게 되면 검출해 낼 수ㅂ 없어 시스템의 위험요소로 남게 된다.
// r2dbc를 사용하기 위해 해당 호출부분만 허용하고 나머지는 여전히 검출대상으로 남기도록 한다.
.allowBlockingCallsInside("dev.miku.r2dbc.mysql.client.ReactorNettyClient", "init")
.install();
SpringApplication.run(ReserveCheckSeviceApplication.class, args);
}
}
package org.egovframe.cloud.reservechecksevice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;
import reactivefeign.spring.config.EnableReactiveFeignClients;
//import reactor.blockhound.BlockHound;
import java.security.Security;
@ComponentScan({"org.egovframe.cloud.common", "org.egovframe.cloud.reactive", "org.egovframe.cloud.reservechecksevice"}) // org.egovframe.cloud.common package 포함하기 위해
@EnableDiscoveryClient
@EnableReactiveFeignClients
@SpringBootApplication
public class ReserveCheckSeviceApplication {
public static void main(String[] args) {
// TLSv1/v1.1 No longer works after upgrade, "No appropriate protocol" error
String property = Security.getProperty("jdk.tls.disabledAlgorithms").replace(", TLSv1", "").replace(", TLSv1.1", "");
Security.setProperty("jdk.tls.disabledAlgorithms", property);
//blocking 코드 감지
// BlockHound.builder()
// //mysql r2dbc 에서 호출되는 FileInputStream.readBytes() 가 블로킹코드인데 이를 허용해주도록 한다.
// //해당 코드가 어디서 호출되는지 알지 못하는 상태에서 FileInputStream.readBytes() 자체를 허용해주는 것은 좋지 않다.
// // 누군가 무분별하게 사용하게 되면 검출해 낼 수ㅂ 없어 시스템의 위험요소로 남게 된다.
// // r2dbc를 사용하기 위해 해당 호출부분만 허용하고 나머지는 여전히 검출대상으로 남기도록 한다.
// .allowBlockingCallsInside("dev.miku.r2dbc.mysql.client.ReactorNettyClient", "init")
// .install();
SpringApplication.run(ReserveCheckSeviceApplication.class, args);
}
}

View File

@@ -1,17 +1,530 @@
package org.egovframe.cloud.reservechecksevice.api;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;
import java.time.LocalDateTime;
import org.egovframe.cloud.common.domain.Role;
import org.egovframe.cloud.common.exception.dto.ErrorCode;
import org.egovframe.cloud.common.exception.dto.ErrorResponse;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveCancelRequestDto;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveListResponseDto;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveSaveRequestDto;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveUpdateRequestDto;
import org.egovframe.cloud.reservechecksevice.client.ReserveItemServiceClient;
import org.egovframe.cloud.reservechecksevice.client.UserServiceClient;
import org.egovframe.cloud.reservechecksevice.client.dto.ReserveItemRelationResponseDto;
import org.egovframe.cloud.reservechecksevice.client.dto.ReserveItemResponseDto;
import org.egovframe.cloud.reservechecksevice.client.dto.UserResponseDto;
import org.egovframe.cloud.reservechecksevice.domain.location.Location;
import org.egovframe.cloud.reservechecksevice.domain.reserve.Reserve;
import org.egovframe.cloud.reservechecksevice.domain.reserve.ReserveItem;
import org.egovframe.cloud.reservechecksevice.domain.reserve.ReserveRepository;
import org.egovframe.cloud.reservechecksevice.domain.reserve.ReserveStatus;
import org.egovframe.cloud.reservechecksevice.util.RestResponsePage;
import org.egovframe.cloud.reservechecksevice.util.WithCustomMockUser;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.BDDMockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.reactive.server.WebTestClient;
import reactor.core.publisher.Mono;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@EnableConfigurationProperties
@TestPropertySource(properties = {"spring.config.location=classpath:application-test.yml"})
@ActiveProfiles(profiles = "test")
class ReserveApiControllerTest {
public class ReserveApiControllerTest {
@Autowired
private ReserveRepository reserveRepository;
@MockBean
private ReserveItemServiceClient reserveItemServiceClient;
@MockBean
private UserServiceClient userServiceClient;
}
@Autowired
private WebTestClient webTestClient;
private static final String API_URL = "/api/v1/reserves";
private UserResponseDto user;
private Location location;
private ReserveItem reserveItem;
private Reserve reserve;
@BeforeEach
public void setup() {
user = UserResponseDto.builder()
.roleId(Role.ADMIN.getKey())
.userId("user")
.build();
location = Location.builder()
.locationId(1L)
.locationName("location")
.build();
reserveItem = ReserveItem.builder()
.reserveItemId(1L)
.reserveItemName("test")
.locationId(location.getLocationId())
.location(location)
.categoryId("place")
.inventoryQty(100)
.totalQty(100)
.reserveMethodId("internet")
.reserveMeansId("realtime")
.requestStartDate(LocalDateTime.of(2021, 1, 1, 1, 1))
.requestEndDate(LocalDateTime.of(2021, 12, 31, 23, 59))
.operationStartDate(LocalDateTime.of(2021, 1, 1, 1, 1))
.operationEndDate(LocalDateTime.of(2021, 12, 31, 23, 59))
.build();
reserve = Reserve.builder()
.reserveId("1")
.reserveItemId(reserveItem.getReserveItemId())
.reserveQty(50)
.reservePurposeContent("test")
.reserveStatusId("request")
.reserveStartDate(LocalDateTime.of(2021, 9, 9, 1, 1))
.reserveEndDate(LocalDateTime.of(2021, 9, 20, 1, 1))
.userId(user.getUserId())
.userEmail("user@email.com")
.userContactNo("contact")
.build();
reserve.setReserveItem(reserveItem);
reserve.setUser(user);
}
@AfterEach
public void tearDown() {
reserveRepository.deleteAll().block();
}
@Test
public void 예약신청관리_목록_조회_성공() throws Exception {
//given
BDDMockito.when(userServiceClient.findByUserId(ArgumentMatchers.anyString()))
.thenReturn(Mono.just(user));
BDDMockito.when(reserveItemServiceClient.findByIdWithRelations(ArgumentMatchers.anyLong()))
.thenReturn(Mono.just(ReserveItemRelationResponseDto.builder().entity(reserveItem).build()));
Reserve saved = reserveRepository.insert(reserve).block();
assertNotNull(saved);
//when
webTestClient.get()
.uri(API_URL + "?page=0&size=5")
.exchange()
.expectStatus().isOk()
.expectBody(new ParameterizedTypeReference<RestResponsePage<ReserveListResponseDto>>() {
})
.value(page -> {
//then
assertThat(page.getTotalElements()).isEqualTo(1L);
assertThat(page.getContent().get(0).getReserveId()).isEqualTo(reserve.getReserveId());
page.getContent().stream().forEach(System.out::println);
});
}
@Test
@WithCustomMockUser(userId = "admin", role = Role.ADMIN)
public void 관리자_취소_성공() throws Exception {
BDDMockito.when(reserveItemServiceClient.updateInventory(ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
.thenReturn(Mono.just(true));
Reserve saved = reserveRepository.insert(reserve).block();
assertNotNull(saved);
webTestClient.put()
.uri(API_URL + "/cancel/{reserveId}", saved.getReserveId())
.bodyValue(ReserveCancelRequestDto.builder().reasonCancelContent("reason for cancellation").build())
.exchange()
.expectStatus().isNoContent();
Reserve updated = reserveRepository.findById(saved.getReserveId()).block();
assertThat(updated.getReserveStatusId()).isEqualTo("cancel");
assertThat(updated.getReasonCancelContent()).isEqualTo("reason for cancellation");
}
@Test
@WithCustomMockUser(userId = "user", role = Role.USER)
public void 사용자_취소_성공() {
//given
BDDMockito.when(reserveItemServiceClient.updateInventory(ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
.thenReturn(Mono.just(true));
Reserve saved = reserveRepository.insert(reserve).block();
assertNotNull(saved);
//when
webTestClient.put()
.uri(API_URL + "/cancel/{reserveId}", saved.getReserveId())
.bodyValue(ReserveCancelRequestDto.builder().reasonCancelContent("reason for cancellation").build())
.exchange()
.expectStatus().isNoContent()
;
Reserve updated = reserveRepository.findById(saved.getReserveId()).block();
assertThat(updated.getReserveStatusId()).isEqualTo("cancel");
assertThat(updated.getReasonCancelContent()).isEqualTo("reason for cancellation");
}
@Test
@WithCustomMockUser(userId = "test", role = Role.USER)
public void 다른사용자_예약_취소_실패() throws Exception {
BDDMockito.when(reserveItemServiceClient.updateInventory(ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
.thenReturn(Mono.just(true));
Reserve saved = reserveRepository.insert(reserve).block();
assertNotNull(saved);
webTestClient.put()
.uri(API_URL + "/cancel/{reserveId}", saved.getReserveId())
.bodyValue(ReserveCancelRequestDto.builder().reasonCancelContent("reason for cancellation").build())
.exchange()
.expectStatus().isBadRequest()
.expectBody(ErrorResponse.class)
.value(response -> {
assertThat(response.getMessage()).isEqualTo("해당 예약은 취소할 수 없습니다.");
assertThat(response.getCode()).isEqualTo(ErrorCode.BUSINESS_CUSTOM_MESSAGE.getCode());
});
}
@Test
@WithCustomMockUser(userId = "user", role = Role.USER)
public void 예약상태_완료_취소_실패() throws Exception {
Reserve done = reserve.updateStatus(ReserveStatus.DONE.getKey());
Reserve saved = reserveRepository.insert(done).block();
assertNotNull(saved);
BDDMockito.when(reserveItemServiceClient.updateInventory(ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
.thenReturn(Mono.just(true));
webTestClient.put()
.uri(API_URL + "/cancel/{reserveId}", saved.getReserveId())
.bodyValue(ReserveCancelRequestDto.builder().reasonCancelContent("reason for cancellation").build())
.exchange()
.expectBody(ErrorResponse.class)
.value(response -> {
assertThat(response.getMessage()).isEqualTo("해당 예약은 이미 실행되어 취소할 수 없습니다.");
assertThat(response.getCode()).isEqualTo(ErrorCode.BUSINESS_CUSTOM_MESSAGE.getCode());
});
;
}
@Test
@WithCustomMockUser(userId = "user", role = Role.USER)
public void 관리자가_아닌_경우_승인_실패() throws Exception {
Reserve saved = reserveRepository.insert(reserve).block();
assertNotNull(saved);
BDDMockito.when(reserveItemServiceClient.findById(ArgumentMatchers.anyLong()))
.thenReturn(Mono.just(ReserveItemResponseDto.builder().reserveItem(reserveItem).build()));
BDDMockito.when(reserveItemServiceClient.updateInventory(ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
.thenReturn(Mono.just(true));
webTestClient.put()
.uri(API_URL + "/approve/{reserveId}", saved.getReserveId())
.exchange()
.expectStatus().isBadRequest()
.expectBody(ErrorResponse.class)
.value(response -> {
assertThat(response.getMessage()).isEqualTo("관리자만 승인할 수 있습니다.");
});
}
@Test
@WithCustomMockUser(userId = "admin", role = Role.ADMIN)
public void 예약승인_성공() throws Exception {
Reserve saved = reserveRepository.insert(reserve).block();
assertNotNull(saved);
BDDMockito.when(reserveItemServiceClient.findById(ArgumentMatchers.anyLong()))
.thenReturn(Mono.just(ReserveItemResponseDto.builder().reserveItem(reserveItem).build()));
BDDMockito.when(reserveItemServiceClient.updateInventory(ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
.thenReturn(Mono.just(true));
webTestClient.put()
.uri(API_URL + "/approve/{reserveId}", saved.getReserveId())
.exchange()
.expectStatus().isNoContent();
Reserve updated = reserveRepository.findById(saved.getReserveId()).block();
assertThat(updated.getReserveStatusId()).isEqualTo("approve");
}
@Test
@WithCustomMockUser(userId = "admin", role = Role.ADMIN)
public void 예약승인_실패_재고부족() throws Exception {
ReserveItem failReserveItem = ReserveItem.builder()
.reserveItemId(1L)
.reserveItemName("test")
.locationId(location.getLocationId())
.location(location)
.categoryId("equipment")
.totalQty(20)
.inventoryQty(10)
.reserveMethodId("internet")
.reserveMeansId("realtime")
.isPeriod(false)
.requestStartDate(LocalDateTime.of(2021, 1, 1, 1, 1))
.requestEndDate(LocalDateTime.of(2021, 12, 31, 23, 59))
.operationStartDate(LocalDateTime.of(2021, 1, 1, 1, 1))
.operationEndDate(LocalDateTime.of(2021, 12, 31, 23, 59))
.build();
Reserve saved = reserveRepository.insert(reserve).block();
assertNotNull(saved);
BDDMockito.when(reserveItemServiceClient.findById(ArgumentMatchers.anyLong()))
.thenReturn(Mono.just(ReserveItemResponseDto.builder().reserveItem(failReserveItem).build()));
BDDMockito.when(reserveItemServiceClient.updateInventory(ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
.thenReturn(Mono.just(false));
webTestClient.put()
.uri(API_URL + "/approve/{reserveId}", saved.getReserveId())
.exchange()
.expectStatus().isBadRequest()
.expectBody(ErrorResponse.class)
.value(response -> {
assertThat(response.getMessage()).isEqualTo("해당 날짜에 예약할 수 있는 재고수량이 없습니다.");
});
}
@Test
@WithCustomMockUser(userId = "admin", role = Role.ADMIN)
public void 관리자_예약정보_수정_성공() throws Exception {
Reserve saved = reserveRepository.insert(reserve).block();
assertNotNull(saved);
BDDMockito.when(reserveItemServiceClient.findById(ArgumentMatchers.anyLong()))
.thenReturn(Mono.just(ReserveItemResponseDto.builder().reserveItem(reserveItem).build()));
BDDMockito.when(reserveItemServiceClient.updateInventory(ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
.thenReturn(Mono.just(true));
ReserveUpdateRequestDto updateRequestDto =
ReserveUpdateRequestDto.builder()
.reserveItemId(saved.getReserveItemId())
.categoryId(saved.getReserveItem().getCategoryId())
.reservePurposeContent("purpose")
.reserveQty(10)
.reserveStartDate(saved.getReserveStartDate())
.reserveEndDate(saved.getReserveEndDate())
.attachmentCode(saved.getAttachmentCode())
.userId(saved.getUserId())
.userContactNo("contact update")
.userEmail(saved.getUserEmail())
.build();
webTestClient.put()
.uri(API_URL + "/{reserveId}", saved.getReserveId())
.bodyValue(updateRequestDto)
.exchange()
.expectStatus().isNoContent()
;
Reserve updated = reserveRepository.findById(saved.getReserveId()).block();
assertThat(updated.getReservePurposeContent()).isEqualTo("purpose");
assertThat(updated.getReserveQty()).isEqualTo(10);
assertThat(updated.getUserContactNo()).isEqualTo("contact update");
}
@Test
@WithCustomMockUser(userId = "test", role = Role.USER)
public void 다른사용자_예약정보_수정_실패() throws Exception {
Reserve saved = reserveRepository.insert(reserve).block();
assertNotNull(saved);
BDDMockito.when(reserveItemServiceClient.findById(ArgumentMatchers.anyLong()))
.thenReturn(Mono.just(ReserveItemResponseDto.builder().reserveItem(reserveItem).build()));
BDDMockito.when(reserveItemServiceClient.updateInventory(ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
.thenReturn(Mono.just(true));
ReserveUpdateRequestDto updateRequestDto =
ReserveUpdateRequestDto.builder()
.reserveItemId(saved.getReserveItemId())
.categoryId(saved.getReserveItem().getCategoryId())
.reservePurposeContent("purpose")
.reserveQty(10)
.reserveStartDate(saved.getReserveStartDate())
.reserveEndDate(saved.getReserveEndDate())
.attachmentCode(saved.getAttachmentCode())
.userId(saved.getUserId())
.userContactNo("contact update")
.userEmail(saved.getUserEmail())
.build();
webTestClient.put()
.uri(API_URL + "/{reserveId}", saved.getReserveId())
.bodyValue(updateRequestDto)
.exchange()
.expectStatus().isBadRequest()
.expectBody(ErrorResponse.class)
.value(response -> {
assertThat(response.getMessage()).isEqualTo("해당 예약은 수정할 수 없습니다.");
});
}
@Test
@WithCustomMockUser(userId = "user", role = Role.USER)
public void 사용자_예약정보_수정_성공() throws Exception {
Reserve saved = reserveRepository.insert(reserve).block();
assertNotNull(saved);
BDDMockito.when(reserveItemServiceClient.findById(ArgumentMatchers.anyLong()))
.thenReturn(Mono.just(ReserveItemResponseDto.builder().reserveItem(reserveItem).build()));
BDDMockito.when(reserveItemServiceClient.updateInventory(ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
.thenReturn(Mono.just(true));
ReserveUpdateRequestDto updateRequestDto =
ReserveUpdateRequestDto.builder()
.reserveItemId(saved.getReserveItemId())
.categoryId(saved.getReserveItem().getCategoryId())
.reservePurposeContent("purpose")
.reserveQty(10)
.reserveStartDate(saved.getReserveStartDate())
.reserveEndDate(saved.getReserveEndDate())
.attachmentCode(saved.getAttachmentCode())
.userId(saved.getUserId())
.userContactNo("contact update")
.userEmail(saved.getUserEmail())
.build();
webTestClient.put()
.uri(API_URL + "/{reserveId}", saved.getReserveId())
.bodyValue(updateRequestDto)
.exchange()
.expectStatus().isNoContent()
;
Reserve updated = reserveRepository.findById(saved.getReserveId()).block();
assertThat(updated.getReservePurposeContent()).isEqualTo("purpose");
assertThat(updated.getReserveQty()).isEqualTo(10);
assertThat(updated.getUserContactNo()).isEqualTo("contact update");
}
@Test
@WithCustomMockUser(userId = "user", role = Role.USER)
public void 사용자_상태승인인예약정보_수정_실패() throws Exception {
Reserve failedReserve = reserve.withReserveStatusId(ReserveStatus.APPROVE.getKey());
Reserve saved = reserveRepository.insert(failedReserve).block();
assertNotNull(saved);
BDDMockito.when(reserveItemServiceClient.findById(ArgumentMatchers.anyLong()))
.thenReturn(Mono.just(ReserveItemResponseDto.builder().reserveItem(reserveItem).build()));
BDDMockito.when(reserveItemServiceClient.updateInventory(ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
.thenReturn(Mono.just(false));
ReserveUpdateRequestDto updateRequestDto =
ReserveUpdateRequestDto.builder()
.reserveItemId(saved.getReserveItemId())
.categoryId(saved.getReserveItem().getCategoryId())
.reservePurposeContent("purpose")
.reserveQty(10)
.reserveStartDate(saved.getReserveStartDate())
.reserveEndDate(saved.getReserveEndDate())
.attachmentCode(saved.getAttachmentCode())
.userId(saved.getUserId())
.userContactNo("contact update")
.userEmail(saved.getUserEmail())
.build();
webTestClient.put()
.uri(API_URL + "/{reserveId}", saved.getReserveId())
.bodyValue(updateRequestDto)
.exchange()
.expectStatus().isBadRequest()
.expectBody(ErrorResponse.class)
.value(response -> {
assertThat(response.getMessage()).isEqualTo("예약 신청 상태인 경우에만 수정 가능합니다.");
});
}
@Test
public void 관리자_예약_성공() throws Exception {
BDDMockito.when(reserveItemServiceClient.findById(ArgumentMatchers.anyLong()))
.thenReturn(Mono.just(ReserveItemResponseDto.builder().reserveItem(reserveItem).build()));
BDDMockito.when(reserveItemServiceClient.updateInventory(ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
.thenReturn(Mono.just(true));
ReserveSaveRequestDto saveRequestDto =
ReserveSaveRequestDto.builder()
.reserveItemId(reserve.getReserveItemId())
.categoryId(reserve.getReserveItem().getCategoryId())
.reservePurposeContent(reserve.getReservePurposeContent())
.reserveQty(reserve.getReserveQty())
.reserveStartDate(reserve.getReserveStartDate())
.reserveEndDate(reserve.getReserveEndDate())
.attachmentCode(reserve.getAttachmentCode())
.userId(reserve.getUserId())
.userContactNo(reserve.getUserContactNo())
.userEmail(reserve.getUserEmail())
.build();
webTestClient.post()
.uri(API_URL)
.bodyValue(saveRequestDto)
.exchange()
.expectStatus().isCreated();
Reserve saved = reserveRepository.findById(reserve.getReserveId()).block();
System.out.println(saved);
}
@Test
public void 예약신청_valid_실패() throws Exception {
ReserveItem validReserveItem = ReserveItem.builder()
.reserveItemId(1L)
.reserveItemName("test")
.locationId(location.getLocationId())
.location(location)
.categoryId("equipment")
.totalQty(100)
.inventoryQty(10)
.operationStartDate(LocalDateTime.of(2021, 10, 1, 1, 1))
.operationEndDate(LocalDateTime.of(2021, 10, 31, 23, 59))
.build();
reserve.setReserveItem(validReserveItem);
ReserveSaveRequestDto saveRequestDto =
ReserveSaveRequestDto.builder()
.reserveItemId(reserve.getReserveItemId())
.categoryId(reserve.getReserveItem().getCategoryId())
.reservePurposeContent(reserve.getReservePurposeContent())
.reserveQty(null)
.reserveStartDate(LocalDateTime.of(2021, 11, 1, 1, 1))
.reserveEndDate(reserve.getReserveEndDate())
.attachmentCode(reserve.getAttachmentCode())
.userId(reserve.getUserId())
.userContactNo(reserve.getUserContactNo())
.userEmail(reserve.getUserEmail())
.build();
webTestClient.post()
.uri(API_URL)
.bodyValue(saveRequestDto)
.exchange()
.expectStatus().isBadRequest()
;
}
}

View File

@@ -1,9 +1,5 @@
package org.egovframe.cloud.reservechecksevice.config;
import io.r2dbc.h2.H2ConnectionConfiguration;
import io.r2dbc.h2.H2ConnectionFactory;
import io.r2dbc.h2.H2ConnectionOption;
import io.r2dbc.spi.ConnectionFactory;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
@@ -13,6 +9,11 @@ import org.springframework.r2dbc.connection.init.CompositeDatabasePopulator;
import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer;
import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator;
import io.r2dbc.h2.H2ConnectionConfiguration;
import io.r2dbc.h2.H2ConnectionFactory;
import io.r2dbc.h2.H2ConnectionOption;
import io.r2dbc.spi.ConnectionFactory;
@Profile("test")
@TestConfiguration
@EnableR2dbcRepositories
@@ -20,7 +21,7 @@ public class R2dbcConfig {
@Bean
public H2ConnectionFactory connectionFactory() {
return new H2ConnectionFactory(H2ConnectionConfiguration.builder()
.tcp("localhost", "~/querydsl")
.inMemory("testdb")
.property(H2ConnectionOption.DB_CLOSE_DELAY, "-1")
.username("sa")
.build());

View File

@@ -1,14 +1,15 @@
package org.egovframe.cloud.reservechecksevice.util;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import java.util.Collections;
import java.util.List;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import java.util.Collections;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
/**
* org.egovframe.cloud.boardservice.util.RestResponsePage

View File

@@ -1,11 +1,11 @@
package org.egovframe.cloud.reservechecksevice.util;
import org.egovframe.cloud.common.domain.Role;
import org.springframework.security.test.context.support.WithSecurityContext;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.egovframe.cloud.common.domain.Role;
import org.springframework.security.test.context.support.WithSecurityContext;
@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class)
public @interface WithCustomMockUser {

View File

@@ -1,14 +1,14 @@
package org.egovframe.cloud.reservechecksevice.util;
import java.util.ArrayList;
import java.util.List;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.test.context.support.WithSecurityContextFactory;
import java.util.ArrayList;
import java.util.List;
public class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory<WithCustomMockUser> {
@Override

View File

@@ -2,20 +2,6 @@ spring:
application:
name: reserve-check-service
datasource:
url: jdbc:h2:mem:testdb;MODE=MYSQL;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false
username: sa
password:
driver-class-name: org.h2.Driver
jpa:
hibernate:
generate-ddl: true
ddl-auto: create-drop
properties:
hibernate:
format_sql: true
default_batch_fetch_size: 1000
show-sql: true
h2:
console:
enabled: true

View File

@@ -1,72 +1,17 @@
-- location Table Create SQL
CREATE TABLE IF NOT EXISTS location
(
location_id BIGINT NOT NULL AUTO_INCREMENT COMMENT '지역 id',
location_name VARCHAR(200) NULL COMMENT '지역 이름',
sort_seq SMALLINT(3) NULL COMMENT '정렬 순서',
use_at TINYINT(1) NULL DEFAULT 1 COMMENT '사용 여부',
created_by VARCHAR(255) NULL COMMENT '생성자',
create_date DATETIME NULL COMMENT '생성일',
last_modified_by VARCHAR(255) NULL COMMENT '수정자',
modified_date DATETIME NULL COMMENT '수정일',
PRIMARY KEY (location_id)
) ;
-- reserve_item Table Create SQL
CREATE TABLE IF NOT EXISTS reserve_item
(
reserve_item_id BIGINT NOT NULL AUTO_INCREMENT COMMENT '예약 물품 id',
reserve_item_name VARCHAR(200) NULL COMMENT '예약 물품 이름',
location_id BIGINT NULL COMMENT '지역 id',
category_id VARCHAR(20) NULL COMMENT '예약유형 - 공통코드 reserve-category',
total_qty BIGINT(18) NULL COMMENT '총 재고/수용인원 수',
inventory_qty BIGINT(18) NULL COMMENT '현재 남은 재고/수용인원 수',
operation_start_date DATETIME NULL COMMENT '운영 시작 일',
operation_end_date DATETIME NULL COMMENT '운영 종료 일',
reserve_method_id VARCHAR(20) NULL COMMENT '예약 방법 - 공통코드 reserve-method',
reserve_means_id VARCHAR(20) NULL COMMENT '예약 구분 (인터넷 예약 시) - 공통코드 reserve-means',
request_start_date DATETIME NULL COMMENT '예약 신청 시작 일시',
request_end_date DATETIME NULL COMMENT '예약 신청 종료 일시',
period_at TINYINT(1) NULL DEFAULT 0 COMMENT '기간 지정 가능 여부 - true: 지정 가능, false: 지정 불가',
period_max_count SMALLINT(3) NULL COMMENT '최대 예약 가능 일 수',
external_url VARCHAR(500) NULL COMMENT '외부링크',
selection_means_id VARCHAR(20) NULL COMMENT '선별 방법 - 공통코드 reserve-selection-means',
free_at TINYINT(1) NULL DEFAULT 1 COMMENT '유/무료 - true: 무료, false: 유료',
usage_cost DECIMAL(18, 0) NULL COMMENT '이용 요금',
use_at TINYINT(1) NULL DEFAULT 1 COMMENT '사용 여부',
purpose_content VARCHAR(4000) NULL COMMENT '용도',
item_addr VARCHAR(500) NULL COMMENT '주소',
target_id VARCHAR(20) NULL COMMENT '이용 대상 - 공통코드 reserve-target',
excluded_content VARCHAR(2000) NULL COMMENT '사용허가 제외대상',
homepage_url VARCHAR(500) NULL COMMENT '홈페이지 url',
contact_no VARCHAR(50) NULL COMMENT '문의처',
manager_dept_name VARCHAR(200) NULL COMMENT '담당자 소속',
manager_name VARCHAR(200) NULL COMMENT '담당자 이름',
manager_contact_no VARCHAR(50) NULL COMMENT '담당자 연락처',
create_date DATETIME NULL COMMENT '생성일',
created_by VARCHAR(255) NULL COMMENT '생성자',
modified_date DATETIME NULL COMMENT '수정일',
last_modified_by VARCHAR(255) NULL COMMENT '수정자',
PRIMARY KEY (reserve_item_id),
CONSTRAINT FK_reserve_item_location_id FOREIGN KEY (location_id)
REFERENCES location (location_id) ON DELETE RESTRICT ON UPDATE RESTRICT
) ;
-- reserve Table Create SQL
CREATE TABLE IF NOT EXISTS reserve
CREATE TABLE IF NOT EXISTS reserve
(
reserve_id BIGINT NOT NULL AUTO_INCREMENT COMMENT '예약 id',
reserve_id VARCHAR(255) NOT NULL COMMENT '예약 id',
reserve_item_id BIGINT NULL COMMENT '예약 물품 id',
location_id BIGINT NULL COMMENT '예약 물품-지역 id',
category_id VARCHAR(255) NULL COMMENT '예약 물품-유형 id',
reserve_qty BIGINT(18) NULL COMMENT '예약 신청인원/수량',
reserve_purpose_content VARCHAR(4000) NULL COMMENT '예약신청 목적',
attachment_code VARCHAR(255) NULL COMMENT '첨부파일 코드',
reserve_start_date DATETIME NULL COMMENT '예약 신청 시작일',
reserve_end_date DATETIME NULL COMMENT '예약 신청 종료일',
reserve_status_id VARCHAR(20) NULL COMMENT '예약상태 - 공통코드(reserve-status)',
reason_cancel_content VARCHAR(4000) NULL COMMENT '예약 취소 사유',
user_id VARCHAR(255) NULL COMMENT '예약자 id',
user_contact_no VARCHAR(50) NULL COMMENT '예약자 연락처',
user_email_addr VARCHAR(500) NULL COMMENT '예약자 이메일',
@@ -74,8 +19,5 @@ CREATE TABLE IF NOT EXISTS reserve
created_by VARCHAR(255) NULL COMMENT '생성자',
modified_date DATETIME NULL COMMENT '수정일',
last_modified_by VARCHAR(255) NULL COMMENT '수정자',
PRIMARY KEY (reserve_id),
CONSTRAINT FK_reserve_reserve_item_id FOREIGN KEY (reserve_item_id)
REFERENCES reserve_item (reserve_item_id) ON DELETE RESTRICT ON UPDATE RESTRICT
PRIMARY KEY (reserve_id)
) ;

View File

@@ -1,8 +1,6 @@
# openjdk8 base image
FROM openjdk:8-jre-alpine
# config server uri: dockder run --e 로 변경 가능
ENV SPRING_CLOUD_CONFIG_URI https://egov-config.paas-ta.org
# jar 파일이 복사되는 위치
ENV APP_HOME=/usr/app/
# 작업 시작 위치

View File

@@ -10,7 +10,7 @@ applications:
- egov-discovery-provided-service # discovery service binding
env:
spring_profiles_active: cf
spring_cloud_config_uri: https://egov-config.paas-ta.org
spring_cloud_config_uri: http://localhost:8888
app_name: egov-reserve-item-service # logstash custom app name
TZ: Asia/Seoul
JAVA_OPTS: -Xss349k

View File

@@ -1,40 +1,40 @@
package org.egovframe.cloud.reserveitemservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
import reactivefeign.spring.config.EnableReactiveFeignClients;
import reactor.blockhound.BlockHound;
import java.security.Security;
@ComponentScan({"org.egovframe.cloud.common", "org.egovframe.cloud.reactive", "org.egovframe.cloud.reserveitemservice"}) // org.egovframe.cloud.common package 포함하기 위해
@EnableDiscoveryClient
@EnableReactiveFeignClients
@SpringBootApplication
public class ReserveItemServiceApplication {
public static void main(String[] args) {
// TLSv1/v1.1 No longer works after upgrade, "No appropriate protocol" error
String property = Security.getProperty("jdk.tls.disabledAlgorithms").replace(", TLSv1", "").replace(", TLSv1.1", "");
Security.setProperty("jdk.tls.disabledAlgorithms", property);
//blocking 코드 감지
BlockHound.builder()
/**
* mysql r2dbc 에서 호출되는 FileInputStream.readBytes() 가 블로킹코드인데 이를 허용해주도록 한다.
* 해당 코드가 어디서 호출되는지 알지 못하는 상태에서 FileInputStream.readBytes() 자체를 허용해주는 것은 좋지 않다.
* 누군가 무분별하게 사용하게 되면 검출해 낼 수 없어 시스템의 위험요소로 남게 된다.
* r2dbc를 사용하기 위해 FileInputStream.readBytes()를 호출하는 부분만 허용하고 나머지는 여전히 검출대상으로 남기도록 한다.
*/
.allowBlockingCallsInside("dev.miku.r2dbc.mysql.client.ReactorNettyClient", "init")
.install();
SpringApplication.run(ReserveItemServiceApplication.class, args);
}
}
package org.egovframe.cloud.reserveitemservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
import reactivefeign.spring.config.EnableReactiveFeignClients;
//import reactor.blockhound.BlockHound;
import java.security.Security;
@ComponentScan({"org.egovframe.cloud.common", "org.egovframe.cloud.reactive", "org.egovframe.cloud.reserveitemservice"}) // org.egovframe.cloud.common package 포함하기 위해
@EnableDiscoveryClient
@EnableReactiveFeignClients
@SpringBootApplication
public class ReserveItemServiceApplication {
public static void main(String[] args) {
// TLSv1/v1.1 No longer works after upgrade, "No appropriate protocol" error
String property = Security.getProperty("jdk.tls.disabledAlgorithms").replace(", TLSv1", "").replace(", TLSv1.1", "");
Security.setProperty("jdk.tls.disabledAlgorithms", property);
//blocking 코드 감지
// BlockHound.builder()
// /**
// * mysql r2dbc 에서 호출되는 FileInputStream.readBytes() 가 블로킹코드인데 이를 허용해주도록 한다.
// * 해당 코드가 어디서 호출되는지 알지 못하는 상태에서 FileInputStream.readBytes() 자체를 허용해주는 것은 좋지 않다.
// * 누군가 무분별하게 사용하게 되면 검출해 낼 수 없어 시스템의 위험요소로 남게 된다.
// * r2dbc를 사용하기 위해 FileInputStream.readBytes()를 호출하는 부분만 허용하고 나머지는 여전히 검출대상으로 남기도록 한다.
// */
// .allowBlockingCallsInside("dev.miku.r2dbc.mysql.client.ReactorNettyClient", "init")
// .install();
SpringApplication.run(ReserveItemServiceApplication.class, args);
}
}

View File

@@ -14,6 +14,7 @@ import org.egovframe.cloud.reserveitemservice.api.reserveItem.dto.ReserveItemRes
import org.egovframe.cloud.reserveitemservice.api.reserveItem.dto.ReserveItemSaveRequestDto;
import org.egovframe.cloud.reserveitemservice.api.reserveItem.dto.ReserveItemUpdateRequestDto;
import org.egovframe.cloud.reserveitemservice.service.reserveItem.ReserveItemService;
import org.springframework.core.env.Environment;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpStatus;
@@ -55,6 +56,21 @@ public class ReserveItemApiController {
private final ReserveItemService reserveItemService;
private final Environment env;
/**
* 서비스 상태 확인
*
* @return
*/
@GetMapping("/actuator/health-info")
public String status() {
return String.format("GET Reserve Item Service on" +
"\n local.server.port :" + env.getProperty("local.server.port")
+ "\n egov.message :" + env.getProperty("egov.message")
);
}
/**
* 목록 조회
*
@@ -97,7 +113,6 @@ public class ReserveItemApiController {
@GetMapping("/api/v1/reserve-items/{reserveItemId}")
@ResponseStatus(HttpStatus.OK)
public Mono<ReserveItemResponseDto> findById(@PathVariable Long reserveItemId) {
System.out.println("findById : " + reserveItemId);
return reserveItemService.findById(reserveItemId);
}
@@ -148,7 +163,7 @@ public class ReserveItemApiController {
@GetMapping("/api/v1/reserve-items/relations/{reserveItemId}")
@ResponseStatus(HttpStatus.OK)
public Mono<ReserveItemRelationResponseDto> findByIdWithRelations(@PathVariable Long reserveItemId) {
return reserveItemService.findByIdWithRelations(reserveItemId).log();
return reserveItemService.findByIdWithRelations(reserveItemId);
}
/**
@@ -161,7 +176,6 @@ public class ReserveItemApiController {
@PutMapping("/api/v1/reserve-items/{reserveItemId}/inventories")
@ResponseStatus(HttpStatus.OK)
public Mono<Boolean> updateInventory(@PathVariable Long reserveItemId, @RequestBody Integer reserveQty) {
System.out.println("update inventories : " + reserveItemId+" : " + reserveQty);
return reserveItemService.updateInventory(reserveItemId, reserveQty);
}

View File

@@ -45,49 +45,18 @@ public class ReserveItemListResponseDto {
private Boolean isPossible; //예약 가능 여부
@Builder
public ReserveItemListResponseDto(ReserveItem reserveItem) {
this.reserveItemId = reserveItem.getReserveItemId();
this.reserveItemName = reserveItem.getReserveItemName();
this.locationId = reserveItem.getLocationId();
this.locationName = reserveItem.getLocation().getLocationName();
this.categoryId = reserveItem.getCategoryId();
this.categoryName = reserveItem.getCategoryName();
this.totalQty = reserveItem.getTotalQty();
this.inventoryQty = reserveItem.getInventoryQty();
this.isUse = reserveItem.getIsUse();
this.createDate = reserveItem.getCreateDate();
this.isPossible = isReservationPossible(reserveItem);
}
/**
* 예약 가능 여부 체크
*
* @param reserveItem
* @return
*/
private boolean isReservationPossible(ReserveItem reserveItem) {
LocalDateTime now = LocalDateTime.now();
if (!reserveItem.getIsUse()) {
return false;
}
if (reserveItem.getInventoryQty() <= 0) {
return false;
}
if (reserveItem.getIsPeriod()) {
if (reserveItem.getRequestStartDate().isBefore(now) && reserveItem.getRequestEndDate().isAfter(now)) {
return true;
}else {
return false;
}
} else {
if (reserveItem.getOperationStartDate().isBefore(now) && reserveItem.getOperationEndDate().isAfter(now)) {
return true;
}else {
return false;
}
}
public ReserveItemListResponseDto(ReserveItem entity) {
this.reserveItemId = entity.getReserveItemId();
this.reserveItemName = entity.getReserveItemName();
this.locationId = entity.getLocationId();
this.locationName = entity.getLocation().getLocationName();
this.categoryId = entity.getCategoryId();
this.categoryName = entity.getCategoryName();
this.totalQty = entity.getTotalQty();
this.inventoryQty = entity.getInventoryQty();
this.isUse = entity.getIsUse();
this.createDate = entity.getCreateDate();
this.isPossible = entity.isReservationPossible();
}
}

View File

@@ -36,38 +36,7 @@ public class ReserveItemMainResponseDto {
this.endDate = entity.getRequestEndDate();
}
}
this.isPossible = isReservationPossible(entity);
}
/**
* 예약 가능 여부 체크
*
* @param entity
* @return
*/
private boolean isReservationPossible(ReserveItem entity) {
LocalDateTime now = LocalDateTime.now();
if (!entity.getIsUse()) {
return false;
}
if (entity.getInventoryQty() <= 0) {
return false;
}
if (entity.getIsPeriod()) {
if (entity.getRequestStartDate().isBefore(now) && entity.getRequestEndDate().isAfter(now)) {
return true;
}else {
return false;
}
} else {
if (entity.getOperationStartDate().isBefore(now) && entity.getOperationEndDate().isAfter(now)) {
return true;
}else {
return false;
}
}
this.isPossible = entity.isReservationPossible();
}
}

View File

@@ -66,6 +66,7 @@ public class ReserveItemRelationResponseDto {
private String managerDept; //담당자 소속
private String managerName; //담당자 이름
private String managerContact; //담당자 연락처
private Boolean isPossible; //예약 가능 여부
@Builder
public ReserveItemRelationResponseDto(ReserveItem entity) {
@@ -103,8 +104,9 @@ public class ReserveItemRelationResponseDto {
this.managerDept = entity.getManagerDept();
this.managerName = entity.getManagerName();
this.managerContact = entity.getManagerContact();
this.isPossible = entity.isReservationPossible();
}
}

View File

@@ -1,5 +1,6 @@
package org.egovframe.cloud.reserveitemservice.api.reserveItem.dto;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
@@ -92,6 +93,43 @@ public class ReserveItemSaveRequestDto {
@Size(max = 50)
private String managerContact; //담당자 연락처
@Builder
public ReserveItemSaveRequestDto(String reserveItemName, Long locationId, String categoryId, Integer totalQty,
Integer inventoryQty, LocalDateTime operationStartDate, LocalDateTime operationEndDate,
String reserveMethodId, String reserveMeansId, LocalDateTime requestStartDate,
LocalDateTime requestEndDate, Boolean isPeriod, Integer periodMaxCount, String externalUrl,
String selectionMeansId, Boolean isPaid, BigDecimal usageCost, Boolean isUse, String purpose,
String address, String targetId, String excluded, String homepage, String contact, String managerDept,
String managerName, String managerContact) {
this.reserveItemName = reserveItemName;
this.locationId = locationId;
this.categoryId = categoryId;
this.totalQty = totalQty;
this.inventoryQty = inventoryQty;
this.operationStartDate = operationStartDate;
this.operationEndDate = operationEndDate;
this.reserveMethodId = reserveMethodId;
this.reserveMeansId = reserveMeansId;
this.requestStartDate = requestStartDate;
this.requestEndDate = requestEndDate;
this.isPeriod = isPeriod;
this.periodMaxCount = periodMaxCount;
this.externalUrl = externalUrl;
this.selectionMeansId = selectionMeansId;
this.isPaid = isPaid;
this.usageCost = usageCost;
this.isUse = isUse;
this.purpose = purpose;
this.address = address;
this.targetId = targetId;
this.excluded = excluded;
this.homepage = homepage;
this.contact = contact;
this.managerDept = managerDept;
this.managerName = managerName;
this.managerContact = managerContact;
}
public ReserveItem toEntity() {
return ReserveItem.builder()
.reserveItemName(this.reserveItemName)

View File

@@ -1,5 +1,6 @@
package org.egovframe.cloud.reserveitemservice.api.reserveItem.dto;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
@@ -61,7 +62,6 @@ public class ReserveItemUpdateRequestDto {
private String externalUrl; //외부링크
@NotBlank
private String selectionMeansId; //선별 방법 - 공통코드 reserve-selection
@NotNull
private Boolean isPaid; // 유/무료 - false: 무료, true: 유료
private BigDecimal usageCost; //이용 요금
private Boolean isUse; //사용여부
@@ -83,6 +83,43 @@ public class ReserveItemUpdateRequestDto {
@Size(max = 50)
private String managerContact; //담당자 연락처
@Builder
public ReserveItemUpdateRequestDto(String reserveItemName, Long locationId, String categoryId,
Integer totalQty, Integer inventoryQty, LocalDateTime operationStartDate, LocalDateTime operationEndDate,
String reserveMethodId, String reserveMeansId, LocalDateTime requestStartDate,
LocalDateTime requestEndDate, Boolean isPeriod, Integer periodMaxCount, String externalUrl,
String selectionMeansId, Boolean isPaid, BigDecimal usageCost, Boolean isUse, String purpose,
String address, String targetId, String excluded, String homepage, String contact, String managerDept,
String managerName, String managerContact) {
this.reserveItemName = reserveItemName;
this.locationId = locationId;
this.categoryId = categoryId;
this.totalQty = totalQty;
this.inventoryQty = inventoryQty;
this.operationStartDate = operationStartDate;
this.operationEndDate = operationEndDate;
this.reserveMethodId = reserveMethodId;
this.reserveMeansId = reserveMeansId;
this.requestStartDate = requestStartDate;
this.requestEndDate = requestEndDate;
this.isPeriod = isPeriod;
this.periodMaxCount = periodMaxCount;
this.externalUrl = externalUrl;
this.selectionMeansId = selectionMeansId;
this.isPaid = isPaid;
this.usageCost = usageCost;
this.isUse = isUse;
this.purpose = purpose;
this.address = address;
this.targetId = targetId;
this.excluded = excluded;
this.homepage = homepage;
this.contact = contact;
this.managerDept = managerDept;
this.managerName = managerName;
this.managerContact = managerContact;
}
public ReserveItem toEntity() {
return ReserveItem.builder()
.reserveItemName(this.reserveItemName)

View File

@@ -278,7 +278,6 @@ public class ReserveItem extends BaseEntity {
* @return
*/
public ReserveItem update(ReserveItemUpdateRequestDto updateRequestDto) {
System.out.println("============ ?? : " + updateRequestDto.toString());
this.reserveItemName = updateRequestDto.getReserveItemName();
this.locationId = updateRequestDto.getLocationId();
this.categoryId = updateRequestDto.getCategoryId();
@@ -332,10 +331,46 @@ public class ReserveItem extends BaseEntity {
return this;
}
/**
* 생성일 세팅
*
* @param createDate
* @return
*/
public ReserveItem setCreateDate(LocalDateTime createDate) {
this.createDate = createDate;
return this;
}
/**
* 예약 가능 여부 체크
*
* @return
*/
public Boolean isReservationPossible() {
if (!this.getIsUse()) {
return false;
}
if (this.getInventoryQty() <= 0) {
return false;
}
LocalDateTime now = LocalDateTime.now();
if (this.getReserveMethodId().equals("internet") && this.getReserveMeansId().equals("realtime")) {
if (this.getRequestStartDate().isBefore(now) && this.getRequestEndDate().isAfter(now)) {
return true;
}else {
return false;
}
} else {
if (this.getOperationStartDate().isBefore(now) && this.getOperationEndDate().isAfter(now)) {
return true;
}else {
return false;
}
}
}
}

View File

@@ -33,9 +33,6 @@ public interface ReserveItemRepositoryCustom {
Flux<ReserveItem> search(ReserveItemRequestDto requestDto, Pageable pageable);
Mono<Long> searchCount(ReserveItemRequestDto requestDto, Pageable pageable);
Flux<ReserveItem> searchForUser(String categoryId, ReserveItemRequestDto requestDto, Pageable pageable);
Mono<Long> searchCountForUser(String categoryId, ReserveItemRequestDto requestDto, Pageable pageable);
Mono<ReserveItem> findWithRelation(Long reserveItemId);
Flux<ReserveItem> findLatestByCategory(Integer count, String categoryId);

View File

@@ -77,42 +77,6 @@ public class ReserveItemRepositoryImpl implements ReserveItemRepositoryCustom{
.count();
}
@Override
public Flux<ReserveItem> searchForUser(String categoryId, ReserveItemRequestDto requestDto, Pageable pageable) {
Criteria where = Criteria.from(whereQuery(requestDto));
if (!"all".equals(categoryId)) {
where = where.and(where("category_id").is(categoryId));
}
Query query = Query.query(where("use_at").isTrue().and(where))
.sort(Sort.by(Sort.Direction.DESC, "create_date"))
.with(pageable);
return entityTemplate.select(ReserveItem.class)
.matching(query)
.all()
.flatMap(this::loadRelations)
.switchIfEmpty(Flux.empty());
}
@Override
public Mono<Long> searchCountForUser(String categoryId, ReserveItemRequestDto requestDto, Pageable pageable) {
Criteria where = Criteria.from(whereQuery(requestDto));
if (!"all".equals(categoryId)) {
where = where.and(where("category_id").is(categoryId));
}
Query query = Query.query(where("use_at").isTrue().and(where))
.sort(Sort.by(Sort.Direction.DESC, "create_date"))
.with(pageable);
return entityTemplate.select(ReserveItem.class)
.matching(query)
.count();
}
/**
* relation 걸린 table 정보도 같이 조회
* 공통코드, 지역
@@ -258,11 +222,11 @@ public class ReserveItemRepositoryImpl implements ReserveItemRepositoryCustom{
}
}
if (requestDto.getLocationId() != null) {
if (requestDto.getLocationId() != null && !"null".equals(requestDto.getLocationId()) && !"undefined".equals(requestDto.getLocationId())) {
whereCriteria.add(where("location_id").in(requestDto.getLocationId()));
}
if (requestDto.getCategoryId() != null ) {
if (requestDto.getCategoryId() != null && !"null".equals(requestDto.getCategoryId()) && !"undefined".equals(requestDto.getCategoryId())) {
whereCriteria.add(where("category_id").in(requestDto.getCategoryId()));
}

View File

@@ -165,7 +165,7 @@ public class LocationService extends ReactiveAbstractService {
.switchIfEmpty(monoResponseStatusEntityNotFoundException(locationId))
.flatMap(locationRepository::delete)
.onErrorResume(DataIntegrityViolationException.class,
throwable -> Mono.error(new BusinessMessageException("참조하는 데이터가 있어 삭제할 수 없습니다.")));
throwable -> Mono.error(new BusinessMessageException(getMessage("err.db.constraint.delete"))));
}
/**

View File

@@ -1,5 +1,6 @@
package org.egovframe.cloud.reserveitemservice.service.reserveItem;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Collections;
@@ -79,7 +80,7 @@ public class ReserveItemService extends ReactiveAbstractService {
* @return
*/
private Mono<ReserveItemListResponseDto> convertReserveItemListResponseDto(ReserveItem reserveItem) {
return Mono.just(ReserveItemListResponseDto.builder().reserveItem(reserveItem).build());
return Mono.just(ReserveItemListResponseDto.builder().entity(reserveItem).build());
}
/**
@@ -108,10 +109,13 @@ public class ReserveItemService extends ReactiveAbstractService {
*/
@Transactional(readOnly = true)
public Mono<Page<ReserveItemListResponseDto>> searchForUser(String categoryId, ReserveItemRequestDto requestDto, Pageable pageable) {
return reserveItemRepository.searchForUser(categoryId, requestDto, pageable)
if (!"all".equals(categoryId)) {
requestDto.setCategoryId(categoryId);
}
return reserveItemRepository.search(requestDto, pageable)
.flatMap(this::convertReserveItemListResponseDto)
.collectList()
.zipWith(reserveItemRepository.searchCountForUser(categoryId, requestDto, pageable))
.zipWith(reserveItemRepository.searchCount(requestDto, pageable))
.flatMap(tuple -> Mono.just(new PageImpl<>(tuple.getT1(), pageable, tuple.getT2())));
}
@@ -200,22 +204,26 @@ public class ReserveItemService extends ReactiveAbstractService {
.switchIfEmpty(monoResponseStatusEntityNotFoundException(reserveItemId))
.flatMap(reserveItem -> {
if (!Category.EDUCATION.isEquals(reserveItem.getCategoryId())) {
return Mono.error(new BusinessMessageException("저장할 수 없습니다."));
//해당 예약은 수정할 수 없습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_not_update")));
}
LocalDateTime now = LocalDateTime.now();
if (!(now.isAfter(reserveItem.getRequestStartDate()) && now.isBefore(reserveItem.getRequestEndDate()))) {
return Mono.error(new BusinessMessageException("예약 가능 일자가 아닙니다."));
//해당 날짜에는 예약할 수 없습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_date")));
}
int qty = reserveItem.getInventoryQty() - reserveQty;
if (qty < 0) {
return Mono.error(new BusinessMessageException("재고가 없습니다."));
//해당 날짜에 예약할 수 있는 재고수량이 없습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_count")));
}
return Mono.just(reserveItem.updateInventoryQty(qty));
})
.flatMap(reserveItemRepository::save)
.delayElement(Duration.ofSeconds(5))
.publishOn(Schedulers.boundedElastic())
.doOnNext(reserveItem -> {
log.info("reserve item inventory updated success");

View File

@@ -2,9 +2,12 @@ package org.egovframe.cloud.reserveitemservice.validator;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.cloud.common.util.MessageUtil;
import org.egovframe.cloud.reserveitemservice.validator.annotation.ReserveItemSaveValid;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.reflect.Field;
@@ -30,6 +33,11 @@ import java.time.LocalDateTime;
@Slf4j
public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItemSaveValid, Object> {
@Resource(
name = "messageUtil"
)
protected MessageUtil messageUtil;
private String message;
@Override
@@ -54,7 +62,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
LocalDateTime operationEndDate = (LocalDateTime) getFieldValue(value, "operationEndDate");
if (operationStartDate.isAfter(operationEndDate)) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("시작일 종료일 보다 니다.")
//시작일, 종료일, {0}이 {1}보다 늦습니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("valid.to_be_slow.format", new Object[]{messageUtil.getMessage("common.start_date"), messageUtil.getMessage("common.end_date")}))
.addPropertyNode("operationStartDate")
.addConstraintViolation();
fieldValid = false;
@@ -66,7 +75,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
// 예약 구분 필수
if (isNull(value, "reserveMeansId")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("인터넷 예약인 경우 예약 구분은 필수입니다.")
//인터넷 예약 구분은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.reserve_means")+ messageUtil.getMessage("valid.required"))
.addPropertyNode("reserveMeansId")
.addConstraintViolation();
fieldValid = false;
@@ -77,24 +87,28 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
// 예약 신청 기간 필수
if (isNull(value, "requestStartDate")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("인터넷 예약인 경우 예약 신청 시작 기간은 필수입니다.")
.addPropertyNode("requestStartDate")
.addConstraintViolation();
// 예약 신청 시작일 값은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.request")+" "+messageUtil.getMessage("common.start_datetime") + messageUtil.getMessage("valid.required"))
.addPropertyNode("requestStartDate")
.addConstraintViolation();
fieldValid = false;
} else if (isNull(value, "requestEndDate")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("인터넷 예약인 경우 예약 신청 종료 기간은 필수입니다.")
.addPropertyNode("requestEndDate")
.addConstraintViolation();
// 예약 신청 종료일 값은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.request")+" "+messageUtil.getMessage("common.end_datetime") + messageUtil.getMessage("valid.required"))
.addPropertyNode("requestEndDate")
.addConstraintViolation();
fieldValid = false;
}else {
LocalDateTime requestStartDate = (LocalDateTime) getFieldValue(value, "requestStartDate");
LocalDateTime requestEndDate = (LocalDateTime) getFieldValue(value, "requestEndDate");
if (requestStartDate.isAfter(requestEndDate)) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("시작일 종료일 보다 니다.")
.addPropertyNode("requestStartDate")
.addConstraintViolation();
//시작일, 종료일, {0}이 {1}보다 늦습니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("valid.to_be_slow.format", new Object[]{messageUtil.getMessage("common.start_date"), messageUtil.getMessage("common.end_date")}))
.addPropertyNode("requestStartDate")
.addConstraintViolation();
fieldValid = false;
}
}
@@ -102,7 +116,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
//기간 지정 필수
if (isNull(value, "isPeriod")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("인터넷 예약인 경우 기간 지정 여부는 필수입니다.")
//기간 지정 가능 여부 값은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.period_possible")+ messageUtil.getMessage("valid.required"))
.addPropertyNode("requestEndDate")
.addConstraintViolation();
fieldValid = false;
@@ -111,7 +126,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
// 기간 지정 가능인 경우 최대 얘약일 수 필수
if (isPeriod && isNull(value, "periodMaxCount")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("기간 지정이 가능인 경우 최대 예약 일수는 필수입니다.")
//최대 예약 가능 일수 값은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.max_period_days")+ messageUtil.getMessage("valid.required"))
.addPropertyNode("periodMaxCount")
.addConstraintViolation();
fieldValid = false;
@@ -121,7 +137,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
//예약 구분이 외부 링크인 경우 외부 링크 url 필수
if (isNull(value, "externalUrl")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("예약 구분이 외부링크인 경우 외부링크 url 값은 필수입니다.")
//외부링크 URL 값은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.external_url")+ messageUtil.getMessage("valid.required"))
.addPropertyNode("externalUrl")
.addConstraintViolation();
fieldValid = false;
@@ -132,7 +149,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
//예약 방법인 '전화'인 경우 contact 필수
if (isNull(value, "contact")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("전화예약인 경우 문의처는 필수입니다.")
//문의처 값은 필수입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.contact")+ messageUtil.getMessage("valid.required"))
.addPropertyNode("contact")
.addConstraintViolation();
fieldValid = false;
@@ -141,7 +159,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
//예약 방법인 '방문'인 경우 주소 필수
if (isNull(value, "address")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("방문예약인 경우 주소는 필수입니다.")
//주소 값은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("common.address")+ messageUtil.getMessage("valid.required"))
.addPropertyNode("address")
.addConstraintViolation();
fieldValid = false;
@@ -152,7 +171,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
Boolean isPaid = Boolean.valueOf(String.valueOf(getFieldValue(value, "isPaid")));
if (isPaid && isNull(value, "usageCost")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("유료인 경우 이용 요금은 필수입니다.")
//이용요금은 필수입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.usage_fee")+ messageUtil.getMessage("valid.required"))
.addPropertyNode("usageCost")
.addConstraintViolation();
fieldValid = false;

View File

@@ -1,144 +1,183 @@
package org.egovframe.cloud.reserveitemservice.api.location;
import static org.junit.jupiter.api.Assertions.*;
import org.egovframe.cloud.reserveitemservice.api.location.dto.LocationSaveRequestDto;
import org.egovframe.cloud.reserveitemservice.api.location.dto.LocationUpdateRequestDto;
import org.egovframe.cloud.reserveitemservice.config.R2dbcConfig;
import org.egovframe.cloud.reserveitemservice.domain.location.Location;
import org.egovframe.cloud.reserveitemservice.domain.location.LocationRepository;
import org.junit.jupiter.api.BeforeEach;
import org.egovframe.cloud.reserveitemservice.domain.reserveItem.ReserveItem;
import org.egovframe.cloud.reserveitemservice.domain.reserveItem.ReserveItemRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.BDDMockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.domain.Pageable;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.reactive.function.BodyInserters;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@EnableConfigurationProperties
@TestPropertySource(properties = {"spring.config.location=classpath:application-test.yml"})
@ActiveProfiles("test")
@Import({R2dbcConfig.class})
class LocationApiControllerTest {
public class LocationApiControllerTest {
@MockBean
private LocationRepository locationRepository;
@Autowired
private LocationRepository locationRepository;
@Autowired
private WebTestClient webTestClient;
@Autowired
private ReserveItemRepository reserveItemRepository;
private final static String API_URL = "/api/v1/locations";
@Autowired
WebTestClient webTestClient;
private Location location = Location.builder()
.locationId(1L)
.locationName("location")
.isUse(true)
.sortSeq(1)
.build();
private static final String API_URL = "/api/v1/locations";
@BeforeEach
public void setup() {
BDDMockito.when(locationRepository.findById(ArgumentMatchers.anyLong()))
.thenReturn(Mono.just(location));
//조회조건 있는 경우
BDDMockito.when(locationRepository.findAllByLocationNameContainingOrderBySortSeq(
ArgumentMatchers.anyString(), ArgumentMatchers.any(Pageable.class)))
.thenReturn(Flux.just(location));
BDDMockito.when(locationRepository.countAllByLocationNameContaining(ArgumentMatchers.anyString()))
.thenReturn(Mono.just(1L));
//조회조건 없는 경우
BDDMockito.when(locationRepository.findAllByOrderBySortSeq(ArgumentMatchers.any(Pageable.class)))
.thenReturn(Flux.just(location));
BDDMockito.when(locationRepository.count()).thenReturn(Mono.just(1L));
@AfterEach
public void tearDown() {
reserveItemRepository.deleteAll().block();
locationRepository.deleteAll().block();
}
BDDMockito.when(locationRepository.save(ArgumentMatchers.any(Location.class)))
.thenReturn(Mono.just(location));
@Test
public void 한건조회_성공() throws Exception {
}
Location location1 = locationRepository.save(Location.builder()
.locationName("location1")
.isUse(true)
.sortSeq(1)
.build()).block();
assertNotNull(location1);
@Test
public void 한건조회_성공() throws Exception {
webTestClient.get()
.uri(API_URL+"/{locationId}", location.getLocationId())
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.locationName").isEqualTo(location.getLocationName());
}
@Test
public void 조회조건있는경우_페이지목록조회_성공() throws Exception {
webTestClient.get()
.uri(API_URL+"?keywordType=locationName&keyword=location&page=0&size=3")
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.totalElements").isEqualTo(1)
.jsonPath("$.content[0].locationName").isEqualTo(location.getLocationName());
}
@Test
public void 조회조건없는경우_페이지목록조회_성공() throws Exception {
webTestClient.get()
.uri(API_URL+"?page=0&size=3")
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.totalElements").isEqualTo(1)
.jsonPath("$.content[0].locationName").isEqualTo(location.getLocationName());
}
@Test
public void 한건저장_성공() throws Exception {
webTestClient.post()
.uri(API_URL)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(LocationSaveRequestDto.builder()
.locationName(location.getLocationName())
.isUse(location.getIsUse())
.sortSeq(location.getSortSeq())
.build()))
.exchange()
.expectStatus().isCreated()
.expectBody().jsonPath("$.locationName").isEqualTo(location.getLocationName());
}
@Test
public void 한건수정_성공() throws Exception {
webTestClient.put()
.uri(API_URL+"/{locationId}", location.getLocationId())
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(LocationUpdateRequestDto.builder()
.locationName("updateLocation")
.isUse(location.getIsUse())
.sortSeq(location.getSortSeq())
.build()))
.exchange()
.expectStatus().isNoContent();
}
@Test
public void 한건삭제_참조데이터존재_삭제실패() throws Exception {
BDDMockito.when(locationRepository.delete(ArgumentMatchers.any(Location.class)))
.thenReturn(Mono.error(new DataIntegrityViolationException("integrity test")));
webTestClient.delete()
.uri(API_URL+"/{locationId}", 1L)
.exchange()
.expectStatus().isBadRequest();
}
webTestClient.get()
.uri(API_URL+"/{locationId}", location1.getLocationId())
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.locationName").isEqualTo(location1.getLocationName());
}
}
@Test
public void 조회조건있는경우_페이지목록조회_성공() throws Exception {
Location location1 = locationRepository.save(Location.builder()
.locationName("location1")
.isUse(true)
.sortSeq(1)
.build()).block();
assertNotNull(location1);
webTestClient.get()
.uri(API_URL+"?keywordType=locationName&keyword=location&page=0&size=3")
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.totalElements").isEqualTo(1)
.jsonPath("$.content[0].locationName").isEqualTo(location1.getLocationName());
}
@Test
public void 조회조건없는경우_페이지목록조회_성공() throws Exception {
Location location1 = locationRepository.save(Location.builder()
.locationName("location1")
.isUse(true)
.sortSeq(1)
.build()).block();
assertNotNull(location1);
webTestClient.get()
.uri(API_URL+"?page=0&size=3")
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.totalElements").isEqualTo(1)
.jsonPath("$.content[0].locationName").isEqualTo(location1.getLocationName());
}
@Test
public void 한건저장_성공() throws Exception {
webTestClient.post()
.uri(API_URL)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(LocationSaveRequestDto.builder()
.locationName("location1")
.isUse(true)
.sortSeq(1)
.build()))
.exchange()
.expectStatus().isCreated()
.expectBody().jsonPath("$.locationName").isEqualTo("location1");
}
@Test
public void 한건수정_성공() throws Exception {
Location location1 = locationRepository.save(Location.builder()
.locationName("location1")
.isUse(true)
.sortSeq(1)
.build()).block();
assertNotNull(location1);
webTestClient.put()
.uri(API_URL+"/{locationId}", location1.getLocationId())
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(LocationUpdateRequestDto.builder()
.locationName("updateLocation")
.isUse(location1.getIsUse())
.sortSeq(location1.getSortSeq())
.build()))
.exchange()
.expectStatus().isNoContent();
Location updatedLocation = locationRepository.findById(location1.getLocationId()).block();
assertNotNull(updatedLocation);
assertEquals(updatedLocation.getLocationName(), "updateLocation");
}
@Test
public void 한건삭제_참조데이터존재_삭제실패() throws Exception {
Location location1 = locationRepository.save(Location.builder()
.locationName("location1")
.isUse(true)
.sortSeq(1)
.build()).block();
assertNotNull(location1);
reserveItemRepository.save(ReserveItem.builder()
.locationId(location1.getLocationId())
.categoryId("test")
.build()).block();
webTestClient.delete()
.uri(API_URL+"/{locationId}", location1.getLocationId())
.exchange()
.expectStatus().isBadRequest();
}
@Test
public void 한건삭제_성공() throws Exception {
Location location1 = locationRepository.save(Location.builder()
.locationName("location1")
.isUse(true)
.sortSeq(1)
.build()).block();
assertNotNull(location1);
webTestClient.delete()
.uri(API_URL+"/{locationId}", location1.getLocationId())
.exchange()
.expectStatus().isNoContent();
}
}

View File

@@ -1,14 +1,30 @@
package org.egovframe.cloud.reserveitemservice.api.reserveItem;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.egovframe.cloud.common.exception.dto.ErrorCode;
import org.egovframe.cloud.common.exception.dto.ErrorResponse;
import org.egovframe.cloud.reserveitemservice.api.reserveItem.dto.ReserveItemMainResponseDto;
import org.egovframe.cloud.reserveitemservice.api.reserveItem.dto.ReserveItemRequestDto;
import org.egovframe.cloud.reserveitemservice.api.reserveItem.dto.ReserveItemResponseDto;
import org.egovframe.cloud.reserveitemservice.api.reserveItem.dto.ReserveItemSaveRequestDto;
import org.egovframe.cloud.reserveitemservice.api.reserveItem.dto.ReserveItemUpdateRequestDto;
import org.egovframe.cloud.reserveitemservice.config.R2dbcConfig;
import org.egovframe.cloud.reserveitemservice.domain.code.Code;
import org.egovframe.cloud.reserveitemservice.domain.location.Location;
import org.egovframe.cloud.reserveitemservice.domain.location.LocationRepository;
import org.egovframe.cloud.reserveitemservice.domain.reserveItem.ReserveItem;
import org.egovframe.cloud.reserveitemservice.domain.reserveItem.ReserveItemRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.BDDMockito;
@@ -17,7 +33,10 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.data.domain.Pageable;
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.reactive.server.WebTestClient;
@@ -29,136 +48,243 @@ import reactor.core.publisher.Mono;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@EnableConfigurationProperties
@TestPropertySource(properties = {"spring.config.location=classpath:application-test.yml"})
@ActiveProfiles(profiles = "test")
@ActiveProfiles("test")
@Import({R2dbcConfig.class})
class ReserveItemApiControllerTest {
@Autowired
private LocationRepository locationRepository;
@MockBean
ReserveItemRepository reserveItemRepository;
@Autowired
private ReserveItemRepository reserveItemRepository;
@Autowired
private R2dbcEntityTemplate entityTemplate;
@Autowired
WebTestClient webTestClient;
private final static String API_URL = "/api/v1/reserve-items";
Code category = null;
Location location = null;
ReserveItem reserveItem = ReserveItem.builder().build();
@AfterEach
public void tearDown() {
entityTemplate.delete(Code.class).all().block();
reserveItemRepository.deleteAll().block();
locationRepository.deleteAll().block();
}
@BeforeEach
public void setUp() {
category = Code.builder().codeName("category").codeId("category").parentCodeId("reserve-category").build();
entityTemplate.insert(Code.class)
.using(category).block();
location = locationRepository.save(Location.builder()
.locationName("location1")
.isUse(true)
.sortSeq(1)
.build()).block();
assertNotNull(location);
reserveItem = ReserveItem.builder()
.categoryId(category.getCodeId())
.locationId(location.getLocationId())
.reserveItemName("test")
.isUse(Boolean.TRUE)
.operationStartDate(LocalDateTime.of(2021, 10, 1, 1, 1))
.operationEndDate(LocalDateTime.of(2021, 10, 31, 23, 59))
.reserveMethodId("internet")
.reserveMeansId("realtime")
.requestStartDate(LocalDateTime.of(2021, 10, 1, 1, 1))
.requestEndDate(LocalDateTime.of(2021, 10, 31, 23, 59))
.totalQty(100)
.inventoryQty(100)
.isPeriod(Boolean.FALSE)
.selectionMeansId("evaluate")
.build();
}
@Test
public void 사용자별_검색_목록_조회_성공() throws Exception {
LocalDateTime startDate = LocalDateTime.of(2021, 1, 28, 1,1);
LocalDateTime endDate = LocalDateTime.of(2021, 12, 6, 1,1);
public void 사용자목록조회_성공() throws Exception {
Location location = Location.builder()
.locationId(1L)
.locationName("location")
.sortSeq(1)
.isUse(true)
.build();
ReserveItem reserveItem = ReserveItem.builder()
.reserveItemId(1L)
.location(location)
.locationId(location.getLocationId())
.reserveItemName("test")
.categoryId("education")
.categoryName("교육")
.totalQty(100)
.inventoryQty(80)
.operationEndDate(endDate)
.operationStartDate(startDate)
.isPeriod(false)
.isUse(true)
.build();
ReserveItem saved = reserveItemRepository.save(reserveItem).block();
assertNotNull(saved);
BDDMockito.when(reserveItemRepository.searchForUser(ArgumentMatchers.anyString(),
ArgumentMatchers.any(ReserveItemRequestDto.class), ArgumentMatchers.any(Pageable.class)))
.thenReturn(Flux.just(reserveItem));
webTestClient.method(HttpMethod.GET)
.uri("/api/v1/"+category.getCodeId()+"/reserve-items"+"?page=0&size=3&isUse=true")
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.totalElements").isEqualTo(1)
.jsonPath("$.content[0].reserveItemName").isEqualTo(reserveItem.getReserveItemName());
}
BDDMockito.when(reserveItemRepository.searchCountForUser(ArgumentMatchers.anyString(),
ArgumentMatchers.any(ReserveItemRequestDto.class), ArgumentMatchers.any(Pageable.class)))
.thenReturn(Mono.just(1L));
@Test
public void 관리자목록조회_성공() throws Exception {
webTestClient.get()
.uri("/api/v1/{categoryId}/reserve-items?keywordType=locationName&keyword=location&page=0&size=3", "education")
.exchange()
.expectStatus().isOk();
ReserveItem saved = reserveItemRepository.save(reserveItem).block();
assertNotNull(saved);
webTestClient.method(HttpMethod.GET)
.uri(API_URL+"?page=0&size=3&isUse=false")
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.totalElements").isEqualTo(1)
.jsonPath("$.content[0].reserveItemName").isEqualTo(reserveItem.getReserveItemName());
}
@Test
public void 한건조회_성공() throws Exception {
ReserveItem saved = reserveItemRepository.save(reserveItem).block();
assertNotNull(saved);
ReserveItemResponseDto responseBody = webTestClient.get()
.uri(API_URL+"/{reserveItemId}", saved.getReserveItemId())
.exchange()
.expectStatus().isOk()
.expectBody(ReserveItemResponseDto.class)
.returnResult().getResponseBody();
assertThat(responseBody.getCategoryId()).isEqualTo(category.getCodeId());
assertThat(responseBody.getReserveItemName()).isEqualTo(saved.getReserveItemName());
}
@Test
public void main_예약물품조회_성공() throws Exception {
BDDMockito.when(reserveItemRepository.findCodeDetail(ArgumentMatchers.anyString()))
.thenReturn(Flux.fromIterable(Arrays.asList(Code.builder().codeId("education").codeName("교육").build(),
Code.builder().codeId("equipment").codeName("장비").build(),
Code.builder().codeId("space").codeName("장소").build())));
public void 사용자_포털_메인_예약목록_조회_성공() throws Exception {
ReserveItem saved = reserveItemRepository.save(reserveItem).block();
assertNotNull(saved);
LocalDateTime startDate = LocalDateTime.of(2021, 1, 28, 1,1);
LocalDateTime endDate = LocalDateTime.of(2021, 12, 6, 1,1);
Location location = Location.builder()
.locationId(1L)
.locationName("location")
.sortSeq(1)
.isUse(true)
.build();
ReserveItem reserveItem1 = ReserveItem.builder()
.reserveItemId(1L)
.location(location)
.locationId(location.getLocationId())
.reserveItemName("test")
.categoryId("education")
.categoryName("교육")
.totalQty(100)
.inventoryQty(80)
.operationEndDate(endDate)
.operationStartDate(startDate)
.reserveMethodId("visit")
.isPeriod(false)
.isUse(true)
.build();
ReserveItem reserveItem2 = ReserveItem.builder()
.reserveItemId(1L)
.location(location)
.locationId(location.getLocationId())
.reserveItemName("test")
.categoryId("education")
.categoryName("장비")
.totalQty(100)
.inventoryQty(80)
.operationEndDate(endDate)
.operationStartDate(startDate)
.reserveMethodId("visit")
.isPeriod(false)
.isUse(true)
.build();
ReserveItem reserveItem3 = ReserveItem.builder()
.reserveItemId(1L)
.location(location)
.locationId(location.getLocationId())
.reserveItemName("test")
.categoryId("education")
.categoryName("공간")
.totalQty(100)
.inventoryQty(80)
.operationEndDate(endDate)
.operationStartDate(startDate)
.reserveMethodId("visit")
.isPeriod(false)
.isUse(true)
.build();
reserveItem1.setCreateDate(LocalDateTime.now());
reserveItem2.setCreateDate(LocalDateTime.now());
reserveItem3.setCreateDate(LocalDateTime.now());
BDDMockito.when(reserveItemRepository.findLatestByCategory(ArgumentMatchers.anyInt(), ArgumentMatchers.anyString()))
.thenReturn(Flux.fromIterable(Arrays.asList(reserveItem1, reserveItem2, reserveItem3)));
webTestClient.get()
.uri("/api/v1/reserve-items/latest/3")
Map<String, Collection<ReserveItemMainResponseDto>> responseBody = webTestClient.get()
.uri(API_URL+"/latest/3")
.exchange()
.expectStatus().isOk();
.expectStatus().isOk()
.expectBody(new ParameterizedTypeReference<Map<String, Collection<ReserveItemMainResponseDto>>>() {
})
.returnResult().getResponseBody();
assertThat(responseBody.keySet().size()).isEqualTo(1);
assertThat(responseBody.keySet().contains(category.getCodeId())).isTrue();
Collection<ReserveItemMainResponseDto> reserveItemMainResponseDtos = responseBody.get(category.getCodeId());
reserveItemMainResponseDtos.stream().forEach(reserveItemMainResponseDto -> {
assertThat(reserveItemMainResponseDto.getReserveItemName().equals(saved.getReserveItemName()));
});
}
@Test
public void 한건_등록_성공() throws Exception {
ReserveItemSaveRequestDto requestDto = ReserveItemSaveRequestDto.builder()
.reserveItemName(reserveItem.getReserveItemName())
.categoryId(reserveItem.getCategoryId())
.locationId(reserveItem.getLocationId())
.inventoryQty(reserveItem.getInventoryQty())
.totalQty(reserveItem.getTotalQty())
.operationStartDate(reserveItem.getOperationStartDate())
.operationEndDate(reserveItem.getOperationEndDate())
.reserveMethodId(reserveItem.getReserveMethodId())
.reserveMeansId(reserveItem.getReserveMeansId())
.isUse(reserveItem.getIsUse())
.requestStartDate(reserveItem.getRequestStartDate())
.requestEndDate(reserveItem.getRequestEndDate())
.isPeriod(reserveItem.getIsPeriod())
.selectionMeansId(reserveItem.getSelectionMeansId())
.build();
ReserveItemResponseDto responseBody = webTestClient.post()
.uri(API_URL)
.bodyValue(requestDto)
.exchange()
.expectStatus().isCreated()
.expectBody(ReserveItemResponseDto.class)
.returnResult().getResponseBody();
System.out.println(responseBody);
assertThat(responseBody.getReserveItemName()).isEqualTo(requestDto.getReserveItemName());
}
@Test
public void 한건_수정_성공() throws Exception {
ReserveItem saved = reserveItemRepository.save(reserveItem).block();
assertNotNull(saved);
ReserveItemUpdateRequestDto requestDto = ReserveItemUpdateRequestDto.builder()
.reserveItemName("update")
.categoryId(reserveItem.getCategoryId())
.locationId(reserveItem.getLocationId())
.inventoryQty(reserveItem.getInventoryQty())
.totalQty(reserveItem.getTotalQty())
.operationStartDate(reserveItem.getOperationStartDate())
.operationEndDate(reserveItem.getOperationEndDate())
.reserveMethodId(reserveItem.getReserveMethodId())
.reserveMeansId(reserveItem.getReserveMeansId())
.isUse(reserveItem.getIsUse())
.requestStartDate(reserveItem.getRequestStartDate())
.requestEndDate(reserveItem.getRequestEndDate())
.isPeriod(reserveItem.getIsPeriod())
.selectionMeansId(reserveItem.getSelectionMeansId())
.build();
webTestClient.put()
.uri(API_URL+"/"+saved.getReserveItemId())
.bodyValue(requestDto)
.exchange()
.expectStatus().isNoContent();
ReserveItem findbyid = reserveItemRepository.findById(saved.getReserveItemId()).block();
assertThat(findbyid.getReserveItemName()).isEqualTo("update");
}
@Test
public void 사용여부_false_수정_성공() throws Exception {
ReserveItem saved = reserveItemRepository.save(reserveItem).block();
assertNotNull(saved);
webTestClient.put()
.uri(API_URL+"/"+saved.getReserveItemId()+"/false")
.exchange()
.expectStatus().isNoContent();
ReserveItem findbyid = reserveItemRepository.findById(saved.getReserveItemId()).block();
assertThat(findbyid.getIsUse()).isEqualTo(Boolean.FALSE);
}
@Test
public void 한건_저장_validation_실패() throws Exception {
ReserveItemSaveRequestDto requestDto = ReserveItemSaveRequestDto.builder()
.reserveItemName(reserveItem.getReserveItemName())
.categoryId(reserveItem.getCategoryId())
.locationId(reserveItem.getLocationId())
.inventoryQty(reserveItem.getInventoryQty())
.totalQty(reserveItem.getTotalQty())
.operationStartDate(reserveItem.getOperationStartDate())
.operationEndDate(reserveItem.getOperationEndDate())
.reserveMethodId(reserveItem.getReserveMethodId())
.reserveMeansId(reserveItem.getReserveMeansId())
.isUse(reserveItem.getIsUse())
.isPeriod(reserveItem.getIsPeriod())
.selectionMeansId(reserveItem.getSelectionMeansId())
.build();
ErrorResponse responseBody = webTestClient.post()
.uri(API_URL)
.bodyValue(requestDto)
.exchange()
.expectStatus().isBadRequest()
.expectBody(ErrorResponse.class)
.returnResult().getResponseBody();
assertThat(responseBody.getCode()).isEqualTo(ErrorCode.INVALID_INPUT_VALUE.getCode());
assertThat(responseBody.getErrors().size()).isEqualTo(1);
responseBody.getErrors().stream().forEach(fieldError -> {
assertThat(fieldError.getField()).isEqualTo("requestStartDate");
System.out.println(fieldError.getMessage());
});
}
}

View File

@@ -21,7 +21,7 @@ public class R2dbcConfig{
@Bean
public H2ConnectionFactory connectionFactory() {
return new H2ConnectionFactory(H2ConnectionConfiguration.builder()
.tcp("localhost", "~/querydsl")
.inMemory("testdb")
.property(H2ConnectionOption.DB_CLOSE_DELAY, "-1")
.username("sa")
.build());

View File

@@ -2,20 +2,6 @@ spring:
application:
name: reserve-item-service
datasource:
url: jdbc:h2:mem:testdb;MODE=MYSQL;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false
username: sa
password:
driver-class-name: org.h2.Driver
jpa:
hibernate:
generate-ddl: true
ddl-auto: create-drop
properties:
hibernate:
format_sql: true
default_batch_fetch_size: 1000
show-sql: true
h2:
console:
enabled: true

View File

@@ -1,14 +1,25 @@
CREATE TABLE IF NOT EXISTS location(
location_id BIGINT AUTO_INCREMENT,
location_name VARCHAR(200),
use_at tinyint(1) default 1 null,
sort_seq smallint(3) null,
create_date DATE null,
modified_date DATE null,
created_by VARCHAR(255) null,
last_modified_by VARCHAR(255) null,
CONSTRAINT PERSON_PK PRIMARY KEY (location_id)
);
CREATE TABLE IF NOT EXISTS `code` (
`code_id` varchar(20) NOT NULL COMMENT '코드 id',
`code_name` varchar(500) NOT NULL COMMENT '코드 명',
`parent_code_id` varchar(20) DEFAULT NULL COMMENT '부모 코드 id',
use_at BOOLEAN NULL DEFAULT TRUE COMMENT '사용 여부',
PRIMARY KEY (`code_id`)
) ;
-- location Table Create SQL
CREATE TABLE IF NOT EXISTS location
(
location_id BIGINT NOT NULL AUTO_INCREMENT COMMENT '지역 id',
location_name VARCHAR(200) NULL COMMENT '지역 이름',
sort_seq SMALLINT(3) NULL COMMENT '정렬 순서',
use_at BOOLEAN NULL DEFAULT TRUE COMMENT '사용 여부',
created_by VARCHAR(255) NULL COMMENT '생성자',
create_date DATETIME NULL COMMENT '생성일',
last_modified_by VARCHAR(255) NULL COMMENT '수정자',
modified_date DATETIME NULL COMMENT '수정일',
PRIMARY KEY (location_id)
) ;
-- reserve_item Table Create SQL
@@ -18,20 +29,21 @@ CREATE TABLE IF NOT EXISTS reserve_item
reserve_item_name VARCHAR(200) NULL COMMENT '예약 물품 이름',
location_id BIGINT NULL COMMENT '지역 id',
category_id VARCHAR(20) NULL COMMENT '예약유형 - 공통코드 reserve-category',
capacity_count MEDIUMINT(5) NULL COMMENT '재고/수용인원 수',
total_qty BIGINT(18) NULL COMMENT '재고/수용인원 수',
inventory_qty BIGINT(18) NULL COMMENT '현재 남은 재고/수용인원 수',
operation_start_date DATETIME NULL COMMENT '운영 시작 일',
operation_end_date DATETIME NULL COMMENT '운영 종료 일',
reserve_method_id VARCHAR(20) NULL COMMENT '예약 방법 - 공통코드 reserve-method',
reserve_means_id VARCHAR(20) NULL COMMENT '예약 구분 (인터넷 예약 시) - 공통코드 reserve-means',
request_start_date DATETIME NULL COMMENT '예약 신청 시작 일시',
request_end_date DATETIME NULL COMMENT '예약 신청 종료 일시',
period_at TINYINT(1) NULL DEFAULT 0 COMMENT '기간 지정 가능 여부 - true: 지정 가능, false: 지정 불가',
period_at BOOLEAN NULL DEFAULT FALSE COMMENT '기간 지정 가능 여부 - true: 지정 가능, false: 지정 불가',
period_max_count SMALLINT(3) NULL COMMENT '최대 예약 가능 일 수',
external_url VARCHAR(500) NULL COMMENT '외부링크',
selection_means_id VARCHAR(20) NULL COMMENT '선별 방법 - 공통코드 reserve-selection-means',
free_at TINYINT(1) NULL DEFAULT 1 COMMENT '유/무료 - true: 무료, false: 유료',
paid_at BOOLEAN NULL DEFAULT FALSE COMMENT '유/무료 - false: 무료, true: 유료',
usage_cost DECIMAL(18, 0) NULL COMMENT '이용 요금',
use_at TINYINT(1) NULL DEFAULT 1 COMMENT '사용 여부',
use_at BOOLEAN NULL DEFAULT TRUE COMMENT '사용 여부',
purpose_content VARCHAR(4000) NULL COMMENT '용도',
item_addr VARCHAR(500) NULL COMMENT '주소',
target_id VARCHAR(20) NULL COMMENT '이용 대상 - 공통코드 reserve-target',
@@ -45,5 +57,10 @@ CREATE TABLE IF NOT EXISTS reserve_item
created_by VARCHAR(255) NULL COMMENT '생성자',
modified_date DATETIME NULL COMMENT '수정일',
last_modified_by VARCHAR(255) NULL COMMENT '수정자',
PRIMARY KEY (reserve_item_id)
);
PRIMARY KEY (reserve_item_id),
CONSTRAINT FK_reserve_item_location_id FOREIGN KEY (location_id)
REFERENCES location (location_id) ON DELETE RESTRICT ON UPDATE RESTRICT
) ;

View File

@@ -1,8 +1,6 @@
# openjdk8 base image
FROM openjdk:8-jre-alpine
# config server uri: dockder run --e 로 변경 가능
ENV SPRING_CLOUD_CONFIG_URI https://egov-config.paas-ta.org
# jar 파일이 복사되는 위치
ENV APP_HOME=/usr/app/
# 작업 시작 위치

View File

@@ -10,7 +10,7 @@ applications:
- egov-discovery-provided-service # discovery service binding
env:
spring_profiles_active: cf
spring_cloud_config_uri: https://egov-config.paas-ta.org
spring_cloud_config_uri: http://localhost:8888
app_name: egov-reserve-request-service # logstash custom app name
TZ: Asia/Seoul
JAVA_OPTS: -Xss349k

View File

@@ -1,33 +1,33 @@
package org.egovframe.cloud.reserverequestservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;
import reactor.blockhound.BlockHound;
import java.security.Security;
@ComponentScan({"org.egovframe.cloud.common", "org.egovframe.cloud.reactive", "org.egovframe.cloud.reserverequestservice"}) // org.egovframe.cloud.common package 포함하기 위해
@EnableDiscoveryClient
@SpringBootApplication
public class ReserveRequestServiceApplication {
public static void main(String[] args) {
// TLSv1/v1.1 No longer works after upgrade, "No appropriate protocol" error
String property = Security.getProperty("jdk.tls.disabledAlgorithms").replace(", TLSv1", "").replace(", TLSv1.1", "");
Security.setProperty("jdk.tls.disabledAlgorithms", property);
//blocking 코드 감지
BlockHound.builder()
//mysql r2dbc 에서 호출되는 FileInputStream.readBytes() 가 블로킹코드인데 이를 허용해주도록 한다.
//해당 코드가 어디서 호출되는지 알지 못하는 상태에서 FileInputStream.readBytes() 자체를 허용해주는 것은 좋지 않다.
// 누군가 무분별하게 사용하게 되면 검출해 낼 수ㅂ 없어 시스템의 위험요소로 남게 된다.
// r2dbc를 사용하기 위해 해당 호출부분만 허용하고 나머지는 여전히 검출대상으로 남기도록 한다.
.allowBlockingCallsInside("dev.miku.r2dbc.mysql.client.ReactorNettyClient", "init")
.install();
SpringApplication.run(ReserveRequestServiceApplication.class, args);
}
}
package org.egovframe.cloud.reserverequestservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;
//import reactor.blockhound.BlockHound;
import java.security.Security;
@ComponentScan({"org.egovframe.cloud.common", "org.egovframe.cloud.reactive", "org.egovframe.cloud.reserverequestservice"}) // org.egovframe.cloud.common package 포함하기 위해
@EnableDiscoveryClient
@SpringBootApplication
public class ReserveRequestServiceApplication {
public static void main(String[] args) {
// TLSv1/v1.1 No longer works after upgrade, "No appropriate protocol" error
String property = Security.getProperty("jdk.tls.disabledAlgorithms").replace(", TLSv1", "").replace(", TLSv1.1", "");
Security.setProperty("jdk.tls.disabledAlgorithms", property);
//blocking 코드 감지
// BlockHound.builder()
// //mysql r2dbc 에서 호출되는 FileInputStream.readBytes() 가 블로킹코드인데 이를 허용해주도록 한다.
// //해당 코드가 어디서 호출되는지 알지 못하는 상태에서 FileInputStream.readBytes() 자체를 허용해주는 것은 좋지 않다.
// // 누군가 무분별하게 사용하게 되면 검출해 낼 수ㅂ 없어 시스템의 위험요소로 남게 된다.
// // r2dbc를 사용하기 위해 해당 호출부분만 허용하고 나머지는 여전히 검출대상으로 남기도록 한다.
// .allowBlockingCallsInside("dev.miku.r2dbc.mysql.client.ReactorNettyClient", "init")
// .install();
SpringApplication.run(ReserveRequestServiceApplication.class, args);
}
}

View File

@@ -10,13 +10,17 @@ import org.egovframe.cloud.reserverequestservice.service.ReserveService;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.MessageListener;
import org.springframework.amqp.rabbit.listener.MessageListenerContainer;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxSink;
import reactor.core.publisher.Mono;
import java.time.Duration;
import java.time.LocalDateTime;
/**
* org.egovframe.cloud.reserverequestservice.api.ReserveApiController
@@ -44,13 +48,28 @@ public class ReserveApiController {
private final MessageListenerContainerFactory messageListenerContainerFactory;
private final AmqpAdmin amqpAdmin;
private final Environment env;
/**
* 서비스 상태 확인
*
* @return
*/
@GetMapping("/actuator/health-info")
public String status() {
return String.format("GET Reserve Request Service on" +
"\n local.server.port :" + env.getProperty("local.server.port")
+ "\n egov.message :" + env.getProperty("egov.message")
);
}
/**
* 예약 신청 - 심사
*
* @param saveRequestDtoMono
* @return
*/
@PostMapping("/api/v1/requests/audit")
@PostMapping("/api/v1/requests/evaluates")
@ResponseStatus(HttpStatus.CREATED)
public Mono<ReserveResponseDto> create(@RequestBody Mono<ReserveSaveRequestDto> saveRequestDtoMono) {
return saveRequestDtoMono.flatMap(reserveService::create);
@@ -79,10 +98,12 @@ public class ReserveApiController {
* @param reserveId
* @return
*/
@CrossOrigin()
@GetMapping(value = "/api/v1/requests/direct/{reserveId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<?> receiveReservationResult(@PathVariable String reserveId) {
public Flux<String> receiveReservationResult(@PathVariable String reserveId) {
MessageListenerContainer mlc = messageListenerContainerFactory.createMessageListenerContainer(reserveId);
Flux<String> f = Flux.create(emitter -> {
mlc.setupMessageListener((MessageListener) m -> {
String qname = m.getMessageProperties().getConsumerQueue();
log.info("message received, queue={}", qname);
@@ -118,7 +139,9 @@ public class ReserveApiController {
.map(v -> {
log.info("sending keepalive message...");
return "no news is good news";
}).mergeWith(f);
})
.mergeWith(f)
.delayElements(Duration.ofSeconds(5));
}
}

View File

@@ -23,6 +23,6 @@ import reactor.core.publisher.Mono;
*/
public interface ReserveRepositoryCustom {
Mono<Reserve> insert(Reserve reserve);
Flux<Reserve> findAllByReserveDateWithoutSelf(String reserveId, Long reserveItemId, LocalDateTime startDate, LocalDateTime endDate);
Mono<Long> findAllByReserveDateWithoutSelfCount(String reserveId, Long reserveItemId, LocalDateTime startDate, LocalDateTime endDate);
Flux<Reserve> findAllByReserveDate(Long reserveItemId, LocalDateTime startDate, LocalDateTime endDate);
Mono<Long> findAllByReserveDateCount(Long reserveItemId, LocalDateTime startDate, LocalDateTime endDate);
}

View File

@@ -54,12 +54,11 @@ public class ReserveRepositoryImpl implements ReserveRepositoryCustom {
* @return
*/
@Override
public Flux<Reserve> findAllByReserveDateWithoutSelf(String reserveId, Long reserveItemId, LocalDateTime startDate, LocalDateTime endDate) {
public Flux<Reserve> findAllByReserveDate(Long reserveItemId, LocalDateTime startDate, LocalDateTime endDate) {
return entityTemplate.select(Reserve.class)
.matching(Query.query(where("reserve_item_id").is(reserveItemId)
.and ("reserve_start_date").lessThanOrEquals(endDate)
.and("reserve_end_date").greaterThanOrEquals(startDate)
.and("reserve_id").not(reserveId)
))
.all();
}
@@ -74,12 +73,11 @@ public class ReserveRepositoryImpl implements ReserveRepositoryCustom {
* @return
*/
@Override
public Mono<Long> findAllByReserveDateWithoutSelfCount(String reserveId, Long reserveItemId, LocalDateTime startDate, LocalDateTime endDate) {
public Mono<Long> findAllByReserveDateCount(Long reserveItemId, LocalDateTime startDate, LocalDateTime endDate) {
return entityTemplate.select(Reserve.class)
.matching(Query.query(where("reserve_item_id").is(reserveItemId)
.and ("reserve_start_date").lessThanOrEquals(endDate)
.and("reserve_end_date").greaterThanOrEquals(startDate)
.and("reserve_id").not(reserveId)
))
.count();
}

View File

@@ -3,6 +3,7 @@ package org.egovframe.cloud.reserverequestservice.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.cloud.common.config.GlobalConstant;
import org.egovframe.cloud.common.dto.AttachmentEntityMessage;
import org.egovframe.cloud.common.exception.BusinessMessageException;
import org.egovframe.cloud.reactive.service.ReactiveAbstractService;
import org.egovframe.cloud.reserverequestservice.api.dto.ReserveResponseDto;
@@ -99,6 +100,12 @@ public class ReserveService extends ReactiveAbstractService {
return Mono.just(tuple.getT1());
})
.flatMap(reserveRepository::insert)
.doOnNext(reserve -> sendAttachmentEntityInfo(streamBridge,
AttachmentEntityMessage.builder()
.attachmentCode(reserve.getAttachmentCode())
.entityName(reserve.getClass().getName())
.entityId(reserve.getReserveId())
.build()))
.flatMap(this::convertReserveResponseDto);
}
@@ -164,7 +171,8 @@ public class ReserveService extends ReactiveAbstractService {
}else if (Category.SPACE.isEquals(saveRequestDto.getCategoryId())) {
return checkSpace(saveRequestDto);
}
return Mono.error(new BusinessMessageException("저장 할 수 없습니다."));
//해당 날짜에는 예약할 수 없습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_date")));
}
/**
@@ -180,17 +188,23 @@ public class ReserveService extends ReactiveAbstractService {
saveRequestDto.getRequestEndDate() : saveRequestDto.getOperationEndDate();
if (saveRequestDto.getReserveStartDate().isBefore(startDate)) {
return Mono.error(new BusinessMessageException("시작일 운영/예약 시작일 이전입니다."));
//{0}이 {1} 보다 빠릅니다. 시작일, 운영/예약 시작일
return Mono.error(new BusinessMessageException(getMessage("valid.to_be_fast.format", new Object[]{getMessage("common.start_date"),
getMessage("reserve_item.operation")+getMessage("reserve")+" "+getMessage("common.start_date")})));
}
if (saveRequestDto.getReserveEndDate().isAfter(endDate)) {
return Mono.error(new BusinessMessageException("종료일 운영/예약 종료일 이후입니다."));
//{0}이 {1} 보다 늦습니다. 종료일, 운영/예약 종료일
return Mono.error(new BusinessMessageException(getMessage("valid.to_be_slow.format", new Object[]{getMessage("common.end_date"),
getMessage("reserve_item.operation")+getMessage("reserve")+" "+getMessage("common.end_date")})));
}
if (saveRequestDto.getIsPeriod()) {
long between = ChronoUnit.DAYS.between(saveRequestDto.getReserveStartDate(),
saveRequestDto.getReserveEndDate());
if (saveRequestDto.getPeriodMaxCount() < between) {
return Mono.error(new BusinessMessageException("최대 예약 가능 일수보다 예약기간이 깁니다. (최대 예약 가능일 수 : "+saveRequestDto.getPeriodMaxCount()+")"));
//최대 예약 가능 일수보다 예약기간이 깁니다. (최대 예약 가능일 수 : {0})
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_period", new Object[]{saveRequestDto.getPeriodMaxCount()})));
}
}
return Mono.just(saveRequestDto);
@@ -204,14 +218,14 @@ public class ReserveService extends ReactiveAbstractService {
*/
private Mono<ReserveSaveRequestDto> checkSpace(ReserveSaveRequestDto saveRequestDto) {
return this.checkReserveDate(saveRequestDto)
.flatMap(result -> reserveRepository.findAllByReserveDateWithoutSelfCount(
result.getReserveId(),
.flatMap(result -> reserveRepository.findAllByReserveDateCount(
result.getReserveItemId(),
result.getReserveStartDate(),
result.getReserveEndDate())
.flatMap(count -> {
if (count > 0) {
return Mono.error(new BusinessMessageException("해당 날짜에는 예약할 수 없습니다."));
//해당 날짜에는 예약할 수 없습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_date")));
}
return Mono.just(result);
})
@@ -226,8 +240,7 @@ public class ReserveService extends ReactiveAbstractService {
*/
private Mono<ReserveSaveRequestDto> checkEquipment(ReserveSaveRequestDto saveRequestDto) {
return this.checkReserveDate(saveRequestDto)
.flatMap(result -> this.getMaxByReserveDateWithoutSelf(
result.getReserveId(),
.flatMap(result -> this.getMaxByReserveDate(
result.getReserveItemId(),
result.getReserveStartDate(),
result.getReserveEndDate())
@@ -239,7 +252,8 @@ public class ReserveService extends ReactiveAbstractService {
})
.flatMap(isValid -> {
if (!isValid) {
return Mono.error(new BusinessMessageException("해당 날짜에 예약할 수 있는 재고수량이 없습니다."));
//해당 날짜에 예약할 수 있는 재고수량이 없습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_count")));
}
return Mono.just(saveRequestDto);
})
@@ -255,8 +269,8 @@ public class ReserveService extends ReactiveAbstractService {
* @param endDate
* @return
*/
private Mono<Integer> getMaxByReserveDateWithoutSelf(String reserveId, Long reserveItemId, LocalDateTime startDate, LocalDateTime endDate) {
Flux<Reserve> reserveFlux = reserveRepository.findAllByReserveDateWithoutSelf(reserveId, reserveItemId, startDate, endDate)
private Mono<Integer> getMaxByReserveDate( Long reserveItemId, LocalDateTime startDate, LocalDateTime endDate) {
Flux<Reserve> reserveFlux = reserveRepository.findAllByReserveDate(reserveItemId, startDate, endDate)
.switchIfEmpty(Flux.empty());
if (reserveFlux.equals(Flux.empty())) {

View File

@@ -0,0 +1,85 @@
package org.egovframe.cloud.reserverequestservice.api;
import static org.assertj.core.api.Assertions.*;
import java.time.LocalDateTime;
import org.egovframe.cloud.common.domain.Role;
import org.egovframe.cloud.reserverequestservice.api.dto.ReserveResponseDto;
import org.egovframe.cloud.reserverequestservice.api.dto.ReserveSaveRequestDto;
import org.egovframe.cloud.reserverequestservice.config.WithCustomMockUser;
import org.egovframe.cloud.reserverequestservice.domain.Reserve;
import org.egovframe.cloud.reserverequestservice.domain.ReserveRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.reactive.server.WebTestClient;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@EnableConfigurationProperties
@TestPropertySource(properties = {"spring.config.location=classpath:application-test.yml"})
@ActiveProfiles(profiles = "test")
class ReserveApiControllerTest {
@Autowired
private ReserveRepository reserveRepository;
@Autowired
private WebTestClient webTestClient;
private Reserve reserve;
@BeforeEach
public void setup() {
reserve = Reserve.builder()
.reserveId("1")
.reserveQty(50)
.reservePurposeContent("test")
.reserveStatusId("request")
.reserveStartDate(LocalDateTime.of(2021, 9, 9, 1, 1))
.reserveEndDate(LocalDateTime.of(2021, 9, 20, 1, 1))
.build();
}
@AfterEach
public void tearDown() {
reserveRepository.deleteAll().block();
}
@Test
@WithCustomMockUser(userId = "user", role = Role.USER)
public void 사용자_예약_성공() throws Exception {
ReserveSaveRequestDto saveRequestDto =
ReserveSaveRequestDto.builder()
.reserveItemId(reserve.getReserveItemId())
.reservePurposeContent(reserve.getReservePurposeContent())
.reserveQty(reserve.getReserveQty())
.reserveStartDate(reserve.getReserveStartDate())
.reserveEndDate(reserve.getReserveEndDate())
.attachmentCode(reserve.getAttachmentCode())
.userId(reserve.getUserId())
.userContactNo(reserve.getUserContactNo())
.userEmail(reserve.getUserEmail())
.build();
ReserveResponseDto responseBody = webTestClient.post()
.uri("/api/v1/requests/evaluates")
.bodyValue(saveRequestDto)
.exchange()
.expectStatus().isCreated()
.expectBody(ReserveResponseDto.class)
.returnResult().getResponseBody();
assertThat(responseBody.getReserveQty()).isEqualTo(reserve.getReserveQty());
assertThat(responseBody.getReservePurposeContent()).isEqualTo(reserve.getReservePurposeContent());
}
}

View File

@@ -0,0 +1,40 @@
package org.egovframe.cloud.reserverequestservice.config;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
import org.springframework.r2dbc.connection.init.CompositeDatabasePopulator;
import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer;
import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator;
import io.r2dbc.h2.H2ConnectionConfiguration;
import io.r2dbc.h2.H2ConnectionFactory;
import io.r2dbc.h2.H2ConnectionOption;
import io.r2dbc.spi.ConnectionFactory;
@Profile("test")
@TestConfiguration
@EnableR2dbcRepositories
public class R2dbcConfig {
@Bean
public H2ConnectionFactory connectionFactory() {
return new H2ConnectionFactory(H2ConnectionConfiguration.builder()
.inMemory("testdb")
.property(H2ConnectionOption.DB_CLOSE_DELAY, "-1")
.username("sa")
.build());
}
@Bean
public ConnectionFactoryInitializer initializer(ConnectionFactory connectionFactory) {
ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer();
initializer.setConnectionFactory(connectionFactory);
CompositeDatabasePopulator populator = new CompositeDatabasePopulator();
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("schema-h2.sql")));
initializer.setDatabasePopulator(populator);
return initializer;
}
}

View File

@@ -0,0 +1,16 @@
package org.egovframe.cloud.reserverequestservice.config;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.egovframe.cloud.common.domain.Role;
import org.springframework.security.test.context.support.WithSecurityContext;
@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class)
public @interface WithCustomMockUser {
String userId() default "user";
Role role() default Role.ADMIN;
}

View File

@@ -0,0 +1,25 @@
package org.egovframe.cloud.reserverequestservice.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.test.context.support.WithSecurityContextFactory;
public class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory<WithCustomMockUser> {
@Override
public SecurityContext createSecurityContext(WithCustomMockUser mockUser) {
SecurityContext context = SecurityContextHolder.createEmptyContext();
List<SimpleGrantedAuthority> roleList = new ArrayList<>();
roleList.add(new SimpleGrantedAuthority(mockUser.role().getKey()));
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(mockUser.userId(), null, roleList);
context.setAuthentication(authenticationToken);
return context;
}
}

View File

@@ -1,21 +1,7 @@
spring:
application:
name: reserve-request-service
name: reserve-check-service
datasource:
url: jdbc:h2:mem:testdb;MODE=MYSQL;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false
username: sa
password:
driver-class-name: org.h2.Driver
jpa:
hibernate:
generate-ddl: true
ddl-auto: create-drop
properties:
hibernate:
format_sql: true
default_batch_fetch_size: 1000
show-sql: true
h2:
console:
enabled: true

View File

@@ -0,0 +1,5 @@
spring:
cloud:
config:
uri: http://localhost:8888
name: reserve-request-service

View File

@@ -0,0 +1,23 @@
-- reserve Table Create SQL
CREATE TABLE IF NOT EXISTS reserve
(
reserve_id VARCHAR(255) NOT NULL COMMENT '예약 id',
reserve_item_id BIGINT NULL COMMENT '예약 물품 id',
location_id BIGINT NULL COMMENT '예약 물품-지역 id',
category_id VARCHAR(255) NULL COMMENT '예약 물품-유형 id',
reserve_qty BIGINT(18) NULL COMMENT '예약 신청인원/수량',
reserve_purpose_content VARCHAR(4000) NULL COMMENT '예약신청 목적',
attachment_code VARCHAR(255) NULL COMMENT '첨부파일 코드',
reserve_start_date DATETIME NULL COMMENT '예약 신청 시작일',
reserve_end_date DATETIME NULL COMMENT '예약 신청 종료일',
reserve_status_id VARCHAR(20) NULL COMMENT '예약상태 - 공통코드(reserve-status)',
reason_cancel_content VARCHAR(4000) NULL COMMENT '예약 취소 사유',
user_id VARCHAR(255) NULL COMMENT '예약자 id',
user_contact_no VARCHAR(50) NULL COMMENT '예약자 연락처',
user_email_addr VARCHAR(500) NULL COMMENT '예약자 이메일',
create_date DATETIME NULL COMMENT '생성일',
created_by VARCHAR(255) NULL COMMENT '생성자',
modified_date DATETIME NULL COMMENT '수정일',
last_modified_by VARCHAR(255) NULL COMMENT '수정자',
PRIMARY KEY (reserve_id)
) ;

View File

@@ -1,9 +1,8 @@
# openjdk8 base image
FROM openjdk:8-jre-alpine
# config server uri: dockder run --e 로 변경 가능
#ENV SPRING_CLOUD_CONFIG_URI https://egov-config.paas-ta.org
RUN mkdir -p /usr/app/msa-attach-volume
# directory 생성
RUN mkdir -p /usr/app/msa-attach-volume/messages
# jar 파일이 복사되는 위치
ENV APP_HOME=/usr/app/
# 작업 시작 위치
@@ -12,5 +11,5 @@ WORKDIR $APP_HOME
COPY build/libs/*.jar app.jar
# cf docker push, random port 사용할 수 없다
#EXPOSE 80
# 실행 (application-cf.yml 프로필이 기본값)
CMD ["java", "-Dspring.profiles.active=${profile:cf}", "-jar", "app.jar"]
# 실행
CMD ["java", "-Dspring.profiles.active=${profile:default}", "-jar", "app.jar"]

View File

@@ -10,7 +10,7 @@ applications:
- egov-discovery-provided-service # discovery service binding
env:
spring_profiles_active: cf
spring_cloud_config_uri: https://egov-config.paas-ta.org
spring_cloud_config_uri: http://localhost:8888
app_name: egov-user-service # logstash custom app name
TZ: Asia/Seoul
JAVA_OPTS: -Xss349k

View File

@@ -1,10 +1,7 @@
package org.egovframe.cloud.userservice.api.role;
import java.util.List;
import java.util.stream.Collectors;
import javax.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.cloud.common.dto.RequestDto;
import org.egovframe.cloud.userservice.api.role.dto.AuthorizationListResponseDto;
import org.egovframe.cloud.userservice.api.role.dto.AuthorizationResponseDto;
@@ -18,17 +15,11 @@ import org.springframework.data.web.PageableDefault;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import javax.validation.Valid;
import java.util.List;
import java.util.stream.Collectors;
/**
* org.egovframe.cloud.userservice.api.role.AuthorizationApiController

View File

@@ -1,27 +1,10 @@
package org.egovframe.cloud.userservice.api.user;
import java.io.IOException;
import java.security.GeneralSecurityException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.egovframe.cloud.common.dto.RequestDto;
import org.egovframe.cloud.common.exception.BusinessMessageException;
import org.egovframe.cloud.common.util.MessageUtil;
import org.egovframe.cloud.userservice.api.user.dto.UserEmailRequestDto;
import org.egovframe.cloud.userservice.api.user.dto.UserFindPasswordSaveRequestDto;
import org.egovframe.cloud.userservice.api.user.dto.UserFindPasswordUpdateRequestDto;
import org.egovframe.cloud.userservice.api.user.dto.UserJoinRequestDto;
import org.egovframe.cloud.userservice.api.user.dto.UserListResponseDto;
import org.egovframe.cloud.userservice.api.user.dto.UserPasswordMatchRequestDto;
import org.egovframe.cloud.userservice.api.user.dto.UserPasswordUpdateRequestDto;
import org.egovframe.cloud.userservice.api.user.dto.UserResponseDto;
import org.egovframe.cloud.userservice.api.user.dto.UserSaveRequestDto;
import org.egovframe.cloud.userservice.api.user.dto.UserUpdateInfoRequestDto;
import org.egovframe.cloud.userservice.api.user.dto.UserUpdateRequestDto;
import org.egovframe.cloud.userservice.api.user.dto.UserVerifyRequestDto;
import org.egovframe.cloud.userservice.api.user.dto.*;
import org.egovframe.cloud.userservice.config.TokenProvider;
import org.egovframe.cloud.userservice.service.user.UserService;
import org.springframework.core.env.Environment;
@@ -29,15 +12,13 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.security.GeneralSecurityException;
/**
* org.egovframe.cloud.userservice.api.user.UserApiController
@@ -149,6 +130,17 @@ public class UserApiController {
tokenProvider.refreshToken(refreshToken, response);
}
/**
* 사용자 회원 가입
*
* @param requestDto 사용자 가입 요청 DTO
* @return Boolean 성공 여부
*/
@PostMapping("/api/v1/users/social")
public SocialUserResponseDto social(@RequestBody @Valid SocialUserRequestDto requestDto) {
return userService.getSocialUserInfo(requestDto.getProvider(), requestDto.getToken());
}
/**
* 이메일 중복 확인
*

View File

@@ -0,0 +1,36 @@
package org.egovframe.cloud.userservice.api.user.dto;
import lombok.Getter;
import lombok.NoArgsConstructor;
/**
* org.egovframe.cloud.userservice.api.user.dto.SocialUserRequestDto
*
* 소셜 사용자 요청 DTO 클래스
*
* @author 표준프레임워크센터 jooho
* @version 1.0
* @since 2021/10/22
*
* <pre>
* << 개정이력(Modification Information) >>
*
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2021/10/22 jooho 최초 생성
* </pre>
*/
@Getter
@NoArgsConstructor
public class SocialUserRequestDto {
/**
* 공급자
*/
private String provider;
/**
* 토큰
*/
private String token;
}

View File

@@ -0,0 +1,58 @@
package org.egovframe.cloud.userservice.api.user.dto;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
/**
* org.egovframe.cloud.userservice.api.user.dto.SocialUserResponseDto
* <p>
* 소셜 사용자 응답 DTO 클래스
*
* @author 표준프레임워크센터 jooho
* @version 1.0
* @since 2021/10/22
*
* <pre>
* << 개정이력(Modification Information) >>
*
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2021/10/22 jooho 최초 생성
* </pre>
*/
@Getter
@NoArgsConstructor
public class SocialUserResponseDto {
/**
* 아이디
*/
private String id;
/**
* 이메일
*/
private String email;
/**
* 이름
*/
private String name;
/**
* 소셜 사용자 DTO 클래스 생성자
* 빌더 패턴으로 객체 생성
*
* @param id 아이디
* @param email 이메일
* @param name 이름
*/
@Builder
public SocialUserResponseDto(String id, String email, String name) {
this.id = id;
this.email = email;
this.name = name;
}
}

View File

@@ -33,24 +33,43 @@ import java.util.UUID;
@NoArgsConstructor
public class UserJoinRequestDto {
/**
* 사용자 이름
*/
@NotBlank(message = "{user.user_name}{valid.required}")
private String userName;
/**
* 이메일
*/
@NotBlank(message = "{user.email}{valid.required}")
@Email
private String email;
/**
* 비밀번호
*/
// (숫자)(영문)(특수문자)(공백제거)(자리수)
@Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,20}",
message = "{valid.password}")
private String password;
/**
* 소셜 공급자
*/
private String provider;
/**
* 소셜 토큰
*/
private String token;
/**
* UserSaveRequestDto 의 필드 값을 User Entity 빌더를 사용하여 주입 후 User를 리턴한다.
* UserSaveRequestDto 가 가지고 있는 User 의 필드만 세팅할 수 있게 된다.
*
* @param passwordEncoder
* @return
* @param passwordEncoder 비밀번호 인코더
* @return User 사용자 엔티티
*/
public User toEntity(BCryptPasswordEncoder passwordEncoder) {
return User.builder()

View File

@@ -1,19 +1,17 @@
package org.egovframe.cloud.userservice.api.user.dto;
import java.util.Arrays;
import java.util.UUID;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import org.egovframe.cloud.common.domain.Role;
import org.egovframe.cloud.userservice.domain.user.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.egovframe.cloud.common.domain.Role;
import org.egovframe.cloud.userservice.domain.user.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import java.util.Arrays;
import java.util.UUID;
/**
* org.egovframe.cloud.userservice.api.user.dto.UserSaveRequestDto

View File

@@ -1,13 +1,13 @@
package org.egovframe.cloud.userservice.api.user.dto;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
/**
* org.egovframe.cloud.userservice.api.user.dto.UserUpdateRequestDto
* <p>

View File

@@ -1,21 +1,9 @@
package org.egovframe.cloud.userservice.config;
import static org.egovframe.cloud.common.config.GlobalConstant.LOGIN_URI;
import static org.springframework.util.StringUtils.hasLength;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.cloud.common.exception.BusinessException;
import org.egovframe.cloud.common.util.LogUtil;
import org.egovframe.cloud.userservice.api.user.dto.UserLoginRequestDto;
import org.egovframe.cloud.userservice.api.user.dto.UserResponseDto;
@@ -34,10 +22,19 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.transaction.annotation.Transactional;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import static org.springframework.util.StringUtils.hasLength;
/**
* org.egovframe.cloud.userservice.config.AuthenticationFilter
@@ -76,11 +73,11 @@ public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
* @param request http 요청
* @param response http 응답
* @return Authentication 인증정보
* @throws NullPointerException 널 포인터 예외
* @throws Exception 예외
* @throws IOException 입출력 예외
* @throws Exception 예외
*/
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
try {
// 사용자가 입력한 인증정보 받기, POST method 값이기 때문에 input stream으로 받았다.
UserLoginRequestDto creds = new ObjectMapper().readValue(request.getInputStream(), UserLoginRequestDto.class);
@@ -108,12 +105,12 @@ public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
// 인증정보 만들기
return getAuthenticationManager().authenticate(upat);
}
} catch (NullPointerException e) {
} catch (IOException e) {
log.error(e.getLocalizedMessage());
throw new RuntimeException(e);
} catch (Exception e) {
log.error(e.getLocalizedMessage());
throw new RuntimeException(e);
throw e;
}
}
@@ -163,46 +160,41 @@ public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
* @param request
* @param response
* @param chain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String token = httpRequest.getHeader(HttpHeaders.AUTHORIZATION);
if (!hasLength(token) || "undefined".equals(token)) {
super.doFilter(request, response, chain);
} else {
try {
final String requestURI = httpRequest.getRequestURI();
log.info("httpRequest.getRequestURI() ={}", requestURI);
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
try {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String token = httpRequest.getHeader(HttpHeaders.AUTHORIZATION);
if (!hasLength(token) || "undefined".equals(token)) {
super.doFilter(request, response, chain);
} else {
// 토큰 유효성 검사는 API Gateway ReactiveAuthorization 클래스에서 미리 처리된다.
Claims claims = tokenProvider.getClaimsFromToken(token);
if (LOGIN_URI.equals(requestURI)) {
// 로그인 등 토큰 정보를 꺼낼 필요가 없는 경우
String username = claims.getSubject();
if (username == null) {
// refresh token 에는 subject, authorities 정보가 없다.
SecurityContextHolder.getContext().setAuthentication(null);
} else {
// 토큰 유효성 검사는 API Gateway ReactiveAuthorization 클래스에서 미리 처리된다.
Claims claims = tokenProvider.getClaimsFromToken(token);
String username = claims.getSubject();
if (username == null) {
// refresh token 에는 subject, authorities 정보가 없다.
SecurityContextHolder.getContext().setAuthentication(null);
} else {
List<SimpleGrantedAuthority> roleList = Arrays.stream(claims.get(tokenProvider.TOKEN_CLAIM_NAME, String.class).split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(username, null, roleList));
}
List<SimpleGrantedAuthority> roleList = Arrays.stream(claims.get(tokenProvider.TOKEN_CLAIM_NAME, String.class).split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(username, null, roleList));
}
chain.doFilter(request, response);
} catch (Exception e) {
SecurityContextHolder.getContext().setAuthentication(null);
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
log.error("AuthenticationFilter doFilter", e);
chain.doFilter(request, response);
}
} catch (BusinessException e) {
SecurityContextHolder.getContext().setAuthentication(null);
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setStatus(e.getErrorCode().getStatus());
log.error("AuthenticationFilter doFilter error: {}", e.getMessage());
} catch (Exception e) {
SecurityContextHolder.getContext().setAuthentication(null);
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
log.error("AuthenticationFilter doFilter error: {}", e.getMessage());
}
}
}

View File

@@ -1,14 +1,5 @@
package org.egovframe.cloud.userservice.domain.role;
import java.util.List;
import org.egovframe.cloud.common.dto.RequestDto;
import org.egovframe.cloud.userservice.api.role.dto.AuthorizationListResponseDto;
import org.egovframe.cloud.userservice.domain.user.QUser;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import com.google.common.base.CaseFormat;
import com.querydsl.core.QueryResults;
import com.querydsl.core.types.Order;
@@ -20,8 +11,15 @@ import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.JPQLQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.egovframe.cloud.common.dto.RequestDto;
import org.egovframe.cloud.userservice.api.role.dto.AuthorizationListResponseDto;
import org.egovframe.cloud.userservice.domain.user.QUser;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import java.util.List;
/**
* org.egovframe.cloud.userservice.domain.role.AuthorizationRepositoryImpl

View File

@@ -1,25 +1,18 @@
package org.egovframe.cloud.userservice.domain.user;
import static javax.persistence.GenerationType.IDENTITY;
import java.time.LocalDateTime;
import java.util.Arrays;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.egovframe.cloud.common.domain.Role;
import org.egovframe.cloud.servlet.domain.BaseEntity;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.Arrays;
import static javax.persistence.GenerationType.IDENTITY;
/**
* org.egovframe.cloud.userservice.domain.user.User
@@ -191,36 +184,6 @@ public class User extends BaseEntity {
return this;
}
/**
* 구글 id 등록
*
* @return User 사용자 엔티티
*/
public User updateGoogleId(String googleId) {
this.googleId = googleId;
return this;
}
/**
* 카카오 id 등록
*
* @return User 사용자 엔티티
*/
public User updateKakaoId(String kakaoId) {
this.kakaoId = kakaoId;
return this;
}
/**
* 네이버 id 등록
*
* @return User 사용자 엔티티
*/
public User updateNaverId(String naverId) {
this.naverId = naverId;
return this;
}
/**
* 소셜 사용자 여부 반환
*
@@ -234,6 +197,28 @@ public class User extends BaseEntity {
return false;
}
/**
* 소셜 정보 설정
*
* @return User 사용자 엔티티
*/
public User setSocial(String provider, String providerId) {
switch (provider) {
case "google":
this.googleId = providerId;
break;
case "naver":
this.naverId = providerId;
break;
case "kakao":
this.kakaoId = providerId;
break;
default:
}
return this;
}
public String getRoleKey() {
return this.role.getKey();
}

View File

@@ -1,11 +1,7 @@
package org.egovframe.cloud.userservice.service.role;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.cloud.common.config.GlobalConstant;
import org.egovframe.cloud.common.dto.RequestDto;
import org.egovframe.cloud.common.exception.EntityNotFoundException;
@@ -28,7 +24,10 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.AntPathMatcher;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* org.egovframe.cloud.userservice.service.role.AuthorizationService
@@ -50,6 +49,7 @@ import lombok.RequiredArgsConstructor;
@Transactional(readOnly = true)
@RequiredArgsConstructor
@Service
@Slf4j
public class AuthorizationService extends AbstractService {
/**

View File

@@ -12,7 +12,9 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.cloud.common.domain.Role;
import org.egovframe.cloud.common.dto.RequestDto;
import org.egovframe.cloud.common.exception.BusinessException;
import org.egovframe.cloud.common.exception.BusinessMessageException;
import org.egovframe.cloud.common.exception.dto.ErrorCode;
import org.egovframe.cloud.common.service.AbstractService;
import org.egovframe.cloud.common.util.LogUtil;
import org.egovframe.cloud.userservice.api.user.dto.*;
@@ -21,6 +23,7 @@ import org.egovframe.cloud.userservice.config.dto.SocialUser;
import org.egovframe.cloud.userservice.domain.log.LoginLog;
import org.egovframe.cloud.userservice.domain.log.LoginLogRepository;
import org.egovframe.cloud.userservice.domain.user.*;
import org.egovframe.cloud.userservice.api.user.dto.SocialUserResponseDto;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -315,7 +318,14 @@ public class UserService extends AbstractService implements UserDetailsService {
throw new BusinessMessageException(getMessage("msg.join.email.exists"));
}
userRepository.save(requestDto.toEntity(passwordEncoder));
User user = requestDto.toEntity(passwordEncoder);
if (requestDto.getProvider() != null && !"".equals(requestDto.getProvider()) && requestDto.getToken() != null && !"".equals(requestDto.getToken())) {
SocialUserResponseDto socialUserResponseDto = getSocialUserInfo(requestDto.getProvider(), requestDto.getToken());
user.setSocial(requestDto.getProvider(), socialUserResponseDto.getId());
}
userRepository.save(user);
return true;
}
@@ -364,12 +374,10 @@ public class UserService extends AbstractService implements UserDetailsService {
log.info("end send change password email - emailAddr: " + emailAddr + ", tokenValue: " + tokenValue);
} catch (MessagingException e) {
e.printStackTrace();
String errorMessage = getMessage("err.user.find.password");
log.error(errorMessage + ": " + e.getMessage());
throw new BusinessMessageException(errorMessage);
} catch (Exception e) {
e.printStackTrace();
String errorMessage = getMessage("err.user.find.password");
log.error(errorMessage + ": " + e.getMessage());
throw new BusinessMessageException(errorMessage);
@@ -579,9 +587,9 @@ public class UserService extends AbstractService implements UserDetailsService {
*/
@Transactional
public UserResponseDto loadUserBySocial(UserLoginRequestDto requestDto) {
String[] userInfo = getSocialUserInfo(requestDto.getProvider(), requestDto.getToken());
/*SocialUserResponseDto socialUserDto = getSocialUserInfo(requestDto.getProvider(), requestDto.getToken());
UserResponseDto userDto = getAndSaveSocialUser(requestDto.getProvider(), userInfo[0], userInfo[1], userInfo[2]);
UserResponseDto userDto = getAndSaveSocialUser(requestDto.getProvider(), socialUserDto);
if (userDto == null) {
throw new BusinessMessageException(getMessage("err.user.join.social"));
@@ -590,7 +598,29 @@ public class UserService extends AbstractService implements UserDetailsService {
throw new BusinessMessageException(getMessage("err.user.state.cantlogin"));
}
return userDto;
return userDto;*/
SocialUserResponseDto socialUserResponseDto = getSocialUserInfo(requestDto.getProvider(), requestDto.getToken());
User user = findSocialUser(requestDto.getProvider(), socialUserResponseDto.getId());
/*// 이메일이 없는 사용자가 이메일을 직접입력하고 나중에 원래 이메일을 가지고 있는 사용자가 다른 접근할 경우 문제가 생길 수 있음
if (user == null && socialUserResponseDto.getEmail() != null) {
user = userRepository.findByEmail(socialUserResponseDto.getEmail()).orElse(null);
// 공급자 id로 조회되지 않지만 이메일로 조회되는 경우 공급자 id 등록
if (user != null) {
user.setSocial(requestDto.getProvider(), socialUserResponseDto.getId());
}
}*/
if (user == null) {
throw new BusinessException(ErrorCode.REQUIRE_USER_JOIN);
}
if (!UserStateCode.NORMAL.getKey().equals(user.getUserStateCode())) {
throw new BusinessMessageException(getMessage("err.user.state.cantlogin"));
}
return new UserResponseDto(user);
}
/**
@@ -601,9 +631,9 @@ public class UserService extends AbstractService implements UserDetailsService {
* @return User 사용자 엔티티
*/
private User findSocialUserByToken(String provider, String token) {
String[] userInfo = getSocialUserInfo(provider, token);
SocialUserResponseDto socialUserResponseDto = getSocialUserInfo(provider, token);
return findSocialUser(provider, userInfo[0]);
return findSocialUser(provider, socialUserResponseDto.getId());
}
/**
@@ -613,26 +643,26 @@ public class UserService extends AbstractService implements UserDetailsService {
* @param token 토큰
* @return String[] 소셜 사용자 정보
*/
private String[] getSocialUserInfo(String provider, String token) {
String[] userInfo = null;
public SocialUserResponseDto getSocialUserInfo(String provider, String token) {
SocialUserResponseDto social = null;
switch (provider) {
case "google":
userInfo = getGoogleUserInfo(token);
social = getGoogleUserInfo(token);
break;
case "naver":
userInfo = getNaverUserInfo(token);
social = getNaverUserInfo(token);
break;
case "kakao":
userInfo = getKakaoUserInfo(token);
social = getKakaoUserInfo(token);
break;
default:
break;
}
if (userInfo == null) throw new BusinessMessageException(getMessage("err.user.social.get"));
if (social == null) throw new BusinessMessageException(getMessage("err.user.social.get"));
return userInfo;
return social;
}
/**
@@ -641,7 +671,7 @@ public class UserService extends AbstractService implements UserDetailsService {
* @param token 토큰
* @return String[] 구글 사용자 정보
*/
private String[] getGoogleUserInfo(String token) {
private SocialUserResponseDto getGoogleUserInfo(String token) {
try {
HttpTransport transport = new NetHttpTransport();
GsonFactory gsonFactory = new GsonFactory();
@@ -652,14 +682,18 @@ public class UserService extends AbstractService implements UserDetailsService {
GoogleIdToken idToken = verifier.verify(token);
GoogleIdToken.Payload payload = idToken.getPayload();
log.info("google oauth2: {}", payload.toString());
if (idToken != null) {
GoogleIdToken.Payload payload = idToken.getPayload();
log.info("google oauth2: {}", payload.toString());
return new String[]{
payload.getSubject(),
payload.getEmail(),
(String) payload.get("name")
};
return SocialUserResponseDto.builder()
.id(payload.getSubject())
.email(payload.getEmail())
.name((String) payload.get("name"))
.build();
}
return null;
} catch (GeneralSecurityException e) {
throw new BusinessMessageException(getMessage("err.user.social.get"));
} catch (IOException e) {
@@ -675,7 +709,7 @@ public class UserService extends AbstractService implements UserDetailsService {
* @param token 토큰
* @return String[] 네이버 사용자 정보
*/
private String[] getNaverUserInfo(String token) {
private SocialUserResponseDto getNaverUserInfo(String token) {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + token);
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
@@ -688,14 +722,26 @@ public class UserService extends AbstractService implements UserDetailsService {
if (response.getBody() != null && !"".equals(response.getBody())) {
JsonElement element = JsonParser.parseString(response.getBody());
JsonObject object = element.getAsJsonObject();
log.info("naver oauth2: {}", object.toString());
log.info("naver oauth2: {}", object);
if (object.get("resultcode") != null && "00".equals(object.get("resultcode").getAsString())) {
return new String[]{
object.get("response").getAsJsonObject().get("id").getAsString(),
object.get("response").getAsJsonObject().get("email").getAsString(),
object.get("response").getAsJsonObject().get("name").getAsString()
};
JsonElement responseElement = object.get("response");
if (responseElement != null) {
SocialUserResponseDto.SocialUserResponseDtoBuilder builder = SocialUserResponseDto.builder();
if (responseElement.getAsJsonObject().get("id") != null && !"".equals(responseElement.getAsJsonObject().get("id").getAsString())) {
builder.id(responseElement.getAsJsonObject().get("id").getAsString());
}
if (responseElement.getAsJsonObject().get("email") != null && !"".equals(responseElement.getAsJsonObject().get("email").getAsString())) {
builder.email(responseElement.getAsJsonObject().get("email").getAsString());
}
if (responseElement.getAsJsonObject().get("name") != null && !"".equals(responseElement.getAsJsonObject().get("name").getAsString())) {
builder.name(responseElement.getAsJsonObject().get("name").getAsString());
}
return builder.build();
}
}
}
@@ -708,7 +754,7 @@ public class UserService extends AbstractService implements UserDetailsService {
* @param token 토큰
* @return String[] 카카오 사용자 정보
*/
private String[] getKakaoUserInfo(String token) {
private SocialUserResponseDto getKakaoUserInfo(String token) {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + token);
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
@@ -721,14 +767,26 @@ public class UserService extends AbstractService implements UserDetailsService {
if (response.getBody() != null && !"".equals(response.getBody())) {
JsonElement element = JsonParser.parseString(response.getBody());
JsonObject object = element.getAsJsonObject();
JsonElement kakaoAccount = object.get("kakao_account");
log.info("kakao oauth2: {}", object.toString());
if (object.get("id") != null && !"".equals(object.get("id").getAsString())) {
return new String[]{
object.get("id").getAsString(),
object.get("kakao_account").getAsJsonObject().get("email").getAsString(),
object.get("kakao_account").getAsJsonObject().get("profile").getAsJsonObject().get("nickname").getAsString()
};
String id = object.get("id") != null && !"".equals(object.get("id").getAsString()) ? object.get("id").getAsString() : null;
if (id != null) {
SocialUserResponseDto.SocialUserResponseDtoBuilder builder = SocialUserResponseDto.builder()
.id(id);
if (kakaoAccount.getAsJsonObject().get("email") != null && !"".equals(kakaoAccount.getAsJsonObject().get("email").getAsString())) {
builder.email(kakaoAccount.getAsJsonObject().get("email").getAsString());
}
JsonElement profile = kakaoAccount.getAsJsonObject().get("profile");
if (profile != null) {
if (profile.getAsJsonObject().get("nickname") != null && !"".equals(profile.getAsJsonObject().get("nickname").getAsString())) {
builder.name(profile.getAsJsonObject().get("nickname").getAsString());
}
}
return builder.build();
}
}
@@ -785,19 +843,7 @@ public class UserService extends AbstractService implements UserDetailsService {
// 공급자 id로 조회되지 않지만 이메일로 조회되는 경우 공급자 id 등록
if (user != null) {
switch (providerCode) {
case "google":
user = user.updateGoogleId(providerId);
break;
case "kakao":
user = user.updateKakaoId(providerId);
break;
case "naver":
user = user.updateNaverId(providerId);
break;
default:
break;
}
user.setSocial(providerCode, providerId);
}
}
@@ -806,27 +852,15 @@ public class UserService extends AbstractService implements UserDetailsService {
final String userId = UUID.randomUUID().toString();
//final String password = makeRandomPassword(); // 임의 비밀번호 생성 시 복호화 불가능
User.UserBuilder userBuilder = User.builder()
user = User.builder()
.email(email) // 100byte
//.encryptedPassword(passwordEncoder.encode(password)) // 100 byte
.userName(userName)
.userId(userId)
.role(Role.USER)
.userStateCode(UserStateCode.NORMAL.getKey());
switch (providerCode) {
case "google":
user = userBuilder.googleId(providerId).build();
break;
case "kakao":
user = userBuilder.kakaoId(providerId).build();
break;
case "naver":
user = userBuilder.naverId(providerId).build();
break;
default:
break;
}
.userStateCode(UserStateCode.NORMAL.getKey())
.build();
user.setSocial(providerCode, providerId);
if (user != null) {
userRepository.save(user);

View File

@@ -4,12 +4,6 @@ server:
spring:
application:
name: user-service
profiles:
group:
default: oauth
docker: oauth
cf: oauth
k8s: oauth
jpa:
hibernate:
ddl-auto: none
@@ -28,6 +22,48 @@ spring:
jcache:
config: classpath:ehcache.xml
# oauth2 를 사용하기 위해서는 아래의 TODO 를 등록해야 함
security:
oauth2:
client:
registration:
# /oauth2/authorization/google
google:
client-id: google_client_id # TODO https://console.cloud.google.com
client-secret: google_client_secret # TODO
scope: profile,email
# 네이버는 Spring Security를 공식 지원하지 않기 때문에 CommonOAuth2Provider 에서 해주는 값들을 수동으로 입력한다.
# /oauth2/authorization/naver
naver:
client-id: naver_client_id # TODO https://developers.naver.com/apps/#/register?api=nvlogin
client-secret: naver_client_secret # TODO
redirect_uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
authorization_grant_type: authorization_code
scope: name,email,profile_image
client-name: Naver
# /oauth2/authorization/kakao
kakao:
client-id: kakao_client_id # TODO https://developers.kakao.com/product/kakaoLogin
client-secret: kakao_client_secret # TODO
redirect-uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
client-authentication-method: POST
authorization-grant-type: authorization_code
scope: profile_nickname, account_email
client-name: Kakao
provider:
naver:
authorization_uri: https://nid.naver.com/oauth2.0/authorize
token_uri: https://nid.naver.com/oauth2.0/token
user-info-uri: https://openapi.naver.com/v1/nid/me
# 기준이 되는 user_name 의 이름을 네이버에서는 response로 지정해야한다. (네이버 회원 조회시 반환되는 JSON 형태 때문이다)
# response를 user_name으로 지정하고 이후 자바 코드로 response의 id를 user_name으로 지정한다. (스프링 시큐리티에서 하위 필드를 명시할 수 없기 때문)
user_name_attribute: response
kakao:
authorization_uri: https://kauth.kakao.com/oauth/authorize
token_uri: https://kauth.kakao.com/oauth/token
user-info-uri: https://kapi.kakao.com/v2/user/me
user_name_attribute: id
# config server actuator
management:
endpoints:
@@ -37,30 +73,3 @@ management:
health:
mail:
enabled: false
# @TODO application-oauth.yml
# spring:
# security:
# oauth2:
# client:
# registration:
# google:
# client-id: @TODO https://console.cloud.google.com
# client-secret: @TODO
# scope: profile,email
# # 네이버는 Spring Security를 공식 지원하지 않기 때문에 CommonOAuth2Provider 에서 해주는 값들을 수동으로 입력한다.
# naver:
# client-id: @TODO https://developers.naver.com/apps/#/register?api=nvlogin
# client-secret: @TODO
# redirect_uri_template: "{baseUrl}/{action}/oauth2/code/{registrationId}"
# authorization_grant_type: authorization_code
# scope: name,email,profile_image
# client-name: Naver
# provider:
# naver:
# authorization_uri: https://nid.naver.com/oauth2.0/authorize
# token_uri: https://nid.naver.com/oauth2.0/token
# user-info-uri: https://openapi.naver.com/v1/nid/me
# # 기준이 되는 user_name 의 이름을 네이버에서는 response로 지정해야한다. (네이버 회원 조회시 반환되는 JSON 형태 때문이다)
# # response를 user_name으로 지정하고 이후 자바 코드로 response의 id를 user_name으로 지정한다. (스프링 시큐리티에서 하위 필드를 명시할 수 없기 때문)
# user_name_attribute: response

View File

@@ -15,7 +15,7 @@
</springProfile>
<springProfile name="!default">
<!-- java -Ddestination="localhost:5001" 와 같이 변경할 수 있다. cf 환경에서는 manifest.yml 파일에 환경변수로 추가 -->
<property name="destination" value="${destination:-localhost:5001}" />
<property name="destination" value="${logstash_hostname:-localhost:5001}" />
<property name="app_name" value="${app_name:-user-service}" />
<!-- ELK - Logstash 로 로그를 전송하기 위한 appender -->

View File

@@ -1,13 +1,6 @@
package org.egovframe.cloud.userservice.api.role;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.egovframe.cloud.userservice.domain.role.Authorization;
import org.egovframe.cloud.userservice.domain.role.AuthorizationRepository;
import org.egovframe.cloud.userservice.domain.role.RoleAuthorization;
@@ -36,7 +29,9 @@ import org.springframework.util.MultiValueMap;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.*;
import static org.assertj.core.api.Assertions.assertThat;
/**
* org.egovframe.cloud.userservice.api.role.AuthorizationApiControllerTest

View File

@@ -12,16 +12,14 @@ eureka:
register-with-eureka: true # eureka 서버에 등록
fetch-registry: true # 외부 검색 가능
service-url:
defaultZone: http://admin:admin@localhost:8761/eureka
defaultZone: http://admin:admin@${eureka.instance.hostname:localhost}:8761/eureka
# file attach location - messages{lang}.properties 도 이 경로에 위치한다.
file:
directory: ${user.home}/msa-attach-volume # url 사용시에는 사용되지 않는다
directory: ${app.home:${user.home}}/msa-attach-volume # url 사용시에는 사용되지 않는다
url: http://localhost:8080 # nginx 로 파일 다운로드 처리
messages:
directory: ${file.directory}/messages
logstash:
url: localhost:8086
apigateway:
host: http://localhost:${server.port}
@@ -29,12 +27,12 @@ apigateway:
# rabbitmq server
spring:
rabbitmq:
host: localhost
host: ${rabbitmq.hostname:${localhost}}
port: 5672
username: guest
password: guest
zipkin:
base-url: http://localhost:8085
base-url: http://${zipkin.hostname:${localhost}}:9411
egov:
message: hello

View File

@@ -1,5 +1,5 @@
database:
url: jdbc:mysql://localhost:3306/msaportal
url: jdbc:mysql://${mysql.hostname:localhost}:3306/msaportal
spring:
datasource:

Some files were not shown because too many files have changed in this diff Show More