Compare commits

...

74 Commits

Author SHA1 Message Date
qkr7828 1f5ad17f5e feat : content(faq, qna) 작업중 7 months ago
qkr7828 2712ce1700 feat : content(faq, qna) 작업중 7 months ago
qkr7828 106055c062 feat : contents 작업중 7 months ago
qkr7828 def31f6b71 feat : contents 작업중 7 months ago
qkr7828 d2ae669797 feat : contents 작업중 7 months ago
qkr7828 55d664215d feat : contents 작업중 7 months ago
lkd9125(이경도) c6a2564b5f refactor: Security 암호화 롤백 7 months ago
lkd9125 44011e96b1 feature/user (#8) 7 months ago
지대한 946dc35c24 fix: ddl-auto none 7 months ago
지대한 c22d5a1424 fix: auto_increment 버그로 인하여 임시로 table 전략으로 변경 7 months ago
지대한 05e2c63fec fix: auto_increment 버그로 인하여 임시로 table 전략으로 변경 7 months ago
지대한 4a787f054c refactor: db h2 test를 위한 수정 7 months ago
지대한 359c96ee8b fix: api-common scurity util 사용하도록 수정 7 months ago
지대한 04b1913753 fix: open해둔 uri중 GET method만 적용이 되는 현상 7 months ago
지대한 322103ad9b feat: session helper 구현 7 months ago
지대한 3d17bec1bb refactor: app에서 querydsl 설정 제거 7 months ago
지대한 e28b1b01ea fix: api-common에서 jpa annotation 못읽어오는 현상 7 months ago
지대한 56b0c72f63 refactor: 모듈 수정 7 months ago
지대한 061663c8b5 refactor: gradle jpa 설정 및 code package 수정 7 months ago
지대한 ac6865a15e refactor: gradle api 명령어 사용하기 위한 수정 7 months ago
지대한 395972cd3f refactor: app gradle print 제거 7 months ago
지대한 6c32044d93 refactor: module 위치 변경 7 months ago
지대한 67ab2bba16 refactor: rest doc gradle test option 적용 7 months ago
lkd9125(이경도) 1463649563 fix : Test 스킵 스크립트 추가 [gradle build -x test] 7 months ago
lkd9125(이경도) d69d14e15a Merge remote-tracking branch 'origin/develop' into develop 8 months ago
lkd9125(이경도) b679f86a08 refactor: 코드정리 8 months ago
lkd9125(이경도) 1ccf1140a3 refactor: [임시] 테스트 데이터 삽입 후 삭제 조치 8 months ago
지대한 5a974631e9 fix: web ignore 사용시 warning 8 months ago
지대한 90802890de feature/data (#6) 8 months ago
lkd9125(이경도) e63d7a64db refactor: Test order 삭제 8 months ago
qkr7828 6b714c0f46 fix : Qualifier 적용되도록 설정 변경 8 months ago
lkd9125(이경도) 0fcad045a6 fix: PermitURL 변경 8 months ago
lkd9125(이경도) 17e1affce5 Merge commit '536dff756b314723675d61f1be5d22c160e3af25' into develop 8 months ago
lkd9125(이경도) 487af94496 Refactor: 트랜잭션 처리 추가, DB에 데이터 쌓이지 않게 변경 8 months ago
lkd9125(이경도) 562df6b0ce Add: RestDocs 스니펫 커스텀으로인한 항목 추가, 테스트 Transaction 롤백기능추가 8 months ago
qkr7828 536dff756b feat : swagger uri 추가 8 months ago
지대한 a085711156 refactor: data module 분기 8 months ago
지대한 36d78d82c5 feat: security 구성 8 months ago
lkd9125(이경도) d584d8c0b7 fix: SpringRestDocs build시 -x test Option으로 테스트 안하고 빌드하도록 수정 8 months ago
지대한 c06fe45fe1 feat: util - masking 추가 8 months ago
지대한 c9422c1a66 feat: util 모듈 app에 추가 8 months ago
지대한 1c27a48858 feat: 암복구화 및 단방향 암호화 유틸 추가 8 months ago
lkd9125(이경도) 1d5bed9ce7 feat: SpringRestDocs 라이브러리 및 예제 추가 8 months ago
지대한 6fa8d61898 Merge pull request 'feat: 공통 exception 설정' (#3) from feature/error into develop 8 months ago
지대한 1fc4f1c93d feat: 공통 exception 설정 8 months ago
지대한 1274960091 feat: message source 구성 (error message 용도) 8 months ago
lkd9125 27d26daa46 Merge pull request 'feature/common/exception' (#2) from feature/common/exception into develop 8 months ago
lkd9125(이경도) e5f77b3de6 feat: Error RS 포맷팅 변경, 서버용 로그 추가 8 months ago
lkd9125(이경도) 95562bf996 move: exception commone 코어 모듈로 이동 8 months ago
지대한 c736566683 feat: querydsl 기능 적용 8 months ago
지대한 679e50bed0 feat: header Accept-Language 언어 강제하기 8 months ago
지대한 9806887ee8 move: exception관련 코드 패키지 이동 8 months ago
지대한 0970cba328 feat: jpa embedded to idclass 8 months ago
박재우 59b6625881 feat: swagger example, config 작업 8 months ago
지대한 41aacc4c14 feat: common root module 생성 8 months ago
지대한 0276f9b767 del: .DS_Store 제거 8 months ago
지대한 7cc65313c4 del: .DS_Store 제거 8 months ago
지대한 5b9398b44f del: .DS_Store 제거 8 months ago
지대한 56bd7d5142 del: .DS_Store 제거 8 months ago
지대한 069406969c del: .DS_Store 제거 8 months ago
지대한 40c4e8dcb5 del: .DS_Store 제거 8 months ago
박재우 708534570a feat : swagger 설정 추가 8 months ago
박재우 cf07273d30 springdoc implement 8 months ago
지대한 e986ad4848 feat: module 분리 8 months ago
지대한 c8c16724bc feat: code api 구성 8 months ago
lkd9125 7777f85203 Merge pull request 'ExceptionHandler추가' (#1) from feature/exception into develop 8 months ago
lkd9125(이경도) 44214a819c ExceptionHandler추가 8 months ago
지대한 087d11efa1 feat: data - code 구성 8 months ago
지대한 18d1e99b23 feat: code 연관관계 구성 8 months ago
지대한 4fd51aa4da docs: 프로젝트 최초 실행 가이드 8 months ago
지대한 f3edb2286e add: repository 객체 추가 8 months ago
지대한 c36929b090 chore: jpa 설정 8 months ago
지대한 0c0eb8ba30 add: entity 객체 추가 8 months ago
지대한 d713a2cb8e chore: docker 관련 내용 추가 9 months ago
  1. BIN
      .DS_Store
  2. 3
      .gitignore
  3. 61
      README.md
  4. BIN
      app/.DS_Store
  5. BIN
      app/kac-app/.DS_Store
  6. 10
      app/kac-app/Dockerfile
  7. 89
      app/kac-app/build.gradle
  8. 3
      app/kac-app/docker-copy.sh
  9. BIN
      app/kac-app/src/.DS_Store
  10. 244
      app/kac-app/src/docs/asciidoc/index.adoc
  11. BIN
      app/kac-app/src/main/.DS_Store
  12. BIN
      app/kac-app/src/main/java/.DS_Store
  13. 3
      app/kac-app/src/main/java/kr/co/palnet/kac/app/KacAppApplication.java
  14. 26
      app/kac-app/src/main/java/kr/co/palnet/kac/app/config/MessageSourceConfig.java
  15. 112
      app/kac-app/src/main/java/kr/co/palnet/kac/app/config/SwaggerConfig.java
  16. 19
      app/kac-app/src/main/java/kr/co/palnet/kac/app/config/WebConfig.java
  17. 132
      app/kac-app/src/main/java/kr/co/palnet/kac/app/core/exception/ServerExceptionHandler.java
  18. 60
      app/kac-app/src/main/java/kr/co/palnet/kac/app/core/security/AppSecurityConfig.java
  19. 68
      app/kac-app/src/main/java/kr/co/palnet/kac/app/core/web/BaseAcceptHeaderLocaleResolver.java
  20. 3
      app/kac-app/src/main/java/kr/co/palnet/kac/app/ping/controller/PingController.java
  21. 128
      app/kac-app/src/main/java/kr/co/palnet/kac/app/ping/controller/TestErrorContoller.java
  22. 31
      app/kac-app/src/main/java/kr/co/palnet/kac/app/ping/controller/TestSessionContrller.java
  23. 3
      app/kac-app/src/main/java/lombok.config
  24. 41
      app/kac-app/src/main/resources/application-swagger.yml
  25. 23
      app/kac-app/src/main/resources/application.yml
  26. 2
      app/kac-app/src/main/resources/log4jdbc.log4j2.properties
  27. 22
      app/kac-app/src/main/resources/messages/errors/error.properties
  28. 22
      app/kac-app/src/main/resources/messages/errors/error_en.properties
  29. 2244
      app/kac-app/src/main/resources/static/docs/index.html
  30. 119
      app/kac-app/src/test/java/kr/co/palnet/kac/BaseTest.java
  31. 600
      app/kac-app/src/test/java/kr/co/palnet/kac/com/code/ComnCodeControllerTest.java
  32. 228
      app/kac-app/src/test/java/kr/co/palnet/kac/user/account/UserAccountControllerTest.java
  33. 11
      app/kac-app/src/test/resources/org/springframework/restdocs/templates/path-parameters.snippet
  34. 10
      app/kac-app/src/test/resources/org/springframework/restdocs/templates/query-parameters.snippet
  35. 12
      app/kac-app/src/test/resources/org/springframework/restdocs/templates/request-fields.snippet
  36. 10
      app/kac-app/src/test/resources/org/springframework/restdocs/templates/request-headers.snippet
  37. 12
      app/kac-app/src/test/resources/org/springframework/restdocs/templates/response-fields.snippet
  38. 87
      build.gradle
  39. 12
      common/config-db/build.gradle
  40. 68
      common/config-db/src/main/java/kr/co/palnet/kac/config/db/KacJpaConfig.java
  41. 20
      common/config-db/src/main/java/kr/co/palnet/kac/config/db/QueryDslConfig.java
  42. 12
      common/config-db/src/main/resources/application-db.yml
  43. 6
      common/core/build.gradle
  44. 4
      common/core/src/main/java/kr/co/palnet/kac/core/Sample.java
  45. 60
      common/core/src/main/java/kr/co/palnet/kac/core/code/ErrorCode.java
  46. 24
      common/core/src/main/java/kr/co/palnet/kac/core/code/Level.java
  47. 8
      common/core/src/main/java/kr/co/palnet/kac/core/code/MessageType.java
  48. 9
      common/core/src/main/java/kr/co/palnet/kac/core/code/ObjectType.java
  49. 32
      common/core/src/main/java/kr/co/palnet/kac/core/code/RSErrorCode.java
  50. 6
      common/core/src/main/java/kr/co/palnet/kac/core/code/Source.java
  51. 54
      common/core/src/main/java/kr/co/palnet/kac/core/exception/BaseErrorCode.java
  52. 132
      common/core/src/main/java/kr/co/palnet/kac/core/exception/BaseException.java
  53. 9
      common/core/src/main/java/kr/co/palnet/kac/core/exception/Level.java
  54. 28
      common/core/src/main/java/kr/co/palnet/kac/core/exception/model/BaseErrorModel.java
  55. 5
      common/core/src/main/java/kr/co/palnet/kac/core/response/BasicResponse.java
  56. 29
      common/core/src/main/java/kr/co/palnet/kac/core/response/ErrorResponse.java
  57. 30
      common/core/src/main/java/kr/co/palnet/kac/core/response/SuccessResponse.java
  58. 5
      common/util/build.gradle
  59. 100
      common/util/src/main/java/kr/co/palnet/kac/util/EncryptUtil.java
  60. 128
      common/util/src/main/java/kr/co/palnet/kac/util/KisaEncryptUtil.java
  61. 106
      common/util/src/main/java/kr/co/palnet/kac/util/MaskingUtil.java
  62. 52
      common/util/src/main/java/kr/co/palnet/kac/util/ObjectMapperUtils.java
  63. 11
      common/util/src/main/java/kr/co/palnet/kac/util/UtilApplication.java
  64. 1928
      common/util/src/main/java/kr/co/palnet/kac/util/kisa/KISA_SEED_CBC.java
  65. 1265
      common/util/src/main/java/kr/co/palnet/kac/util/kisa/KISA_SEED_CTR.java
  66. 1421
      common/util/src/main/java/kr/co/palnet/kac/util/kisa/KISA_SEED_ECB.java
  67. 453
      common/util/src/main/java/kr/co/palnet/kac/util/kisa/KISA_SHA256.java
  68. 26
      data/cns/build.gradle
  69. 78
      data/cns/src/main/java/kr/co/palnet/kac/data/cns/model/CnsFaqBas.java
  70. 104
      data/cns/src/main/java/kr/co/palnet/kac/data/cns/model/CnsQnaBas.java
  71. 28
      data/cns/src/main/java/kr/co/palnet/kac/data/cns/repository/CnsFaqBasRepository.java
  72. 165
      data/cns/src/main/java/kr/co/palnet/kac/data/cns/repository/CnsFaqQueryRepository.java
  73. 23
      data/cns/src/main/java/kr/co/palnet/kac/data/cns/repository/CnsQnaBasRepository.java
  74. 42
      data/cns/src/main/java/kr/co/palnet/kac/data/cns/service/CnsFaqDomainService.java
  75. 26
      data/com/build.gradle
  76. 53
      data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComAdmDistrictBas.java
  77. 114
      data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComArcrftBas.java
  78. 63
      data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComAuthBas.java
  79. 103
      data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComCdBas.java
  80. 70
      data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComCdGroupBas.java
  81. 106
      data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComCdLangCtg.java
  82. 74
      data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComConfirmBas.java
  83. 85
      data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComFileBas.java
  84. 72
      data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComIdntfBas.java
  85. 111
      data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComRiseSetBas.java
  86. 59
      data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComSiteBas.java
  87. 58
      data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComTrmnlBas.java
  88. 7
      data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComAdmDistrictBasRepository.java
  89. 7
      data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComArcrftBasRepository.java
  90. 7
      data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComAuthBasRepository.java
  91. 14
      data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComCdBasRepository.java
  92. 10
      data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComCdGroupBasRepository.java
  93. 10
      data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComCdLangCtgRepository.java
  94. 8
      data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComConfirmBasRepository.java
  95. 8
      data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComFileBasRepository.java
  96. 8
      data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComIdntBasRepository.java
  97. 8
      data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComRiseSetBasRepository.java
  98. 7
      data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComSiteBasRepository.java
  99. 7
      data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComTrmnlBasRepository.java
  100. 212
      data/com/src/main/java/kr/co/palnet/kac/data/com/service/ComCodeDomainService.java
  101. Some files were not shown because too many files have changed in this diff Show More

BIN
.DS_Store vendored

Binary file not shown.

3
.gitignore vendored

@ -35,3 +35,6 @@ out/
### VS Code ### ### VS Code ###
.vscode/ .vscode/
/db/
.DS_Store
**/.DS_Store

61
README.md

@ -0,0 +1,61 @@
# Spec
## 환경 구성
### 기본 정보
- java 21
- spring boot 3.2.1
- jpa
- mysql
## 작업전 준비
### 1. mysql 설치
```
docker-compose up -d database
```
### 2. application.yml 설정 변경
최초 실행시 table 생성하기 위한 작업
`ddl-auto: create`로 변경 후 실행한 다음 Table이 생성되었는지 확인하고 원래 설정값으로 변경한다.
```yaml
spring:
jpa:
hibernate:
ddl-auto: create
```
## 설정 정보
### log4jdbc.log4j2.properties 속성
| 속성 | 설명 |
|--------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
| log4jdbc.spylogdelegator.name | 로그4jdbc에서 사용할 로그 델리게이트(Delegate)의 이름을 지정합니다. 이 구성을 통해 로그 델리게이트를 변경할 수 있습니다. 이 코드에서는 SLF4J를 사용하는 net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator가 지정되어 있습니다. |
| log4jdbc.dump.sql.maxlinelength | SQL문의 최대 길이를 지정합니다. 이 속성은 SQL문을 자동 줄 바꿈하는 데 사용됩니다. 이 코드에서는 0으로 설정되어 있으므로 SQL문의 길이에 제한이 없습니다. |
| log4jdbc.spylogdelegator.name | 로그4jdbc에서 사용할 로그 델리게이트(Delegate)의 이름을 지정합니다. 이 구성을 통해 로그 델리게이트를 변경할 수 있습니다. 이 코드에서는 SLF4J를 사용하는 net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator가 지정되어 있습니다. |
| log4jdbc.dump.sql.maxlinelength | SQL문의 최대 길이를 지정합니다. 이 속성은 SQL문을 자동 줄 바꿈하는 데 사용됩니다. 이 코드에서는 0으로 설정되어 있으므로 SQL문의 길이에 제한이 없습니다. |
| log4jdbc.auto.load.popular.drivers | 자주 사용되는 드라이버를 자동으로 로드할지 여부를 지정합니다. 이 코드에서는 true로 설정되어 있습니다. |
| log4jdbc.trim.sql.enabled | SQL 문의 앞뒤 공백을 자동으로 제거할지 여부를 지정합니다. 이 코드에서는 true로 설정되어 있습니다. |
| log4jdbc.trim.sql.extrablanklines | SQL 문의 공백 라인을 제거할지 여부를 지정합니다. 이 코드에서는 false로 설정되어 있습니다. |
| log4jdbc.suppress.generated.keys.exception | SQL 문에서 생성된 키 예외를 억제할지 여부를 지정합니다. 이 코드에서는 false로 설정되어 있습니다.
## spring rest doc
### URL
- uri : `/docs/index.html`
- local : http://localhost:8080/docs/index.html
## spring swagger
### URL
- uri : `/swagger-ui/index.html`
- local : http://localhost:8080/swagger-ui/index.html

BIN
app/.DS_Store vendored

Binary file not shown.

BIN
app/kac-app/.DS_Store vendored

Binary file not shown.

10
app/kac-app/Dockerfile

@ -0,0 +1,10 @@
FROM openjdk:21
ENV TZ=Asia/Seoul
EXPOSE 8080
WORKDIR /app
ADD ./build/libs/*.jar /app/app.jar
ENTRYPOINT ["java","-jar","/app/app.jar"]

89
app/kac-app/build.gradle

@ -1,9 +1,94 @@
plugins {
id "org.asciidoctor.jvm.convert" version "3.3.2"
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
asciidoctorExt
}
dependencies { dependencies {
implementation "$boot:spring-boot-starter-web" implementation "$boot:spring-boot-starter-web"
runtimeOnly 'com.mysql:mysql-connector-j' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'
// security
implementation "$boot:spring-boot-starter-security"
// implementation "com.auth0:java-jwt:4.4.0"
// db
// runtimeOnly "com.mysql:mysql-connector-j"
// implementation "org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4:1.16"
implementation("org.springframework:spring-tx")
// jpa
// implementation "$boot:spring-boot-starter-data-jpa"
// querydsl
// implementation "com.querydsl:querydsl-jpa:5.0.0:jakarta"
// rest doc
asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor'
// test
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation project(":common:core")
// implementation project(":common:config-db")
implementation project(":common:util")
implementation project(":web:security")
implementation project(":web:api-common")
implementation project(":web:api-user")
implementation project(":web:api-cns")
}
ext {
snippetsDir = file('build/generated-snippets')
}
tasks {
def isTest = gradle.startParameter.excludedTaskNames.contains('test')
if (!isTest) {
asciidoctor {
dependsOn test
inputs.dir snippetsDir
doFirst {
delete file('src/main/resources/static/docs')
}
}
}
test {
outputs.dir snippetsDir
}
bootJar {
if (!isTest) {
dependsOn asciidoctor
from("${asciidoctor.outputDir}/html5") {
into 'static/docs'
}
}
}
task copyDocument(type: Copy) {
if (!isTest) {
dependsOn asciidoctor
from file("build/docs/asciidoc")
into file("src/main/resources/static/docs")
}
}
build {
if (!isTest) {
dependsOn copyDocument
}
}
compileOnly project(":data-user")
} }

3
app/kac-app/docker-copy.sh

@ -0,0 +1,3 @@
sh ../../gradlew clean && ../../gradlew bootJar
docker cp ./build/libs/app-kac-app-1.0.0.jar kac-app:/app/app.jar
docker restart kac-app

BIN
app/kac-app/src/.DS_Store vendored

Binary file not shown.

244
app/kac-app/src/docs/asciidoc/index.adoc

@ -0,0 +1,244 @@
ifndef::snippets[]
:snippets: ./build/generated-snippets
endif::[]
= KAC App Docs
API 문서
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 2
:sectlinks:
[[Common-Code-API]]
== Common-Code API
[[Code-All]]
=== [Code 전체코드 조회]
==== [HTTP REQUEST INFO]
include::{snippets}/com/code/all/http-request.adoc[]
include::{snippets}/com/code/all/query-parameters.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/com/code/all/http-response.adoc[]
include::{snippets}/com/code/all/response-fields.adoc[]
***
=== [Code 코드목록 조회]
==== [HTTP REQUEST INFO]
include::{snippets}/com/code/code/http-request.adoc[]
include::{snippets}/com/code/code/query-parameters.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/com/code/code/http-response.adoc[]
include::{snippets}/com/code/code/response-fields.adoc[]
***
=== [Code 그룹목록 조회]
==== [HTTP REQUEST INFO]
include::{snippets}/com/code/group/http-request.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/com/code/group/http-response.adoc[]
include::{snippets}/com/code/group/response-fields.adoc[]
***
=== [Code 그룹 등록]
==== [HTTP REQUEST INFO]
include::{snippets}/com/code/group/create/http-request.adoc[]
include::{snippets}/com/code/group/create/request-fields.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/com/code/group/create/http-response.adoc[]
include::{snippets}/com/code/group/create/response-fields.adoc[]
***
=== [Code 코드 등록]
==== [HTTP REQUEST INFO]
include::{snippets}/com/code/code/create/http-request.adoc[]
include::{snippets}/com/code/code/create/request-fields.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/com/code/code/create/http-response.adoc[]
include::{snippets}/com/code/code/create/response-fields.adoc[]
***
=== [Code 코드언어 등록]
==== [HTTP REQUEST INFO]
include::{snippets}/com/code/lang/create/http-request.adoc[]
include::{snippets}/com/code/lang/create/request-fields.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/com/code/lang/create/http-response.adoc[]
include::{snippets}/com/code/lang/create/response-fields.adoc[]
***
=== [Code 그룹 수정]
==== [HTTP REQUEST INFO]
include::{snippets}/com/code/group/update/http-request.adoc[]
include::{snippets}/com/code/group/update/request-fields.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/com/code/group/update/http-response.adoc[]
include::{snippets}/com/code/group/update/response-fields.adoc[]
***
=== [Code 코드 수정]
==== [HTTP REQUEST INFO]
include::{snippets}/com/code/code/update/http-request.adoc[]
include::{snippets}/com/code/code/update/request-fields.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/com/code/code/update/http-response.adoc[]
include::{snippets}/com/code/code/update/response-fields.adoc[]
***
=== [Code 코드언어 수정]
==== [HTTP REQUEST INFO]
include::{snippets}/com/code/lang/update/http-request.adoc[]
include::{snippets}/com/code/lang/update/request-fields.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/com/code/lang/update/http-response.adoc[]
include::{snippets}/com/code/lang/update/response-fields.adoc[]
***
=== [Code 그룹 삭제]
==== [HTTP REQUEST INFO]
include::{snippets}/com/code/group/delete/http-request.adoc[]
include::{snippets}/com/code/group/delete/query-parameters.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/com/code/group/delete/http-response.adoc[]
***
=== [Code 코드 삭제]
==== [HTTP REQUEST INFO]
include::{snippets}/com/code/code/delete/http-request.adoc[]
include::{snippets}/com/code/code/delete/query-parameters.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/com/code/code/delete/http-response.adoc[]
***
=== [Code 언어 삭제]
==== [HTTP REQUEST INFO]
include::{snippets}/com/code/lang/delete/http-request.adoc[]
include::{snippets}/com/code/lang/delete/query-parameters.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/com/code/lang/delete/http-response.adoc[]
***
[[User-Account-API]]
== User-Account API
=== [User 회원가입]
==== [HTTP REQUEST INFO]
include::{snippets}/user/account/register/http-request.adoc[]
include::{snippets}/user/account/register/request-fields.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/user/account/register/http-response.adoc[]
***
=== [User 회원탈퇴]
==== [HTTP REQUEST INFO]
include::{snippets}/user/account/delete/http-request.adoc[]
include::{snippets}/user/account/delete/request-headers.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/user/account/delete/http-response.adoc[]
***
=== [User 회원정보 조회]
==== [HTTP REQUEST INFO]
include::{snippets}/user/account/profile/http-request.adoc[]
include::{snippets}/user/account/profile/request-headers.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/user/account/profile/http-response.adoc[]
include::{snippets}/user/account/profile/response-fields.adoc[]
***
=== [User 회원암호 변경]
==== [HTTP REQUEST INFO]
include::{snippets}/user/account/update/pswd/http-request.adoc[]
include::{snippets}/user/account/update/pswd/request-headers.adoc[]
include::{snippets}/user/account/update/pswd/request-fields.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/user/account/update/pswd/http-response.adoc[]
***
=== [User 회원정보 변경]
==== [HTTP REQUEST INFO]
include::{snippets}/user/account/update/http-request.adoc[]
include::{snippets}/user/account/update/request-headers.adoc[]
include::{snippets}/user/account/update/request-fields.adoc[]
==== [HTTP RESPONSE INFO]
include::{snippets}/user/account/update/http-response.adoc[]
***

BIN
app/kac-app/src/main/.DS_Store vendored

Binary file not shown.

BIN
app/kac-app/src/main/java/.DS_Store vendored

Binary file not shown.

3
app/kac-app/src/main/java/kr/co/palnet/kac/app/KacAppApplication.java

@ -7,7 +7,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages = { @SpringBootApplication(scanBasePackages = {
"kr.co.palnet.kac.app", "kr.co.palnet.kac.app",
"kr.co.palnet.kac.data", "kr.co.palnet.kac.data",
"kr.co.palnet.kac.api" "kr.co.palnet.kac.api",
"kr.co.palnet.kac.config"
}) })
public class KacAppApplication { public class KacAppApplication {
public static void main(String[] args) { public static void main(String[] args) {

26
app/kac-app/src/main/java/kr/co/palnet/kac/app/config/MessageSourceConfig.java

@ -0,0 +1,26 @@
package kr.co.palnet.kac.app.config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
@Configuration
public class MessageSourceConfig {
@Bean(name = "errorMessageSource")
public MessageSource getErrorMessageSource() {
ReloadableResourceBundleMessageSource errorMessageSource = new ReloadableResourceBundleMessageSource();
errorMessageSource.setBasenames("classpath:messages/errors/error");
errorMessageSource.setDefaultEncoding("UTF-8");
errorMessageSource.setCacheSeconds(300);
return errorMessageSource;
}
@Bean(name = "errorMessageSourceAccessor")
public MessageSourceAccessor errorMessageSourceAccessor(@Qualifier("errorMessageSource") MessageSource errorMessageSource) {
return new MessageSourceAccessor(errorMessageSource);
}
}

112
app/kac-app/src/main/java/kr/co/palnet/kac/app/config/SwaggerConfig.java

@ -0,0 +1,112 @@
package kr.co.palnet.kac.app.config;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.List;
@Slf4j
@Configuration
public class SwaggerConfig {
// @Bean
// public Docket api() {
// return new Docket(DocumentationType.OAS_30) // open api spec 3.0
// .apiInfo(new ApiInfoBuilder().version("1.0").title("PAV").build())
// .forCodeGeneration(true).securitySchemes(Arrays.asList(apiKey()))
// .select()
// .apis(RequestHandlerSelectors.any())
// .paths(PathSelectors.any())
// .build()
// .apiInfo(apiInfo())
// .directModelSubstitute(Date.class, String.class)
// .directModelSubstitute(LocalDate.class, String.class)
// .directModelSubstitute(LocalDateTime.class, String.class)
// .directModelSubstitute(Pageable.class, SwaggerPageable.class)
// .securityContexts(Arrays.asList(securityContext()))
// .securitySchemes(Arrays.asList(apiKey()));
// }
//
//
// private ApiInfo apiInfo() {
// return new ApiInfoBuilder()
// .title("PAV API")
// .description("----")
// .version("1.0")
// .build();
// }
//
// //ApiKey 정의
// private ApiKey apiKey() {
// return new ApiKey("Authorization", "Authorization", "header");
// }
//
// //JWT SecurityContext 구성
// private SecurityContext securityContext() {
// return SecurityContext.builder().securityReferences(defaultAuth()).build();
// }
//
// private List<SecurityReference> defaultAuth() {
// AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEveryThing");
// AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
// authorizationScopes[0] = authorizationScope;
// return Arrays.asList(new SecurityReference("Authorization", authorizationScopes));
// }
private static final String BEARER_TOKEN_PREFIX = "palnet";
@Bean
public OpenAPI openAPI() {
final String securitySchemeName = "BearerAuth";
SecurityRequirement securityRequirement = new SecurityRequirement().addList(securitySchemeName, List.of("read", "write"));
Components components = new Components()
.addSecuritySchemes(securitySchemeName, new SecurityScheme()
.type(SecurityScheme.Type.APIKEY)
.in(SecurityScheme.In.HEADER)
.name("Authorization")
.description("prefix add 'palnet ' + token")
);
// Swagger UI 접속 후, 딱 한 번만 accessToken을 입력해주면 모든 API에 토큰 인증 작업이 적용됩니다.
return new OpenAPI()
.addSecurityItem(securityRequirement)
.components(components)
.info(new Info()
.title("PAV API")
.version("1.0")
.description("PAV API")
);
}
@Bean
public GroupedOpenApi commonCode() {
return GroupedOpenApi.builder()
.group("공통-코드")
.pathsToMatch("/v1/com/code/**")
.build();
}
@Bean
public GroupedOpenApi selectAll() {
return GroupedOpenApi.builder()
.group("All")
.pathsToMatch("/**")
.build();
}
}

19
app/kac-app/src/main/java/kr/co/palnet/kac/app/config/WebConfig.java

@ -0,0 +1,19 @@
package kr.co.palnet.kac.app.config;
import kr.co.palnet.kac.app.core.web.BaseAcceptHeaderLocaleResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import java.util.Locale;
@Configuration
public class WebConfig {
@Bean
public LocaleResolver localeResolver() {
AcceptHeaderLocaleResolver localeResolver = new BaseAcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(Locale.KOREA);
return localeResolver;
}
}

132
app/kac-app/src/main/java/kr/co/palnet/kac/app/core/exception/ServerExceptionHandler.java

@ -0,0 +1,132 @@
package kr.co.palnet.kac.app.core.exception;
import kr.co.palnet.kac.core.exception.BaseErrorCode;
import kr.co.palnet.kac.core.exception.BaseException;
import kr.co.palnet.kac.core.exception.Level;
import kr.co.palnet.kac.core.exception.model.BaseErrorModel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.resource.NoResourceFoundException;
import java.time.Instant;
@Slf4j
@RequiredArgsConstructor
@RestControllerAdvice
public class ServerExceptionHandler {
@Qualifier("errorMessageSourceAccessor")
private final MessageSourceAccessor errorMessageSourceAccessor;
@ExceptionHandler(BaseException.class)
public ResponseEntity<BaseErrorModel> appExceptionHandle(BaseException e) {
BaseErrorCode errorType = e.getErrorCode();
BaseErrorModel baseBody = new BaseErrorModel();
baseBody.setTimestamp(Instant.now());
baseBody.setStatus(errorType.status().value());
baseBody.setError(errorType.status().getReasonPhrase());
baseBody.setCode(errorType.code());
baseBody.setMessage(this.getMessage(errorType));
baseBody.setPath(this.getUrl());
this.printLog(e);
return ResponseEntity.status(errorType.status()).body(baseBody);
}
@ExceptionHandler(NoResourceFoundException.class)
public ResponseEntity<BaseErrorModel> noResourceFoundException(NoResourceFoundException e) {
BaseErrorModel baseBody = new BaseErrorModel();
baseBody.setTimestamp(Instant.now());
baseBody.setStatus(e.getBody().getStatus());
baseBody.setError(e.getBody().getDetail());
baseBody.setCode(BaseErrorCode.WEB_NOT_FOUND.code());
baseBody.setMessage(this.getMessage(BaseErrorCode.WEB_NOT_FOUND));
baseBody.setPath(e.getResourcePath());
log.warn("", e);
return ResponseEntity.status(e.getBody().getStatus()).body(baseBody);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<BaseErrorModel> exceptionHandle(Exception e) {
BaseErrorCode errorType = BaseErrorCode.UNKNOWN;
BaseErrorModel baseBody = new BaseErrorModel();
baseBody.setTimestamp(Instant.now());
baseBody.setStatus(errorType.status().value());
baseBody.setError(errorType.status().getReasonPhrase());
baseBody.setCode(errorType.code());
baseBody.setMessage(this.getMessage(errorType));
baseBody.setPath(this.getUrl());
log.error("", e);
return ResponseEntity.status(errorType.status()).body(baseBody);
}
private String getUrl() {
ServletRequestAttributes servletRequestAttr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (servletRequestAttr != null) return servletRequestAttr.getRequest().getRequestURI();
else return null;
}
private String getMessage(BaseErrorCode e) {
String message = null;
try {
// message = errorMessageSourceAccessor.getMessage(e.code(), LocaleContextHolder.getLocale());
message = errorMessageSourceAccessor.getMessage(e.code());
} catch (NoSuchMessageException noSuchMessageException) {
message = "관리자에게 문의해주세요.";
}
return message;
}
private void printLog(BaseException e) {
Level level = e.getLevel();
String message = e.getLogMessage() == null ? e.getMessage() : e.getLogMessage();
Object[] paramArray = e.getParamArray();
switch (level) {
case TRACE:
log.trace("message: {}, params: {}, trace: {}", message, paramArray, e.getStackTrace());
log.trace("", e);
break;
case DEBUG:
log.debug("message: {}, params: {}, trace: {}", message, paramArray, e.getStackTrace());
log.debug("", e);
break;
case INFO:
log.info("message: {}, params: {}, trace: {}", message, paramArray, e.getStackTrace());
log.info("", e);
break;
case WARN:
log.warn("message: {}, params: {}, trace: {}", message, paramArray, e.getStackTrace());
log.warn("", e);
break;
case ERROR:
log.trace("message: {}, params: {}, trace: {}", message, paramArray, e.getStackTrace());
log.error("", e);
break;
default:
break;
}
}
}

60
app/kac-app/src/main/java/kr/co/palnet/kac/app/core/security/AppSecurityConfig.java

@ -0,0 +1,60 @@
package kr.co.palnet.kac.app.core.security;
import kr.co.palnet.kac.config.security.SecurityConfig;
import kr.co.palnet.kac.config.security.exception.BaseAccessDeniedHandler;
import kr.co.palnet.kac.config.security.exception.BaseAuthenticationEntryPoint;
import kr.co.palnet.kac.config.security.service.BaseUserDetailsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
@EnableWebSecurity
@Configuration
public class AppSecurityConfig extends SecurityConfig {
// 시큐리티 적용 안하는 URL 목록
private final String[] IGNORE_URL = {
"/v1/**",
"/v1/user/account/register",
};
// 권한(ROLE)별 URL
private final String[] USER_URL = {
};
public AppSecurityConfig(BaseUserDetailsService baseUserDetailsService, BaseAuthenticationEntryPoint baseAuthenticationEntryPoint, BaseAccessDeniedHandler baseAccessDeniedHandler) {
super(baseUserDetailsService, baseAuthenticationEntryPoint, baseAccessDeniedHandler);
}
@Override
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// 기본 security 설정을 불러온다.
this.setDefaultHttpSecurity(http);
// 여기서는 role별 허용 url 설정을 한다.
http
.securityMatchers(matchers -> matchers.requestMatchers("/**"))
.authorizeHttpRequests(authz ->
authz
.requestMatchers(USER_URL).hasRole("USER")
.anyRequest().authenticated()
)
;
return http.build();
}
// security filter 제외 - permission all
@Override
protected List<String> getExcludeURI() {
return new ArrayList<>(Arrays.asList(IGNORE_URL));
}
}

68
app/kac-app/src/main/java/kr/co/palnet/kac/app/core/web/BaseAcceptHeaderLocaleResolver.java

@ -0,0 +1,68 @@
package kr.co.palnet.kac.app.core.web;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@Slf4j
public class BaseAcceptHeaderLocaleResolver extends AcceptHeaderLocaleResolver {
private final List<Locale> LOCALES = Arrays.asList(
new Locale("ko"),
new Locale("ko", "KR"),
new Locale("en"),
new Locale("en", "US")
);
private final String LOCALE_HEADER_KEY = "Accept-Language";
/**
* resolve locale 구성
*
* @param request the request to resolve the locale for
* @return
*/
@Override
public Locale resolveLocale(HttpServletRequest request) {
if (!StringUtils.hasText(request.getHeader(LOCALE_HEADER_KEY))) {
return this.getDefaultLocale();
}
try {
Locale locale = LOCALES.stream().filter(_locale -> {
String defaultLocale = _locale.toString()
.replaceAll("-", "")
.replaceAll("_", "")
.toLowerCase();
String headerLocale = request.getHeader(LOCALE_HEADER_KEY).toString()
.replaceAll("-", "")
.replaceAll("_", "")
.toLowerCase();
return defaultLocale.equals(headerLocale);
}).findFirst().orElse(null);
if (locale == null) {
locale = LOCALES.stream()
.filter(_locale -> {
String language = _locale.getLanguage();
return request.getHeader(LOCALE_HEADER_KEY).contains(language);
})
.map(_locale -> {
String language = _locale.getLanguage();
return new Locale(language);
})
.distinct()
.findFirst().orElse(Locale.KOREAN);
}
// log.debug("{}, {}", request.getHeader(LOCALE_HEADER_KEY), locale);
return locale;
} catch (IllegalArgumentException e) {
log.warn("{}", e.getMessage());
return this.getDefaultLocale();
}
}
}

3
app/kac-app/src/main/java/kr/co/palnet/kac/app/ping/controller/PingController.java

@ -1,8 +1,10 @@
package kr.co.palnet.kac.app.ping.controller; package kr.co.palnet.kac.app.ping.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController @RestController
public class PingController { public class PingController {
@ -10,4 +12,5 @@ public class PingController {
public String ping() { public String ping() {
return "pong"; return "pong";
} }
} }

128
app/kac-app/src/main/java/kr/co/palnet/kac/app/ping/controller/TestErrorContoller.java

@ -0,0 +1,128 @@
package kr.co.palnet.kac.app.ping.controller;
import kr.co.palnet.kac.core.exception.BaseErrorCode;
import kr.co.palnet.kac.core.exception.BaseException;
import kr.co.palnet.kac.util.EncryptUtil;
import kr.co.palnet.kac.util.KisaEncryptUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@Slf4j
@RequiredArgsConstructor
@RequestMapping("/test")
@RestController
public class TestErrorContoller {
@Qualifier("errorMessageSource")
private final MessageSource errorMessageSource;
@Qualifier("errorMessageSourceAccessor")
private final MessageSourceAccessor errorMessageSourceAccessor;
@GetMapping("/encrypt/{plainText}")
public String ecrypt(@PathVariable String plainText) {
String encrypt = KisaEncryptUtil.CbcEncrypt.encrypt(plainText);
log.info("e : {}", encrypt);
String decrypt = KisaEncryptUtil.CbcEncrypt.decrypt(encrypt);
log.info("d : {}", decrypt);
String encrypt1 = EncryptUtil.encrypt(plainText);
log.info("e : {}", encrypt1);
String decrypt1 = EncryptUtil.decrypt(encrypt1);
log.info("d : {}", decrypt1);
return decrypt;
}
@GetMapping("/error/{caseNumber}")
public String errorTest(@PathVariable("caseNumber") Integer caseNumber) throws Exception {
log.info("{}", caseNumber);
return switch (caseNumber) {
case 1 -> throw new BaseException(BaseErrorCode.IO_ERROR);
case 2 -> throw new Exception("test");
default -> "success";
};
}
@GetMapping("/message/locale")
public Map<String, String> locale() {
Map<String, String> map = new HashMap<>();
map.put("message", errorMessageSourceAccessor.getMessage("TEST001"));
map.put("locale", LocaleContextHolder.getLocale().toString());
return map;
}
@GetMapping("/message/error")
public void messageSource() {
Map<String, String> map = new HashMap<>();
try {
String ko_KR = errorMessageSource.getMessage("TEST001", null, Locale.KOREA);
map.put("ko_KR", ko_KR);
} catch (Exception e) {
log.error("{}", e.getMessage());
}
try {
String ko = errorMessageSource.getMessage("TEST001", null, Locale.KOREAN);
map.put("ko", ko);
} catch (Exception e) {
log.error("{}", e.getMessage());
}
try {
String en = errorMessageSource.getMessage("TEST001", null, Locale.ENGLISH);
map.put("en", en);
} catch (Exception e) {
log.error("{}", e.getMessage());
}
try {
String en_US = errorMessageSource.getMessage("TEST001", null, Locale.US);
map.put("en_US", en_US);
} catch (Exception e) {
log.error("{}", e.getMessage());
}
log.info("==========================================================================================");
try {
String df = errorMessageSourceAccessor.getMessage("TEST001");
map.put("df", df);
} catch (Exception e) {
log.error("{}", e.getMessage());
}
try {
String str = errorMessageSourceAccessor.getMessage("TEST001", Locale.KOREAN);
map.put("s_ko", str);
} catch (Exception e) {
log.error("{}", e.getMessage());
}
try {
String str = errorMessageSourceAccessor.getMessage("TEST001", Locale.KOREA);
map.put("s_ko_kr", str);
} catch (Exception e) {
log.error("{}", e.getMessage());
}
try {
String str = errorMessageSourceAccessor.getMessage("TEST001", Locale.ENGLISH);
map.put("s_en", str);
} catch (Exception e) {
log.error("{}", e.getMessage());
}
try {
String str = errorMessageSourceAccessor.getMessage("TEST001", Locale.US);
map.put("s_en_us", str);
} catch (Exception e) {
log.error("{}", e.getMessage());
}
log.info("{}", map);
}
}

31
app/kac-app/src/main/java/kr/co/palnet/kac/app/ping/controller/TestSessionContrller.java

@ -0,0 +1,31 @@
package kr.co.palnet.kac.app.ping.controller;
import kr.co.palnet.kac.config.security.model.BaseUserDetails;
import kr.co.palnet.kac.config.security.util.SessionHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping("/test/session")
public class TestSessionContrller {
@GetMapping("/auth")
public void test() {
BaseUserDetails userInfo = SessionHelper.getUserInfo();
log.info("userInfo ::: {}", userInfo);
Long userNo = SessionHelper.getCstmrSno();
log.info("userNo ::: {}", userNo);
String userId = SessionHelper.getUserId();
log.info("userId ::: {}", userId);
boolean isRole1 = SessionHelper.hasRole("USER");
log.info("isRole1 ::: {}", isRole1);
boolean isRole2 = SessionHelper.hasRole("ADMIN");
log.info("isRole2 ::: {}", isRole2);
boolean isRole3 = SessionHelper.hasRole("ADMINasdfasdf");
log.info("isRole3 ::: {}", isRole3);
}
}

3
app/kac-app/src/main/java/lombok.config

@ -0,0 +1,3 @@
lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier
lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Value
lombok.anyConstructor.addConstructorProperties=true

41
app/kac-app/src/main/resources/application-swagger.yml

@ -0,0 +1,41 @@
springdoc:
api-docs:
path: /api-docs
groups:
enabled: true
# paths-to-exclude:
# - /api/v1/utm
# - /api/bas/flight/**
# - /api/ctr/cntrl/contains
# - /api/file/**
swagger-ui:
# 각 API의 그룹 표시 순서
# path, query, body, response 순으로 출력
path: /index.html
display-request-duration: true
groups-order: ASC
# 태그 정렬 순서.
# alpha: 알파벳 순 정렬
# method: OpenAPI specification file에 원하는 태그 정렬 방식 직접 기재
tags-sorter: alpha
# 컨트롤러 정렬 순서.
# method는 delete - get - patch - post - put 순으로 정렬된다.
# alpha를 사용해 알파벳 순으로 정렬할 수 있다.
operations-sorter: alpha
# Spring Actuator의 endpoint까지 보여줄 것인지?
show-actuator: false
# request media type 의 기본 값
default-consumes-media-type: application/json
# response media type 의 기본 값
default-produces-media-type: application/json
# Swagger UI에서 기본적으로 펼쳐져 보이는 경로의 수
doc-expansion : none

23
app/kac-app/src/main/resources/application.yml

@ -0,0 +1,23 @@
spring:
profiles:
include:
- swagger
- db
threads:
virtual:
enabled: true
logging:
level:
kr.co.palnet: DEBUG
com.com.zaxxer.hikari: INFO
jdbc:
audit: OFF
resultset: OFF
resultsettable: INFO #SQL 결과 데이터 Table을 로그로 남긴다.
sqlonly: OFF #SQL만 로그로 남긴다.
sqltiming: INFO #SQL과 소요시간을 표기한다.
connection : OFF # 커넥션 확인가능
org.hibernate:
SQL: DEBUG
type.descriptor.sql.BasicBinder: TRACE

2
app/kac-app/src/main/resources/log4jdbc.log4j2.properties

@ -0,0 +1,2 @@
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
log4jdbc.dump.sql.maxlinelength=0

22
app/kac-app/src/main/resources/messages/errors/error.properties

@ -0,0 +1,22 @@
CM001=\uC131\uACF5\uC785\uB2C8\uB2E4.
CM900=\uC54C \uC218 \uC5C6\uB294 \uC624\uB958\uC785\uB2C8\uB2E4.
CM999=\uC2E4\uD328\uC785\uB2C8\uB2E4.
CM002=\uC694\uCCAD\uD558\uC2E0 \uB0B4\uC6A9\uC774 \uCC98\uB9AC \uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
CM003=\uC785\uCD9C\uB825 \uC624\uB958\uC785\uB2C8\uB2E4.
CM100=\uB85C\uADF8\uC778\uC744 \uB2E4\uC2DC \uD574\uC8FC\uC138\uC694.
CM101=\uC774\uBBF8 \uB85C\uADF8\uC778\uD55C \uC0AC\uC6A9\uC790\uC785\uB2C8\uB2E4.
CM102=\uB85C\uADF8\uC778 \uC2DC\uB3C4\uAC00 \uC815\uD574\uC9C4 \uD69F\uC218\uB97C \uCD08\uACFC\uD558\uC600\uC2B5\uB2C8\uB2E4.
CM110=SNS \uB85C\uADF8\uC778\uC744 \uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.
CM111=\uC774\uBBF8 \uAC00\uC785\uB41C SNS \uACC4\uC815\uC785\uB2C8\uB2E4.
CM120=\uD1A0\uD070\uC774 \uB9CC\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
CM121=\uC798\uBABB\uB41C \uD1A0\uD070\uC785\uB2C8\uB2E4.
CM130=\uC0AC\uC6A9\uC790\uC758 \uACC4\uC815\uC774 \uC815\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
CM131=\uC0AC\uC6A9\uC790\uC758 \uACC4\uC815\uC774 \uD734\uBA74\uC0C1\uD0DC\uC785\uB2C8\uB2E4.
CM200=\uCE90\uC2DC \uB85C\uB529\uC5D0 \uC2E4\uD328\uD558\uC600\uC2B5\uB2C8\uB2E4.
CM201=\uCE90\uC2DC \uB9AC\uB85C\uB529\uC5D0 \uC2E4\uD328\uD558\uC600\uC2B5\uB2C8\uB2E4.
CM401=\uC0AC\uC6A9\uC790\uC758 \uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.
WB400=\uD30C\uB77C\uBBF8\uD130\uB97C \uB2E4\uC2DC \uD655\uC778 \uD6C4 \uC694\uCCAD\uD574\uC8FC\uC138\uC694.
WB500=\uC678\uBD80 \uC5F0\uB3D9 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD558\uC600\uC2B5\uB2C8\uB2E4.
WB404=\uC694\uCCAD\uD558\uC2E0 URL\uC774 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.
DT001=\uC774\uBBF8 \uB4F1\uB85D\uB41C \uB370\uC774\uD130 \uC785\uB2C8\uB2E4.
DT002=\uC694\uCCAD\uD55C \uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.

22
app/kac-app/src/main/resources/messages/errors/error_en.properties

@ -0,0 +1,22 @@
CM001=It's a success.
CM900=Unknown error.
CM999=It's a failure.
CM002=Your request has not been processed.
CM003=Input/output error.
CM100=Please log in again.
CM101=This is a user who has already logged in.
CM102=The login attempt exceeded the specified number of times.
CM110=I can't log in to SNS.
CM111=This is an SNS account that has already been subscribed.
CM120=The token has expired.
CM121=Invalid token.
CM130=Your account has been suspended.
CM131=Your account is dormant.
CM200=Cache loading failed.
CM201=Cache reloading failed.
CM401=You do not have permissions.
WB400=Please check the parameters again and request them.
WB500=External interlocking error occurred.
WB404=The URL you requested does not exist.
DT001=Data already registered.
DT002=No data requested.

2244
app/kac-app/src/main/resources/static/docs/index.html

File diff suppressed because it is too large Load Diff

119
app/kac-app/src/test/java/kr/co/palnet/kac/BaseTest.java

@ -0,0 +1,119 @@
package kr.co.palnet.kac;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException;
import kr.co.palnet.kac.api.v1.user.account.model.detail.SearchUserRS;
import kr.co.palnet.kac.api.v1.user.account.model.register.FormRegisterRQ;
import kr.co.palnet.kac.api.v1.user.account.service.UserAccountService;
import kr.co.palnet.kac.app.KacAppApplication;
import kr.co.palnet.kac.config.security.model.BaseUserDetails;
import kr.co.palnet.kac.config.security.service.BaseUserDetailsService;
import kr.co.palnet.kac.config.security.util.JwtUtil;
import kr.co.palnet.kac.util.ObjectMapperUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockFilterConfig;
import org.springframework.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.RestDocumentationExtension;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.security.config.BeanIds;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.DelegatingFilterProxy;
import java.time.LocalDate;
import java.time.LocalDateTime;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.modifyUris;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
@SpringBootTest(classes = KacAppApplication.class)
@ExtendWith({RestDocumentationExtension.class})
public class BaseTest {
@Autowired
protected WebApplicationContext webApplicationContext;
@Autowired
protected UserAccountService userAccountService;
@Autowired
protected BaseUserDetailsService baseUserDetailsService;
public MockMvc mockMvc;
protected final String CREATE_PASSWORD = "palnet!234";
@BeforeEach
public void setUpAll(RestDocumentationContextProvider restDocumentationContextProvider) throws ServletException {
DelegatingFilterProxy delegateProxyFilter = new DelegatingFilterProxy();
delegateProxyFilter.init(new MockFilterConfig(webApplicationContext.getServletContext(), BeanIds.SPRING_SECURITY_FILTER_CHAIN));
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) // @Autowired로 빈주입 받은 context
.addFilters(new CharacterEncodingFilter("UTF-8", true), delegateProxyFilter) // UTF-8 인코딩 필터, SecurityFilter
.apply(
MockMvcRestDocumentation.documentationConfiguration(restDocumentationContextProvider)
.operationPreprocessors()
.withRequestDefaults(
modifyUris().scheme("http").host("localhost").port(8080), prettyPrint() // URL 정보를 넣어주시면 됩니다.
)
.withResponseDefaults(
prettyPrint()
)
)
.build();
}
protected String getUserToken(){
String username = "TEST_" + System.currentTimeMillis();
String jsonRQ = """
{
"cstrmDivCd" : "MEMBER",
"cstrmStatusCd" : "ACTIVE",
"userId" : "%s",
"authId" : "USER",
"siteCode" : "DRONE",
"userPswd" : "%s",
"joinCrtfyCd" : "HP_CRTFD",
"memberName" : "이경도",
"brthdyDate" : "1999-09-07",
"email" : "lkd9125@naver.com",
"hpno" : "01083703435",
"clncd" : "+82"
}
""".formatted(username, this.CREATE_PASSWORD);
FormRegisterRQ rq = new FormRegisterRQ();
rq.setCstrmDivCd("MEMBER");
rq.setCstrmStatusCd("ACTIVE");
rq.setUserId(username);
rq.setAuthId("USER");
rq.setSiteCode("DRONE");
rq.setUserPswd("palnet!234");
rq.setJoinCrtfyCd("HP_CRTFD");
rq.setMemberName("이경도");
rq.setBrthdyDate(LocalDate.of(1999, 9, 7));
rq.setEmail("lkd9125@naver.com");
rq.setHpno("01083703435");
rq.setClncd("+82");
try{
userAccountService.createUser(rq);
} catch (Exception e){
e.printStackTrace();
}
BaseUserDetails userDetails = (BaseUserDetails) baseUserDetailsService.loadUserByUsername(username);
return JwtUtil.makeAuthToken(userDetails);
}
}

600
app/kac-app/src/test/java/kr/co/palnet/kac/com/code/ComnCodeControllerTest.java

@ -0,0 +1,600 @@
package kr.co.palnet.kac.com.code;
import kr.co.palnet.kac.BaseTest;
import kr.co.palnet.kac.api.v1.common.code.model.FormCodeGroupRQ;
import kr.co.palnet.kac.api.v1.common.code.model.FormCodeLangRQ;
import kr.co.palnet.kac.api.v1.common.code.model.FormCodeRQ;
import kr.co.palnet.kac.api.v1.common.code.service.ComCodeService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.restdocs.payload.PayloadDocumentation.*;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.queryParameters;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public class ComnCodeControllerTest extends BaseTest {
@Autowired
private ComCodeService comCodeService;
private final String BASE_URL = "/v1/com/code";
@DisplayName("언어코드 삭제")
@Test
public void deleteLang() throws Exception {
String groupCd = "NEW_GROUP001";
String cdId = "NEW_CODE001";
String langDivCd = "ko_KR";
this.mockMvc.perform(
delete(this.BASE_URL + "/lang?groupCd=" + groupCd + "&cdId=" + cdId + "&langDivCd=" + langDivCd)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andDo(print())
.andDo(
document(
"com/code/lang/delete", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()),
queryParameters(
parameterWithName("groupCd").description("그룹 아이디"),
parameterWithName("cdId").description("코드 아이디"),
parameterWithName("langDivCd").description("삭제할 언어코드")
)
)
)
.andExpect(status().isOk());
}
@DisplayName("코드 삭제")
@Test
public void deleteCode() throws Exception {
String groupCd = "NEW_GROUP001";
String cdId = "NEW_CODE001";
this.mockMvc.perform(
delete(this.BASE_URL + "/code?groupCd=" + groupCd + "&cdId=" + cdId)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andDo(print())
.andDo(
document(
"com/code/code/delete", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()),
queryParameters(
parameterWithName("groupCd").description("그룹 아이디"),
parameterWithName("cdId").description("코드 아이디")
)
)
)
.andExpect(status().isOk());
}
@DisplayName("그룹 삭제")
@Test
public void deleteCodeGroup() throws Exception {
String deleteGroupCd = "NEW_GROUP001";
this.mockMvc.perform(
delete(this.BASE_URL + "/group?groupCd=" + deleteGroupCd)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andDo(print())
.andDo(
document(
"com/code/group/delete", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()),
queryParameters(
parameterWithName("groupCd").description("그룹 아이디")
)
)
)
.andExpect(status().isOk());
}
@DisplayName("코드의 언어코드 수정")
@Test
@Transactional
public void updateCodeLang() throws Exception {
String randomNm = "NEW_GROUP_" + System.currentTimeMillis();
randomNm = randomNm.substring(0, 20);
FormCodeGroupRQ groupRq = FormCodeGroupRQ.builder().groupCd(randomNm).siteCd("KAC").groupCdNm("신규그룹001").rm("비고....").build();
comCodeService.createCodeGroup(groupRq);
FormCodeRQ codeRq = FormCodeRQ.builder().groupCd(randomNm).cdId("NEW_CODE001").upperCd(null).sortOrdr(0).addInfoValue("추가!!").useYn("Y").build();
comCodeService.createCode(codeRq);
FormCodeLangRQ langRq = FormCodeLangRQ.builder().groupCd(randomNm).cdId("NEW_CODE001").langDivCd("ko_KR").cdNm("신규코드001").rm("비고....").build();
comCodeService.createCodeLang(langRq);
String jsonRQ = """
{
"groupCd": "%s",
"cdId": "NEW_CODE001",
"langDivCd": "ko_KR",
"cdNm": "신규코드001",
"rm": "수정..."
}
""".formatted(randomNm);
this.mockMvc.perform(
put(this.BASE_URL + "/lang")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(jsonRQ)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andDo(print())
.andDo(
document(
"com/code/lang/update", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()),
requestFields(
fieldWithPath("groupCd").type(JsonFieldType.STRING).description("그룹코드"),
fieldWithPath("cdId").type(JsonFieldType.STRING).description("코드 아이디"),
fieldWithPath("langDivCd").type(JsonFieldType.STRING).description("언어코드"),
fieldWithPath("cdNm").type(JsonFieldType.STRING).description("코드이름[언어별]"),
fieldWithPath("rm").type(JsonFieldType.STRING).description("비고")
),
responseFields(
fieldWithPath("groupCd").type(JsonFieldType.STRING).description("그룹코드"),
fieldWithPath("cdId").type(JsonFieldType.STRING).description("코드 아이디"),
fieldWithPath("langDivCd").type(JsonFieldType.STRING).description("언어코드"),
fieldWithPath("cdNm").type(JsonFieldType.STRING).description("코드이름[언어별]"),
fieldWithPath("rm").type(JsonFieldType.STRING).description("비고"),
fieldWithPath("createUserId").type(JsonFieldType.STRING).description("등록한 유저 아이디"),
fieldWithPath("createDt").type(JsonFieldType.STRING).description("등록일시"),
fieldWithPath("updateUserId").type(JsonFieldType.STRING).description("수정한 유저 아이디"),
fieldWithPath("updateDt").type(JsonFieldType.STRING).description("수정일시")
)
)
)
.andExpect(status().isOk());
}
@DisplayName("코드 수정")
@Test
@Transactional
public void updateCode() throws Exception {
String randomNm = "NEW_GROUP_" + System.currentTimeMillis();
randomNm = randomNm.substring(0, 20);
FormCodeGroupRQ groupRq = FormCodeGroupRQ.builder().groupCd(randomNm).siteCd("KAC").groupCdNm("신규그룹001").rm("비고....").build();
comCodeService.createCodeGroup(groupRq);
FormCodeRQ codeRq = FormCodeRQ.builder().groupCd(randomNm).cdId("NEW_CODE001").upperCd(null).sortOrdr(0).addInfoValue("추가!!").useYn("Y").build();
comCodeService.createCode(codeRq);
FormCodeLangRQ langRq = FormCodeLangRQ.builder().groupCd(randomNm).cdId("NEW_CODE001").langDivCd("ko_KR").cdNm("신규코드001").rm("비고....").build();
comCodeService.createCodeLang(langRq);
String jsonRQ = """
{
"groupCd": "%s",
"cdId": "NEW_CODE001",
"sortOrdr": 0,
"addInfoValue": "수정!!",
"useYn": "Y"
}
""".formatted(randomNm);
this.mockMvc.perform(
put(this.BASE_URL + "/code")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(jsonRQ)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andDo(print())
.andDo(
document(
"com/code/code/update", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()),
requestFields(
fieldWithPath("groupCd").type(JsonFieldType.STRING).description("그룹코드"),
fieldWithPath("cdId").type(JsonFieldType.STRING).description("코드 아이디"),
fieldWithPath("sortOrdr").type(JsonFieldType.NUMBER).description("정렬순서"),
fieldWithPath("addInfoValue").type(JsonFieldType.STRING).description("추가사항"),
fieldWithPath("useYn").type(JsonFieldType.STRING).description("사용여부")
),
responseFields(
fieldWithPath("groupCd").type(JsonFieldType.STRING).description("그룹코드"),
fieldWithPath("cdId").type(JsonFieldType.STRING).description("코드 아이디"),
fieldWithPath("upperCd").type(JsonFieldType.STRING).description("상위 아이디").optional(),
fieldWithPath("sortOrdr").type(JsonFieldType.NUMBER).description("정렬순서"),
fieldWithPath("addInfoValue").type(JsonFieldType.STRING).description("추가사항"),
fieldWithPath("useYn").type(JsonFieldType.STRING).description("사용여부"),
fieldWithPath("createUserId").type(JsonFieldType.STRING).description("등록한 유저 아이디"),
fieldWithPath("createDt").type(JsonFieldType.STRING).description("등록일시"),
fieldWithPath("updateUserId").type(JsonFieldType.STRING).description("수정한 유저 아이디"),
fieldWithPath("updateDt").type(JsonFieldType.STRING).description("수정일시")
)
)
)
.andExpect(status().isOk());
}
@DisplayName("그룹 수정")
@Test
@Transactional
public void updateCodeGroup() throws Exception {
String randomNm = "NEW_GROUP_" + System.currentTimeMillis();
randomNm = randomNm.substring(0, 20);
FormCodeGroupRQ groupRq = FormCodeGroupRQ.builder().groupCd(randomNm).siteCd("KAC").groupCdNm("신규그룹001").rm("비고....").build();
comCodeService.createCodeGroup(groupRq);
String jsonRQ = """
{
"groupCd": "%s",
"siteCd": "KAC",
"groupCdNm": "신규그룹001",
"rm": "비고...."
}
""".formatted(randomNm);
this.mockMvc.perform(
put(this.BASE_URL + "/group")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(jsonRQ)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andDo(print())
.andDo(
document(
"com/code/group/update", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()),
requestFields(
fieldWithPath("groupCd").type(JsonFieldType.STRING).description("그룹코드"),
fieldWithPath("siteCd").type(JsonFieldType.STRING).description("사이트코드"),
fieldWithPath("groupCdNm").type(JsonFieldType.STRING).description("그룹이름"),
fieldWithPath("rm").type(JsonFieldType.STRING).description("비고")
),
responseFields(
fieldWithPath("groupCd").type(JsonFieldType.STRING).description("그룹코드"),
fieldWithPath("siteCd").type(JsonFieldType.STRING).description("사이트코드"),
fieldWithPath("groupCdNm").type(JsonFieldType.STRING).description("그룹이름"),
fieldWithPath("rm").type(JsonFieldType.STRING).description("비고"),
fieldWithPath("createUserId").type(JsonFieldType.STRING).description("등록한 유저 아이디"),
fieldWithPath("createDt").type(JsonFieldType.STRING).description("등록일시"),
fieldWithPath("updateUserId").type(JsonFieldType.STRING).description("수정한 유저 아이디"),
fieldWithPath("updateDt").type(JsonFieldType.STRING).description("수정일시")
)
)
)
.andExpect(status().isOk());
}
@DisplayName("코드의 언어코드 추가")
@Test
@Transactional
public void createCodeLang() throws Exception {
String langDivCd = "ko_KR";
String randomNm = "NEW_GROUP_" + System.currentTimeMillis();
randomNm = randomNm.substring(0, 20);
FormCodeGroupRQ groupRq = FormCodeGroupRQ.builder().groupCd(randomNm).siteCd("KAC").groupCdNm("신규그룹001").rm("비고....").build();
comCodeService.createCodeGroup(groupRq);
FormCodeRQ codeRq = FormCodeRQ.builder().groupCd(randomNm).cdId("NEW_CODE001").upperCd(null).sortOrdr(0).addInfoValue("추가!!").useYn("Y").build();
comCodeService.createCode(codeRq);
String jsonRQ = """
{
"groupCd": "%s",
"cdId": "NEW_CODE001",
"langDivCd": "%s",
"cdNm": "신규코드001",
"rm": "비고...."
}
""".formatted(randomNm, langDivCd);
this.mockMvc.perform(
post(this.BASE_URL + "/lang")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(jsonRQ)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andDo(print())
.andDo(
document(
"com/code/lang/create", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()),
requestFields(
fieldWithPath("groupCd").type(JsonFieldType.STRING).description("그룹코드"),
fieldWithPath("cdId").type(JsonFieldType.STRING).description("코드 아이디"),
fieldWithPath("langDivCd").type(JsonFieldType.STRING).description("언어코드"),
fieldWithPath("cdNm").type(JsonFieldType.STRING).description("코드이름[언어별]"),
fieldWithPath("rm").type(JsonFieldType.STRING).description("비고")
),
responseFields(
fieldWithPath("groupCd").type(JsonFieldType.STRING).description("그룹코드"),
fieldWithPath("cdId").type(JsonFieldType.STRING).description("코드 아이디"),
fieldWithPath("langDivCd").type(JsonFieldType.STRING).description("언어코드"),
fieldWithPath("cdNm").type(JsonFieldType.STRING).description("코드이름[언어별]"),
fieldWithPath("rm").type(JsonFieldType.STRING).description("비고"),
fieldWithPath("createUserId").type(JsonFieldType.STRING).description("등록한 유저 아이디"),
fieldWithPath("createDt").type(JsonFieldType.STRING).description("등록일시"),
fieldWithPath("updateUserId").type(JsonFieldType.STRING).description("수정한 유저 아이디"),
fieldWithPath("updateDt").type(JsonFieldType.STRING).description("수정일시")
)
)
)
.andExpect(status().isOk());
}
@DisplayName("코드 추가")
@Test
@Transactional
public void createCode() throws Exception {
String codeNm = "NEW_CODE001";
String randomNm = "NEW_GROUP_" + System.currentTimeMillis();
randomNm = randomNm.substring(0, 20);
FormCodeGroupRQ groupRq = FormCodeGroupRQ.builder().groupCd(randomNm).siteCd("KAC").groupCdNm("신규그룹001").rm("비고....").build();
comCodeService.createCodeGroup(groupRq);
String jsonRQ = """
{
"groupCd": "%s",
"cdId": "%s",
"sortOrdr": 0,
"addInfoValue": "추가!!",
"useYn": "Y"
}
""".formatted(randomNm, codeNm);
this.mockMvc.perform(
post(this.BASE_URL + "/code")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(jsonRQ)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andDo(print())
.andDo(
document(
"com/code/code/create", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()),
requestFields(
fieldWithPath("groupCd").type(JsonFieldType.STRING).description("그룹코드"),
fieldWithPath("cdId").type(JsonFieldType.STRING).description("코드 아이디"),
fieldWithPath("sortOrdr").type(JsonFieldType.NUMBER).description("정렬순서"),
fieldWithPath("addInfoValue").type(JsonFieldType.STRING).description("추가사항"),
fieldWithPath("useYn").type(JsonFieldType.STRING).description("사용여부")
),
responseFields(
fieldWithPath("groupCd").type(JsonFieldType.STRING).description("그룹코드"),
fieldWithPath("cdId").type(JsonFieldType.STRING).description("코드 아이디"),
fieldWithPath("upperCd").type(JsonFieldType.STRING).description("상위 아이디").optional(),
fieldWithPath("sortOrdr").type(JsonFieldType.NUMBER).description("정렬순서"),
fieldWithPath("addInfoValue").type(JsonFieldType.STRING).description("추가사항"),
fieldWithPath("useYn").type(JsonFieldType.STRING).description("사용여부"),
fieldWithPath("createUserId").type(JsonFieldType.STRING).description("등록한 유저 아이디"),
fieldWithPath("createDt").type(JsonFieldType.STRING).description("등록일시"),
fieldWithPath("updateUserId").type(JsonFieldType.STRING).description("수정한 유저 아이디"),
fieldWithPath("updateDt").type(JsonFieldType.STRING).description("수정일시")
)
)
)
.andExpect(status().isOk());
}
@DisplayName("코드그룹 추가")
@Test
@Transactional
public void createCodeGroup() throws Exception {
String randomNm = "NEW_GROUP_" + System.currentTimeMillis();
randomNm = randomNm.substring(0, 20);
String jsonRQ = """
{
"groupCd": "%s",
"siteCd": "KAC",
"groupCdNm": "신규그룹001",
"rm": "비고...."
}
""".formatted(randomNm);
this.mockMvc.perform(
post(this.BASE_URL + "/group")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(jsonRQ)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andDo(print())
.andDo(
document(
"com/code/group/create", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()),
requestFields(
fieldWithPath("groupCd").type(JsonFieldType.STRING).description("그룹코드"),
fieldWithPath("siteCd").type(JsonFieldType.STRING).description("사이트코드"),
fieldWithPath("groupCdNm").type(JsonFieldType.STRING).description("그룹이름"),
fieldWithPath("rm").type(JsonFieldType.STRING).description("비고")
),
responseFields(
fieldWithPath("groupCd").type(JsonFieldType.STRING).description("그룹코드"),
fieldWithPath("siteCd").type(JsonFieldType.STRING).description("사이트코드"),
fieldWithPath("groupCdNm").type(JsonFieldType.STRING).description("그룹이름"),
fieldWithPath("rm").type(JsonFieldType.STRING).description("비고"),
fieldWithPath("createUserId").type(JsonFieldType.STRING).description("등록한 유저 아이디"),
fieldWithPath("createDt").type(JsonFieldType.STRING).description("등록일시"),
fieldWithPath("updateUserId").type(JsonFieldType.STRING).description("수정한 유저 아이디"),
fieldWithPath("updateDt").type(JsonFieldType.STRING).description("수정일시")
)
)
)
.andExpect(status().isOk());
}
@DisplayName("모든 코드 조회")
@Test
@Transactional(propagation = Propagation.SUPPORTS)
public void getAllCodeByGroup() throws Exception {
String randomNm = "NEW_GROUP_" + System.currentTimeMillis();
randomNm = randomNm.substring(0, 20);
FormCodeGroupRQ groupRq = FormCodeGroupRQ.builder().groupCd(randomNm).siteCd("KAC").groupCdNm("신규그룹001").rm("비고....").build();
comCodeService.createCodeGroup(groupRq);
FormCodeRQ codeRq = FormCodeRQ.builder().groupCd(randomNm).cdId("NEW_CODE001").upperCd(null).sortOrdr(0).addInfoValue("추가!!").useYn("Y").build();
comCodeService.createCode(codeRq);
FormCodeLangRQ langRq = FormCodeLangRQ.builder().groupCd(randomNm).cdId("NEW_CODE001").langDivCd("ko_KR").cdNm("신규코드001").rm("비고....").build();
comCodeService.createCodeLang(langRq);
String langDivCd = "ko_KR";
this.mockMvc.perform(
get(this.BASE_URL + "/code")
.param("groupCd", randomNm)
.param("langDivCd", langDivCd)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andDo(print())
.andDo(
document(
"com/code/code", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()),
queryParameters(
parameterWithName("groupCd").description("그룹코드"),
parameterWithName("langDivCd").description("언어코드")
),
responseFields(
fieldWithPath("[].groupCd").type(JsonFieldType.STRING).description("코드의 그룹").optional(),
fieldWithPath("[].cdId").type(JsonFieldType.STRING).description("코드의 ID").optional(),
fieldWithPath("[].cdNm").type(JsonFieldType.STRING).description("코드의 이름").optional(),
fieldWithPath("[].upperCd").type(JsonFieldType.STRING).description("상위 코드의 이름").optional(),
fieldWithPath("[].sortOrdr").type(JsonFieldType.NUMBER).description("코드의 정렬순서").optional(),
fieldWithPath("[].addInfoValue").type(JsonFieldType.STRING).description("코드의 추가 밸류").optional(),
fieldWithPath("[].children").type(JsonFieldType.STRING).description("코드의 하위요소").optional()
)
)
)
.andExpect(status().isOk());
// comCodeService.deleteLang(randomNm, "NEW_CODE001", "ko_KR");
// comCodeService.deleteCode(randomNm, "NEW_CODE001");
comCodeService.deleteCodeGroup(randomNm);
}
@DisplayName("모든 그룹과 코드 조회")
@Test
@Transactional
public void getAllGroupCode() throws Exception {
String randomNm = "NEW_GROUP_" + System.currentTimeMillis();
randomNm = randomNm.substring(0, 20);
FormCodeGroupRQ groupRq = FormCodeGroupRQ.builder().groupCd(randomNm).siteCd("KAC").groupCdNm("신규그룹001").rm("비고....").build();
comCodeService.createCodeGroup(groupRq);
FormCodeRQ codeRq = FormCodeRQ.builder().groupCd(randomNm).cdId("NEW_CODE001").upperCd(null).sortOrdr(0).addInfoValue("추가!!").useYn("Y").build();
comCodeService.createCode(codeRq);
FormCodeLangRQ langRq = FormCodeLangRQ.builder().groupCd(randomNm).cdId("NEW_CODE001").langDivCd("ko_KR").cdNm("신규코드001").rm("비고....").build();
comCodeService.createCodeLang(langRq);
this.mockMvc.perform(
get(this.BASE_URL + "/group")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andDo(print())
.andDo(
document(
"com/code/group", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()),
responseFields(
fieldWithPath("[].groupCd").type(JsonFieldType.STRING).description("그룹 코드").optional(),
fieldWithPath("[].siteCd").type(JsonFieldType.STRING).description("사이트 코드").optional(),
fieldWithPath("[].groupCdNm").type(JsonFieldType.STRING).description("그룹 명").optional(),
fieldWithPath("[].rm").type(JsonFieldType.STRING).description("비고").optional(),
fieldWithPath("[].codeList").type(JsonFieldType.ARRAY).description("그룹에 포함된 코드 리스트").optional()
)
)
)
.andExpect(status().isOk());
}
@DisplayName("모든 그룹 조회")
@Test
@Transactional
public void getAllGroup() throws Exception {
String randomNm = "NEW_GROUP_" + System.currentTimeMillis();
randomNm = randomNm.substring(0, 20);
FormCodeGroupRQ groupRq = FormCodeGroupRQ.builder().groupCd(randomNm).siteCd("KAC").groupCdNm("신규그룹001").rm("비고....").build();
comCodeService.createCodeGroup(groupRq);
FormCodeRQ codeRq = FormCodeRQ.builder().groupCd(randomNm).cdId("NEW_CODE001").upperCd(null).sortOrdr(0).addInfoValue("추가!!").useYn("Y").build();
comCodeService.createCode(codeRq);
FormCodeLangRQ langRq = FormCodeLangRQ.builder().groupCd(randomNm).cdId("NEW_CODE001").langDivCd("ko_KR").cdNm("신규코드001").rm("비고....").build();
comCodeService.createCodeLang(langRq);
String siteCd = "KAC";
String langDivCd = "ko_KR";
this.mockMvc.perform(
get(this.BASE_URL + "/all")
.param("siteCd", siteCd)
.param("langDivCd", langDivCd)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andDo(print())
.andDo(
document(
"com/code/all", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()),
queryParameters(
parameterWithName("siteCd").description("사이트코드"),
parameterWithName("langDivCd").description("언어코드")
),
responseFields(
fieldWithPath("[].groupCd").type(JsonFieldType.STRING).description("그룹 코드").optional(),
fieldWithPath("[].siteCd").type(JsonFieldType.STRING).description("사이트 코드").optional(),
fieldWithPath("[].groupCdNm").type(JsonFieldType.STRING).description("그룹 명").optional(),
fieldWithPath("[].rm").type(JsonFieldType.STRING).description("비고").optional(),
fieldWithPath("[].codeList").type(JsonFieldType.ARRAY).description("그룹에 포함된 코드 리스트").optional(),
fieldWithPath("[].codeList[].groupCd").type(JsonFieldType.STRING).description("코드의 그룹").optional(),
fieldWithPath("[].codeList[].cdId").type(JsonFieldType.STRING).description("코드의 ID").optional(),
fieldWithPath("[].codeList[].cdNm").type(JsonFieldType.STRING).description("코드의 이름").optional(),
fieldWithPath("[].codeList[].upperCd").type(JsonFieldType.STRING).description("상위 코드의 이름").optional(),
fieldWithPath("[].codeList[].sortOrdr").type(JsonFieldType.NUMBER).description("코드의 정렬순서").optional(),
fieldWithPath("[].codeList[].addInfoValue").type(JsonFieldType.STRING).description("코드의 추가 밸류").optional(),
fieldWithPath("[].codeList[].children").type(JsonFieldType.STRING).description("코드의 하위요소").optional()
)
)
)
.andExpect(status().isOk());
}
}

228
app/kac-app/src/test/java/kr/co/palnet/kac/user/account/UserAccountControllerTest.java

@ -0,0 +1,228 @@
package kr.co.palnet.kac.user.account;
import kr.co.palnet.kac.BaseTest;
import kr.co.palnet.kac.api.v1.user.account.service.UserAccountService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.restdocs.headers.HeaderDocumentation;
import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders;
import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.transaction.annotation.Transactional;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.restdocs.payload.PayloadDocumentation.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public class UserAccountControllerTest extends BaseTest {
@Autowired
private UserAccountService userAccountService;
private final String BASE_URL = "/v1/user/account";
private final String GRANT_TYPE = "Bearer";
@DisplayName("회원정보 변경")
@Test
@Transactional
public void updateUser() throws Exception{
String jsonRQ = """
{
"email" : "lkd9125@naver.com",
"hpno" : "01083703435"
}
""";
String token = this.getUserToken();
this.mockMvc.perform(
put(this.BASE_URL + "/update")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(jsonRQ)
.accept(MediaType.APPLICATION_JSON_VALUE)
.header("Authorization", GRANT_TYPE + " " + token)
)
.andDo(print())
.andDo(
document(
"user/account/update",
preprocessResponse(prettyPrint()),
HeaderDocumentation.requestHeaders(
HeaderDocumentation.headerWithName("Authorization").description("Access토큰 [로그인 발급]")
),
requestFields(
fieldWithPath("email").type(JsonFieldType.STRING).description("바꿀 이메일").optional(),
fieldWithPath("hpno").type(JsonFieldType.STRING).description("바꿀 전화번호").optional()
)
)
)
.andExpect(status().isOk());
}
@DisplayName("암호 변경")
@Test
@Transactional
public void updatePassword() throws Exception{
String jsonRQ = """
{
"userPswd" : "%s",
"newPswd" : "palnet!234",
"newPswdConfirm" : "palnet!234"
}
""".formatted(this.CREATE_PASSWORD);
String token = this.getUserToken();
this.mockMvc.perform(
put(this.BASE_URL + "/update/pswd")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(jsonRQ)
.accept(MediaType.APPLICATION_JSON_VALUE)
.header("Authorization", GRANT_TYPE + " " + token)
)
.andDo(print())
.andDo(
document(
"user/account/update/pswd",
preprocessResponse(prettyPrint()),
HeaderDocumentation.requestHeaders(
HeaderDocumentation.headerWithName("Authorization").description("Access토큰 [로그인 발급]")
),
requestFields(
fieldWithPath("userPswd").type(JsonFieldType.STRING).description("현재 암호").optional(),
fieldWithPath("newPswd").type(JsonFieldType.STRING).description("바뀔 암호"),
fieldWithPath("newPswdConfirm").type(JsonFieldType.STRING).description("바뀔 암호 확인")
)
)
)
.andExpect(status().isOk());
}
@DisplayName("회원정보 조회")
@Test
@Transactional
public void getUserInfo() throws Exception{
String token = this.getUserToken();
this.mockMvc.perform(
get(this.BASE_URL + "/profile")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON_VALUE)
.header("Authorization", GRANT_TYPE + " " + token)
)
.andDo(print())
.andDo(
document(
"user/account/profile", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()),
HeaderDocumentation.requestHeaders(
HeaderDocumentation.headerWithName("Authorization").description("Access토큰 [로그인 발급]")
),
responseFields(
fieldWithPath("memberName").type(JsonFieldType.STRING).description("회원 이름"),
fieldWithPath("brthdyDate").type(JsonFieldType.STRING).description("생년월일"),
fieldWithPath("cntryCd").type(JsonFieldType.STRING).description("국적 구분코드"),
fieldWithPath("email").type(JsonFieldType.STRING).description("이메일"),
fieldWithPath("hpno").type(JsonFieldType.STRING).description("휴대폰 번호"),
fieldWithPath("userId").type(JsonFieldType.STRING).description("아이디"),
fieldWithPath("updateDt").type(JsonFieldType.STRING).description("수정일시"),
fieldWithPath("updateuserId").type(JsonFieldType.STRING).description("수정자 아이디"),
fieldWithPath("cptAuthCode").type(JsonFieldType.STRING).description("각 항청 구분코드")
)
)
)
.andExpect(status().isOk());
}
@DisplayName("회원탈퇴")
@Test
@Transactional
public void deleteUser() throws Exception{
String token = this.getUserToken();
this.mockMvc.perform(
RestDocumentationRequestBuilders.delete(this.BASE_URL + "/delete")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON_VALUE)
.header("Authorization", GRANT_TYPE + " " + token)
)
.andDo(print())
.andDo(
document(
"user/account/delete", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()),
HeaderDocumentation.requestHeaders(
HeaderDocumentation.headerWithName("Authorization").description("Access토큰 [로그인 발급]")
)
)
)
.andExpect(status().isOk());
}
@DisplayName("회원가입")
@Test
@Transactional
public void register() throws Exception{
String username = "TEST_" + System.currentTimeMillis();
String jsonRQ = """
{
"cstrmDivCd" : "MEMBER",
"cstrmStatusCd" : "ACTIVE",
"userId" : "%s",
"authId" : "USER",
"siteCode" : "DRONE",
"userPswd" : "palnet!234",
"joinCrtfyCd" : "HP_CRTFD",
"memberName" : "이경도",
"brthdyDate" : "1999-09-07",
"email" : "lkd9125@naver.com",
"hpno" : "01083703435",
"clncd" : "+82"
}
""".formatted(username);
this.mockMvc.perform(
post(this.BASE_URL + "/register")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(jsonRQ)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andDo(print())
.andDo(
document(
"user/account/register", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()),
requestFields(
fieldWithPath("cstrmDivCd").type(JsonFieldType.STRING).description("회원타입 코드"),
fieldWithPath("cstrmStatusCd").type(JsonFieldType.STRING).description("회원 활성화 코드"),
fieldWithPath("userId").type(JsonFieldType.STRING).description("아이디"),
fieldWithPath("authId").type(JsonFieldType.STRING).description("권한 값"),
fieldWithPath("siteCode").type(JsonFieldType.STRING).description("사이트 코드"),
fieldWithPath("userPswd").type(JsonFieldType.STRING).description("암호"),
fieldWithPath("joinCrtfyCd").type(JsonFieldType.STRING).description("가입인증 분류 코드"),
fieldWithPath("memberName").type(JsonFieldType.STRING).description("이름"),
fieldWithPath("brthdyDate").type(JsonFieldType.STRING).description("생년월일"),
fieldWithPath("email").type(JsonFieldType.STRING).description("이메일"),
fieldWithPath("hpno").type(JsonFieldType.STRING).description("휴대폰 번호"),
fieldWithPath("clncd").type(JsonFieldType.STRING).description("휴대폰 국가번호"),
fieldWithPath("terms").type(JsonFieldType.ARRAY).description("동의 약관 리스트").optional(),
fieldWithPath("terms[].termsSno").type(JsonFieldType.NUMBER).description("약관 식별번호"),
fieldWithPath("terms[].agreeYn").type(JsonFieldType.STRING).description("약관 동의여부")
)
)
)
.andExpect(status().isCreated());
}
}

11
app/kac-app/src/test/resources/org/springframework/restdocs/templates/path-parameters.snippet vendored

@ -0,0 +1,11 @@
.+{{path}}+
|===
|파라미터|설명|필수
{{#parameters}}
|{{#tableCellContent}}`+{{name}}+`{{/tableCellContent}}
|{{#tableCellContent}}{{description}}{{/tableCellContent}}
|{{#tableCellContent}}{{#optional}}false{{/optional}}{{^optional}}true{{/optional}}{{/tableCellContent}}
{{/parameters}}
|===

10
app/kac-app/src/test/resources/org/springframework/restdocs/templates/query-parameters.snippet vendored

@ -0,0 +1,10 @@
|===
|파라미터|설명|필수
{{#parameters}}
|{{#tableCellContent}}`+{{name}}+`{{/tableCellContent}}
|{{#tableCellContent}}{{description}}{{/tableCellContent}}
|{{#tableCellContent}}{{#optional}}false{{/optional}}{{^optional}}true{{/optional}}{{/tableCellContent}}
{{/parameters}}
|===

12
app/kac-app/src/test/resources/org/springframework/restdocs/templates/request-fields.snippet vendored

@ -0,0 +1,12 @@
|===
|파라미터|타입|설명|필수
{{#fields}}
|{{#tableCellContent}}`+{{path}}+`{{/tableCellContent}}
|{{#tableCellContent}}`+{{type}}+`{{/tableCellContent}}
|{{#tableCellContent}}{{description}}{{/tableCellContent}}
|{{#tableCellContent}}{{#optional}}false{{/optional}}{{^optional}}true{{/optional}}{{/tableCellContent}}
{{/fields}}
|===

10
app/kac-app/src/test/resources/org/springframework/restdocs/templates/request-headers.snippet vendored

@ -0,0 +1,10 @@
|===
|파라미터|설명|필수
{{#headers}}
|{{#tableCellContent}}`+{{name}}+`{{/tableCellContent}}
|{{#tableCellContent}}{{description}}{{/tableCellContent}}
|{{#tableCellContent}}{{#optional}}false{{/optional}}{{^optional}}true{{/optional}}{{/tableCellContent}}
{{/headers}}
|===

12
app/kac-app/src/test/resources/org/springframework/restdocs/templates/response-fields.snippet vendored

@ -0,0 +1,12 @@
|===
|파라미터|타입|설명|필수
{{#fields}}
|{{#tableCellContent}}`+{{path}}+`{{/tableCellContent}}
|{{#tableCellContent}}`+{{type}}+`{{/tableCellContent}}
|{{#tableCellContent}}{{description}}{{/tableCellContent}}
|{{#tableCellContent}}{{#optional}}false{{/optional}}{{^optional}}true{{/optional}}{{/tableCellContent}}
{{/fields}}
|===

87
build.gradle

@ -1,6 +1,6 @@
buildscript { buildscript {
ext { ext {
spring = '3.2.1' spring = '3.2.2'
boot = 'org.springframework.boot' boot = 'org.springframework.boot'
lombok = 'org.projectlombok:lombok' lombok = 'org.projectlombok:lombok'
} }
@ -15,60 +15,59 @@ buildscript {
allprojects { allprojects {
group = "kr.co.palnet" group = "kr.co.palnet"
version = "1.0.0" version = "1.0.0"
} }
subprojects {
apply plugin: "java" ["app", "data", "web", "common"].each {
apply plugin: boot def rootDirName = it;
apply plugin: "io.spring.dependency-management" def subProjectDir = new File(projectDir, it)
apply plugin: "idea" subProjectDir.eachDir { dir ->
def projectName = ":${it}:${dir.name}"
project(projectName) {
repositories { plugins.apply("java")
mavenCentral() plugins.apply("java-library")
} plugins.apply(boot)
plugins.apply("io.spring.dependency-management")
plugins.apply("idea")
configurations { repositories {
developmentOnly mavenCentral()
runtimeClasspath { }
extendsFrom developmentOnly
}
}
dependencies { configurations {
developmentOnly("$boot:spring-boot-devtools") developmentOnly
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.15.3' runtimeClasspath {
extendsFrom developmentOnly
}
compileOnly {
extendsFrom annotationProcessor
}
}
compileOnly lombok dependencies {
testCompileOnly lombok developmentOnly("$boot:spring-boot-devtools")
annotationProcessor lombok implementation 'com.fasterxml.jackson.core:jackson-annotations:2.15.3'
testAnnotationProcessor lombok
testImplementation "$boot:spring-boot-starter-test" compileOnly lombok
} testCompileOnly lombok
annotationProcessor lombok
testAnnotationProcessor lombok
test { testImplementation "$boot:spring-boot-starter-test"
useJUnitPlatform() }
}
}
["data", "web"].each { test {
def subProjectDir = new File(projectDir, it) useJUnitPlatform()
subProjectDir.eachDir {dir-> }
def projectName = ":${it}-${dir.name}"
project(projectName){
bootJar.enabled(false)
jar.enabled(true)
}
}
}
["app"].each {
def subProjectDir = new File(projectDir, it)
subProjectDir.eachDir {dir->
def projectName = ":${it}-${dir.name}"
project(projectName){
if (rootDirName == 'app') {
bootJar.enabled(true)
jar.enabled(false)
} else {
bootJar.enabled(false)
jar.enabled(true)
}
} }
} }
} }

12
common/config-db/build.gradle

@ -0,0 +1,12 @@
dependencies {
// jpa
implementation "$boot:spring-boot-starter-data-jpa"
// querydsl
implementation "com.querydsl:querydsl-jpa:5.0.0:jakarta"
runtimeOnly "com.mysql:mysql-connector-j"
implementation "org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4:1.16"
}

68
common/config-db/src/main/java/kr/co/palnet/kac/config/db/KacJpaConfig.java

@ -0,0 +1,68 @@
package kr.co.palnet.kac.config.db;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.Map;
import java.util.Objects;
@Configuration
@EnableJpaRepositories(
basePackages = "kr.co.palnet.kac.data.*.repository",
entityManagerFactoryRef = "kacEntityManagerFactory",
transactionManagerRef = "kacTransactionManager"
)
public class KacJpaConfig {
private final JpaProperties jpaProperties;
private final HibernateProperties hibernateProperties;
public KacJpaConfig(JpaProperties jpaProperties, HibernateProperties hibernateProperties) {
this.jpaProperties = jpaProperties;
this.hibernateProperties = hibernateProperties;
}
@Bean(name = "kacDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.pav-kac")
public DataSource kacDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "kacEntityManagerFactory")
@Primary
public LocalContainerEntityManagerFactoryBean kacEntityManagerFactory(EntityManagerFactoryBuilder builder) {
Map<String, Object> prop = hibernateProperties.determineHibernateProperties(
jpaProperties.getProperties(),
new HibernateSettings()
);
return builder.dataSource(kacDataSource())
.properties(prop)
.packages(
"kr.co.palnet.kac.data.**.model",
"kr.co.palnet.kac.data.**.domain"
)
.persistenceUnit("kac")
.build();
}
@Bean(name = "kacTransactionManager")
@Primary
public PlatformTransactionManager kacTransactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(Objects.requireNonNull(kacEntityManagerFactory(builder).getObject()));
}
}

20
common/config-db/src/main/java/kr/co/palnet/kac/config/db/QueryDslConfig.java

@ -0,0 +1,20 @@
package kr.co.palnet.kac.config.db;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QueryDslConfig {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(entityManager);
}
}

12
common/config-db/src/main/resources/application-db.yml

@ -0,0 +1,12 @@
spring:
jpa:
hibernate:
ddl-auto: none
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
datasource:
pav-kac:
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
jdbc-url: jdbc:log4jdbc:mysql://localhost:13306/PAV_KAC?characterEncoding=UTF-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
username: kac
password: palnet!234

6
common/core/build.gradle

@ -0,0 +1,6 @@
dependencies {
implementation "$boot:spring-boot-starter-web"
implementation 'io.swagger.core.v3:swagger-annotations:2.2.20'
}

4
common/core/src/main/java/kr/co/palnet/kac/core/Sample.java

@ -0,0 +1,4 @@
package kr.co.palnet.kac.core;
public class Sample {
}

60
common/core/src/main/java/kr/co/palnet/kac/core/code/ErrorCode.java

@ -0,0 +1,60 @@
package kr.co.palnet.kac.core.code;
import com.fasterxml.jackson.annotation.JsonCreator;
public enum ErrorCode {
SUCCESS("1", "성공"),
FAIL("-1", "실패"),
NON_VALID_PARAMETER("VP001", "파라미터가 유효하지 않습니다."),
INTERNAL_SERVER_ERROR("ER500", "내부 시스템 오류"),
NOT_REGIST_ERROR_CODE("ER501", "등록되지 않은 오류 코드"),
DATA_NOTFIND("DT001", "데이터 를 찾을수 없습니다."),
DATA_DUPLICATE("DT002", "중복 데이터가 존재합니다."),
DATA_NOT_CHANGE("DT003", "아직 갱신되지 않았습니다."),
DATA_NO("DT003", "데이터 미존재"),
DB_ERROR("DB001", "디비 처리중 오류"),
PLAN_DATA_DUPLICATE("FT500", "이미 등록된 비행계획서의 비행구역과 비행시간이 일치합니다.\n비행시간 또는 비행구역을 수정하여 주십시오."),
ARCRFT_DATA_DUPLICATE("FT501", "해당 기체는 다른 비행계획서에서 이미 등록된 기체입니다.\n비행시간 또는 기체 정보를 확인하여 주십시오."),
PLAN_LAANC_NOT_VALID("FT502", "LAANC를 통과하지 못한 비행계획서입니다."),
EXTERNAL_API_ERROR("EA500", "외부서버 호출에 실패하였습니다."),
AUTH_NAUTHORIZED("AU001", "권한이 없습니다."),
// TS 연동 ERROR CODE
TS_SUCCESS("TS200", "정상적으로 수신되었습니다."),
TS_PARAM("TS300", "메시지 규격이 다릅니다."), // Json 포멧이 틀린 경우
TS_PARAM_REQUIRED("TS301", "필수 항목이 누락되었습니다."), // 필수 항목이 누락된 경우
TS_TYPE("TS302", "메시지 타입이 맞지 않습니다."), // 메시지내 파라미터의 타입이 잘못된 경우
TS_SERVER_ERROR("TS500", "서버 연결이 되지 않습니다."), // call측 network exception 처리
TS_NT_LAZY("TS501", "네트워크 연결이 지연 됩니다."), // call측 network exception 처리
TS_AUTH_KEY("TS600", "인증키가 유효하지 않습니다."),
TS_ETC("TS700", "기타 오류"), // 기 정의된 내용이 아닌 기타 오류인 경우
// QR 관련 ERROR CODE
QR_EXPIRED("QR001", "QR코드 유효기간이 만료되었습니다");
private final String code;
private final String message;
private ErrorCode(String code, String message) {
this.code = code;
this.message = message;
}
public String code() {
return code;
}
public String message() {
return message;
}
@JsonCreator
public static ErrorCode fromCode(String code) {
for (ErrorCode errorCode : ErrorCode.values()) {
if (errorCode.code().equals(code)) {
return errorCode;
}
}
return null;
}
}

24
common/core/src/main/java/kr/co/palnet/kac/core/code/Level.java

@ -0,0 +1,24 @@
package kr.co.palnet.kac.core.code;
public enum Level {
INFO(0),
WARN(1),
RETRY(2),
DROP(3),
RECYCLE(4),
CRITICAL(5);
private int code;
Level(int code) {
setLevel(code);
}
public int getLevel() {
return code;
}
public void setLevel(int code) {
this.code = code;
}
}

8
common/core/src/main/java/kr/co/palnet/kac/core/code/MessageType.java

@ -0,0 +1,8 @@
package kr.co.palnet.kac.core.code;
public enum MessageType {
OPENSKY,
ADSB,
LTEM,
ETC,
}

9
common/core/src/main/java/kr/co/palnet/kac/core/code/ObjectType.java

@ -0,0 +1,9 @@
package kr.co.palnet.kac.core.code;
public enum ObjectType {
DRON,
AIRPLANE,
CAR,
BUS,
PERSON
}

32
common/core/src/main/java/kr/co/palnet/kac/core/code/RSErrorCode.java

@ -0,0 +1,32 @@
package kr.co.palnet.kac.core.code;
public enum RSErrorCode {
SUCCESS("1", "Success"),
FAIL("-1" , "Fail"),
ER_PARAM("-100" , "Please parameter Check"),
DATA_NOTFOUNT("-101" , "Data not found"),
PSWD_NOTMATCH("-102" , "Password does not match"),
ACNT_UNAVAIL("-103","Account is unavailable"),
AUTH_ERROR("-401", "auth error"),
INTERNAL_SERVER_ERROR("-500", "Internal system error"),
DATA_DUPLICATE("-104","Duplicate data exists");
private final String code;
private final String message;
private RSErrorCode(String code, String message) {
this.code = code;
this.message = message;
}
public String code() {
return code;
}
public String message() {
return message;
}
}

6
common/core/src/main/java/kr/co/palnet/kac/core/code/Source.java

@ -0,0 +1,6 @@
package kr.co.palnet.kac.core.code;
public enum Source {
SERVER,
INTERNAL
}

54
common/core/src/main/java/kr/co/palnet/kac/core/exception/BaseErrorCode.java

@ -0,0 +1,54 @@
package kr.co.palnet.kac.core.exception;
import org.springframework.http.HttpStatus;
public enum BaseErrorCode {
SUCCESS("CM001", HttpStatus.OK, "성공"),
FAILED("CM900", HttpStatus.INTERNAL_SERVER_ERROR, "실패"),
UNKNOWN("CM999", HttpStatus.INTERNAL_SERVER_ERROR, "실패(사용자 정의 없는 에러)"),
NOT_PROCESS("CM002", HttpStatus.INTERNAL_SERVER_ERROR, "처리되지 않음"),
IO_ERROR("CM003", HttpStatus.INTERNAL_SERVER_ERROR, "IO 에러"),
LOGIN_FAILED("CM100", HttpStatus.INTERNAL_SERVER_ERROR, "로그인 실패"),
LOGIN_DUPLICATED("CM101", HttpStatus.INTERNAL_SERVER_ERROR, "중복 로그인"),
LOGIN_ATTEMPT_COUNT("CM102", HttpStatus.INTERNAL_SERVER_ERROR, "로그인 실패 횟수 초과"),
LOGIN_SNS_FAILED("CM110", HttpStatus.INTERNAL_SERVER_ERROR, "SNS 로그인 실패"),
LOGIN_SNS_DUPLICATED("CM111", HttpStatus.INTERNAL_SERVER_ERROR, "SNS 가입 중복"),
TOKEN_EXPIRED("CM120", HttpStatus.INTERNAL_SERVER_ERROR, "토큰 만료"),
TOKEN_INVALID("CM121", HttpStatus.INTERNAL_SERVER_ERROR, "잘못된 토큰"),
ACCOUNT_LOCK("CM130", HttpStatus.INTERNAL_SERVER_ERROR, "계정 잠김"),
ACCOUNT_DORMANT("CM131", HttpStatus.INTERNAL_SERVER_ERROR, "휴면 계정"),
CACHE_LOAD_FAILED("CM200", HttpStatus.INTERNAL_SERVER_ERROR, "캐시 로딩 실패"),
CACHE_RELOAD_FAILED("CM201", HttpStatus.INTERNAL_SERVER_ERROR, "캐시 리로딩 실패"),
AUTH_EMPTY("CM401", HttpStatus.UNAUTHORIZED, "권한 없음"),
WEB_PARAM_INVALID("WB400", HttpStatus.INTERNAL_SERVER_ERROR, "잘못된 파라미터"),
WEB_NOT_FOUND("WB404", HttpStatus.INTERNAL_SERVER_ERROR, "찾을수 없는 페이지"),
WEB_API_ERROR("WB500", HttpStatus.INTERNAL_SERVER_ERROR, "외부 연동 에러"),
DATA_ALREADY_EXISTS("DT001", HttpStatus.INTERNAL_SERVER_ERROR, "이미 등록된 데이터"),
DATA_EMPTY("DT002", HttpStatus.INTERNAL_SERVER_ERROR, "데이터 없음");
private final String code;
private final HttpStatus status;
private final String message;
private BaseErrorCode(String code, HttpStatus status, String message) {
this.code = code;
this.status = status;
this.message = message;
}
public String code() {
return this.code;
}
public String message() {
return this.message;
}
public HttpStatus status() {
return this.status;
}
}

132
common/core/src/main/java/kr/co/palnet/kac/core/exception/BaseException.java

@ -0,0 +1,132 @@
package kr.co.palnet.kac.core.exception;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.MessageSource;
import java.util.Locale;
@Getter
public class BaseException extends RuntimeException {
private final BaseErrorCode errorCode;
private final String logMessage;
private final Level level;
private final Object[] paramArray;
public BaseException() {
this(BaseErrorCode.FAILED, null, Level.WARN, null);
}
public BaseException(Object[] paramArray) {
this(BaseErrorCode.FAILED, null, Level.WARN, paramArray);
}
public BaseException(Level level) {
this(BaseErrorCode.FAILED, null, level, null);
}
public BaseException(Level level, Object[] paramArray) {
this(BaseErrorCode.FAILED, null, level, paramArray);
}
public BaseException(String logMessage) {
this(BaseErrorCode.FAILED, logMessage, Level.WARN, null);
}
public BaseException(String logMessage, Object[] paramArray) {
this(BaseErrorCode.FAILED, logMessage, Level.WARN, paramArray);
}
public BaseException(String logMessage, Level level) {
this(BaseErrorCode.FAILED, logMessage, level, null);
}
public BaseException(String logMessage, Level level, Object[] paramArray) {
this(BaseErrorCode.FAILED, logMessage, level, paramArray);
}
public BaseException(BaseErrorCode errorCode) {
this(errorCode, null, Level.WARN, null);
}
public BaseException(BaseErrorCode errorCode, Object[] paramArray) {
this(errorCode, null, Level.WARN, paramArray);
}
public BaseException(BaseErrorCode errorCode, Level level) {
this(errorCode, null, level, null);
}
public BaseException(BaseErrorCode errorCode, Level level, Object[] paramArray) {
this(errorCode, null, level, paramArray);
}
public BaseException(BaseErrorCode errorCode, String logMessage) {
this(errorCode, logMessage, Level.WARN, null);
}
public BaseException(BaseErrorCode errorCode, String logMessage, Object[] paramArray) {
this(errorCode, logMessage, Level.WARN, paramArray);
}
public BaseException(BaseErrorCode errorCode, String logMessage, Level level) {
this(errorCode, logMessage, level, null);
}
public BaseException(BaseErrorCode errorCode, String logMessage, Level level, Object[] paramArray) {
this.errorCode = errorCode;
this.logMessage = logMessage;
this.level = level;
this.paramArray = paramArray;
}
public BaseException(String message, BaseErrorCode errorCode, String logMessage, Level level, Object[] paramArray) {
super(message);
this.errorCode = errorCode;
this.logMessage = logMessage;
this.level = level;
this.paramArray = paramArray;
}
public BaseException(String message, Throwable cause, BaseErrorCode errorCode, String logMessage, Level level, Object[] paramArray) {
super(message, cause);
this.errorCode = errorCode;
this.logMessage = logMessage;
this.level = level;
this.paramArray = paramArray;
}
public BaseException(Throwable cause, BaseErrorCode errorCode, String logMessage, Level level, Object[] paramArray) {
super(cause);
this.errorCode = errorCode;
this.logMessage = logMessage;
this.level = level;
this.paramArray = paramArray;
}
public BaseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, BaseErrorCode errorCode, String logMessage, Level level, Object[] paramArray) {
super(message, cause, enableSuppression, writableStackTrace);
this.errorCode = errorCode;
this.logMessage = logMessage;
this.level = level;
this.paramArray = paramArray;
}
public String getCode() {
return errorCode.code();
}
public String getErrorMessage(MessageSource ms) {
if (ms == null) {
return BaseErrorCode.UNKNOWN.message();
}
return ms.getMessage(getCode(), getParamArray(), BaseErrorCode.UNKNOWN.message(), Locale.getDefault());
}
}

9
common/core/src/main/java/kr/co/palnet/kac/core/exception/Level.java

@ -0,0 +1,9 @@
package kr.co.palnet.kac.core.exception;
public enum Level {
TRACE,
DEBUG,
INFO,
WARN,
ERROR
}

28
common/core/src/main/java/kr/co/palnet/kac/core/exception/model/BaseErrorModel.java

@ -0,0 +1,28 @@
package kr.co.palnet.kac.core.exception.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.Instant;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BaseErrorModel {
private Instant timestamp;
private int status;
private String error;
private String path;
private String message;
private String code;
}

5
common/core/src/main/java/kr/co/palnet/kac/core/response/BasicResponse.java

@ -0,0 +1,5 @@
package kr.co.palnet.kac.core.response;
public abstract class BasicResponse {
}

29
common/core/src/main/java/kr/co/palnet/kac/core/response/ErrorResponse.java

@ -0,0 +1,29 @@
package kr.co.palnet.kac.core.response;
import kr.co.palnet.kac.core.code.RSErrorCode;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper=false)
public class ErrorResponse extends BasicResponse{
private String errorMessage;
private String errorCode;
public ErrorResponse(String errorMessage) {
this.errorMessage = errorMessage;
this.errorCode = "404";
}
public ErrorResponse(RSErrorCode code) {
this.errorMessage = code.message();
this.errorCode = code.code();
}
public ErrorResponse(String errorMessage, String errorCode) {
this.errorMessage = errorMessage;
this.errorCode = errorCode;
}
}

30
common/core/src/main/java/kr/co/palnet/kac/core/response/SuccessResponse.java

@ -0,0 +1,30 @@
package kr.co.palnet.kac.core.response;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper=false)
public class SuccessResponse<T> extends BasicResponse {
@Schema(description = "응답 데이터 건수")
private int count;
@Schema(description = "응답 데이터")
private T data;
public SuccessResponse(T data) {
this.data = data;
if(data instanceof List) {
this.count = ((List<?>)data).size();
} else {
this.count = 1;
}
}
}

5
common/util/build.gradle

@ -0,0 +1,5 @@
dependencies {
implementation "$boot:spring-boot-starter-json"
}

100
common/util/src/main/java/kr/co/palnet/kac/util/EncryptUtil.java

@ -0,0 +1,100 @@
package kr.co.palnet.kac.util;
import kr.co.palnet.kac.util.kisa.KISA_SHA256;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@Slf4j
public class EncryptUtil {
// 16byte
private static String ENCRYPT_KEY = "__DEFAULT__KEY__";
private static String ENCRYPT_IV = "DEFAULT_IV_VALUE";
public static void setEncryptKey(String encryptKey) {
ENCRYPT_KEY = encryptKey;
}
public static void setEncryptIv(String encryptIv) {
ENCRYPT_IV = encryptIv;
}
public static String encrypt(String value) {
return encrypt(ENCRYPT_KEY, ENCRYPT_IV, value);
}
public static String decrypt(String encrypted) {
return decrypt(ENCRYPT_KEY, ENCRYPT_IV, encrypted);
}
// 암호화
public static String encrypt(String key, String initVector, String value) {
// log.info("encrypt() key: {}, initVector: {}, value: {}", key, initVector, value);
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes(StandardCharsets.UTF_8));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
// cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(value.getBytes());
Base64.Encoder encoder = Base64.getEncoder();
String encodedString = encoder.encodeToString(encrypted);
log.debug("encrypted string: {}", encodedString);
return encodedString;
} catch (Exception e) {
log.error("encrypt() Exception: {}", e.getMessage());
}
return value;
}
// 복호화
public static String decrypt(String key, String initVector, String encrypted) {
// log.info("decrypt() key: {}, initVector: {}, encrypted: {}", key, initVector, encrypted);
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes(StandardCharsets.UTF_8));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
//cipher.init(Cipher.DECRYPT_MODE, skeySpec);
Base64.Decoder decoder = Base64.getDecoder();
byte[] original = cipher.doFinal(decoder.decode(encrypted));
return new String(original);
} catch (Exception e) {
log.error("decrypt() Exception: {}", e.getMessage());
}
return encrypted;
}
public static String sha256Encrypt(String str) {
byte[] bytes = str.getBytes();
byte[] pszDigest = new byte[32];
KISA_SHA256.SHA256_Encrpyt(bytes, bytes.length, pszDigest);
StringBuffer encrypted = new StringBuffer();
for (int i = 0; i < 32; i++) {
encrypted.append(String.format("%02x", pszDigest[i]));
}
return encrypted.toString();
}
public static void main(String[] args) {
String key = "1234567890123456";
String initVector = "1234567890123456";
String test = "test";
// WkaOhqSK03Z1pSuPOdc03w==
// WkaOhqSK03Z1pSuPOdc03w==
String encrypted = encrypt(test);
log.info("encrypted: {}", encrypted);
String decrypted = decrypt(encrypted);
log.info("decrypted: {}", decrypted);
}
}

128
common/util/src/main/java/kr/co/palnet/kac/util/KisaEncryptUtil.java

@ -0,0 +1,128 @@
package kr.co.palnet.kac.util;
import kr.co.palnet.kac.util.kisa.KISA_SEED_CBC;
import kr.co.palnet.kac.util.kisa.KISA_SEED_CTR;
import kr.co.palnet.kac.util.kisa.KISA_SEED_ECB;
import kr.co.palnet.kac.util.kisa.KISA_SHA256;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class KisaEncryptUtil {
// 사용자가 지정하는 입력 키 (16 bytes)
private final static String PBSZ_USER_KEY = "PBSZ_USER_KEY___"; // 16 bytes
// 사용자가 지정하는 초기화 벡트 (16 bytes)
private final static String PBSZ_VECTOR = "PBSZ_INIT_VECTOR"; // 16 bytes
public static class EcbEncrypt {
public static String encrypt(String value) {
byte[] ecbEncBytes = KISA_SEED_ECB.SEED_ECB_Encrypt(PBSZ_USER_KEY.getBytes(StandardCharsets.UTF_8), value.getBytes(StandardCharsets.UTF_8), 0, value.getBytes(StandardCharsets.UTF_8).length);
Base64.Encoder encoder = Base64.getEncoder();
byte[] ecbEncode = encoder.encode(ecbEncBytes);
return new String(ecbEncode);
}
public static String decrypt(String value) {
Base64.Decoder decoder = Base64.getDecoder();
byte[] ecbDecoder = decoder.decode(value.getBytes(StandardCharsets.UTF_8));
byte[] ecbDecBytes = KISA_SEED_ECB.SEED_ECB_Decrypt(PBSZ_USER_KEY.getBytes(StandardCharsets.UTF_8), ecbDecoder, 0, ecbDecoder.length);
return new String(ecbDecBytes);
}
}
public static class CbcEncrypt {
public static String encrypt(String value) {
byte[] ecbEncBytes = KISA_SEED_CBC.SEED_CBC_Encrypt(
PBSZ_USER_KEY.getBytes(StandardCharsets.UTF_8),
PBSZ_VECTOR.getBytes(StandardCharsets.UTF_8),
value.getBytes(StandardCharsets.UTF_8),
0,
value.getBytes(StandardCharsets.UTF_8).length
);
Base64.Encoder encoder = Base64.getEncoder();
byte[] ecbEncode = encoder.encode(ecbEncBytes);
return new String(ecbEncode);
}
public static String decrypt(String value) {
Base64.Decoder decoder = Base64.getDecoder();
byte[] ecbDecoder = decoder.decode(value.getBytes(StandardCharsets.UTF_8));
byte[] ecbDecBytes = KISA_SEED_CBC.SEED_CBC_Decrypt(
PBSZ_USER_KEY.getBytes(StandardCharsets.UTF_8),
PBSZ_VECTOR.getBytes(StandardCharsets.UTF_8),
ecbDecoder,
0,
ecbDecoder.length
);
return new String(ecbDecBytes);
}
}
public static class CtrEncrypt {
public static String encrypt(String value) {
byte[] encBytes = KISA_SEED_CTR.SEED_CTR_Encrypt(
PBSZ_USER_KEY.getBytes(StandardCharsets.UTF_8),
PBSZ_VECTOR.getBytes(StandardCharsets.UTF_8),
value.getBytes(StandardCharsets.UTF_8),
0,
value.getBytes(StandardCharsets.UTF_8).length
);
Base64.Encoder encoder = Base64.getEncoder();
byte[] encodeBytes = encoder.encode(encBytes);
return new String(encodeBytes);
}
public static String decrypt(String value) {
Base64.Decoder decoder = Base64.getDecoder();
byte[] decodeBytes = decoder.decode(value.getBytes(StandardCharsets.UTF_8));
byte[] decBytes = KISA_SEED_CTR.SEED_CTR_Decrypt(
PBSZ_USER_KEY.getBytes(StandardCharsets.UTF_8),
PBSZ_VECTOR.getBytes(StandardCharsets.UTF_8),
decodeBytes,
0,
decodeBytes.length
);
return new String(decBytes);
}
}
public static class ShaEncrypt {
public static String encrypt(String value) {
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
byte[] pszDigest = new byte[32];
KISA_SHA256.SHA256_Encrpyt(bytes, bytes.length, pszDigest);
StringBuffer encrypted = new StringBuffer();
for (int i = 0; i < 32; i++) {
encrypted.append(String.format("%02x", pszDigest[i]));
}
return encrypted.toString();
}
}
public static void main(String[] args) {
String message = "this is message!!@#!$^#$%^&@#$~!@ 메시지 입니다.___+_+)(_)(";
System.out.println("message = " + message);
System.out.println("=============== ECB =================");
String ecbEncStr = EcbEncrypt.encrypt(message);
System.out.println("ecbEncStr = " + ecbEncStr);
String ecbDecStr = EcbEncrypt.decrypt(ecbEncStr);
System.out.println("ecbDecStr = " + ecbDecStr);
System.out.println("=============== CBC =================");
String cbcEncStr = CbcEncrypt.encrypt(message);
System.out.println("cbcEncStr = " + cbcEncStr);
String cbcDncStr = CbcEncrypt.decrypt(cbcEncStr);
System.out.println("cbcDncStr = " + cbcDncStr);
System.out.println("=============== CTR =================");
String ctrEncStr = CtrEncrypt.encrypt(message);
System.out.println("ctrEncStr = " + ctrEncStr);
String ctrDncStr = CtrEncrypt.decrypt(ctrEncStr);
System.out.println("ctrDncStr = " + ctrDncStr);
System.out.println("=============== SHA =================");
String shaEncStr = ShaEncrypt.encrypt(message);
System.out.println("shaEncStr = " + shaEncStr);
}
}

106
common/util/src/main/java/kr/co/palnet/kac/util/MaskingUtil.java

@ -0,0 +1,106 @@
package kr.co.palnet.kac.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MaskingUtil {
public static String maskString(String originalString, int start, int end) {
String mask = originalString.substring(start, end).replaceAll(".", "*");
return originalString.substring(0, start) + mask + originalString.substring(end);
}
public static String maskStringEndWith(String originalString, int end) {
return maskString(originalString, 0, end);
}
public static String maskStringStartWith(String originalString, int start) {
return maskString(originalString, start, originalString.length());
}
public static String maskEmail(String email) {
return email.replaceAll("(?<=.{3}).(?=[^@]*?@)", "*");
}
public static String maskEmailAndDomain(String email) {
String regex = "(.+)@(.+)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(email);
if (matcher.find()) {
String localPart = matcher.group(1);
String domain = matcher.group(2);
localPart = maskString(localPart, 3, localPart.length());
domain = maskString(domain, 3, domain.length());
return localPart + "@" + domain;
}
return email;
}
public static String maskCardNumber(String cardNumber) {
// return cardNumber.replaceAll("\\b(\\d{6})(\\d+)(\\d{4})\\b", "$1****$2");
// 하이픈 제거
String cardNumberWithoutHyphens = cardNumber.replace("-", "");
// 마스킹 적용
StringBuffer sb = new StringBuffer();
Pattern pattern = Pattern.compile("(\\d{6})(\\d+)(\\d{4})");
Matcher matcher = pattern.matcher(cardNumberWithoutHyphens);
while (matcher.find()) {
matcher.appendReplacement(sb, matcher.group(1) + "*".repeat(matcher.group(2).length()) + matcher.group(3));
}
matcher.appendTail(sb);
String maskedCardNumber = sb.toString();
// Return the card number in the original format
return cardNumber.contains("-")
? maskedCardNumber.replaceAll("(\\d{4})(.{4})(.{4})(\\d{3,4})", "$1-$2-$3-$4")
: maskedCardNumber;
}
public static String maskName(String name) {
if (name.length() == 1) {
return "*";
} else if (name.length() == 2) {
return name.replaceAll("(?<=.).", "*");
} else {
return name.replaceAll("(?<=.).(?=.)", "*");
}
}
public static String maskPhoneNumber(String phoneNumber) {
// 하이픈 제거
String phoneNumberWithoutHyphens = phoneNumber.replace("-", "");
// 마스킹 적용
StringBuffer sb = new StringBuffer();
Pattern pattern = Pattern.compile("(02|0\\d{2})(\\d+)(\\d{4})");
Matcher matcher = pattern.matcher(phoneNumberWithoutHyphens);
while (matcher.find()) {
matcher.appendReplacement(sb, matcher.group(1) + "*".repeat(matcher.group(2).length()) + matcher.group(3));
}
matcher.appendTail(sb);
String maskedPhoneNumber = sb.toString();
return phoneNumber.contains("-")
? maskedPhoneNumber.replaceAll("(\\d{2,3})(.{3,4})(\\d{4})", "$1-$2-$3")
: maskedPhoneNumber;
}
public static String maskExpireDate(String expireDate) {
return expireDate.replaceAll("(\\d{2})(\\d{2})", "$1/$2");
}
public static String maskResidentRegistrationNumber(String rrn) {
return rrn.replaceAll("(\\d{6}-?\\d{1})(\\d{6})", "$1******");
}
public static String maskIp(String ip) {
return ip.replaceAll("^(\\d+)(\\.\\d+\\.\\d+\\.\\d+)$", "***$2");
}
}

52
common/util/src/main/java/kr/co/palnet/kac/util/ObjectMapperUtils.java

@ -0,0 +1,52 @@
package kr.co.palnet.kac.util;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;
/**
* packageName : com.sumair.common.core.utils
* fileName : ObjectMapperUtils
* author : dhji
* date : 2023-05-17(017)
* description :
* ===========================================================
* DATE AUTHOR NOTE
* -----------------------------------------------------------
* 2023-05-17(017) dhji 최초 생성
*/
public class ObjectMapperUtils {
public static ObjectMapper getObjectMapper() {
return getObjectMapperBuilder().build();
}
public static Jackson2ObjectMapperBuilder getObjectMapperBuilder() {
Jackson2ObjectMapperBuilder jacksonBuilder = new Jackson2ObjectMapperBuilder();
jacksonBuilder.serializationInclusion(JsonInclude.Include.NON_NULL);
jacksonBuilder.serializationInclusion(JsonInclude.Include.NON_EMPTY);
// jacksonBuilder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// jacksonBuilder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// jacksonBuilder.featuresToDisable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
// jacksonBuilder.featuresToDisable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
// jacksonBuilder.modulesToInstall(new JavaTimeModule());
// jacksonBuilder.timeZone(TimeZone.getTimeZone("UTC"));
// jacksonBuilder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
// jacksonBuilder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
// jacksonBuilder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
// jacksonBuilder.deserializers(new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
// jacksonBuilder.deserializers(new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
return jacksonBuilder;
}
}

11
common/util/src/main/java/kr/co/palnet/kac/util/UtilApplication.java

@ -0,0 +1,11 @@
package kr.co.palnet.kac.util;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class UtilApplication {
public static void main(String[] args) {
SpringApplication.run(UtilApplication.class, args);
}
}

1928
common/util/src/main/java/kr/co/palnet/kac/util/kisa/KISA_SEED_CBC.java

File diff suppressed because it is too large Load Diff

1265
common/util/src/main/java/kr/co/palnet/kac/util/kisa/KISA_SEED_CTR.java

File diff suppressed because it is too large Load Diff

1421
common/util/src/main/java/kr/co/palnet/kac/util/kisa/KISA_SEED_ECB.java

File diff suppressed because it is too large Load Diff

453
common/util/src/main/java/kr/co/palnet/kac/util/kisa/KISA_SHA256.java

@ -0,0 +1,453 @@
package kr.co.palnet.kac.util.kisa;
/**
@file KISA_SHA256.java
@brief SHA256 암호 알고리즘
@author Copyright (c) 2013 by KISA
@remarks http://seed.kisa.or.kr/
*/
public class KISA_SHA256 {
// DEFAULT : JAVA = BIG_ENDIAN
private static int ENDIAN = Common.BIG_ENDIAN;
private static final int SHA256_DIGEST_BLOCKLEN = 64;
private static final int SHA256_DIGEST_VALUELEN = 32;
private static final int SHA256_K[] =
{
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
private static final int ROTL_ULONG(int x, int n) {
return (x << n) | Common.URShift(x, 32 - n);
}
private static final int ROTR_ULONG(int x, int n) {
return Common.URShift(x, n) | (x << (32 - (n)));
}
private static final int ENDIAN_REVERSE_ULONG(int dwS) {
return ( (ROTL_ULONG((dwS), 8) & 0x00ff00ff) | (ROTL_ULONG((dwS), 24) & 0xff00ff00) );
}
private static final void BIG_D2B(int D, byte[] B, int B_offset) {
Common.int_to_byte_unit(B, B_offset, D, ENDIAN);
}
private static final int RR(int x, int n) { return ROTR_ULONG(x, n); }
private static final int SS(int x, int n) { return Common.URShift(x, n); }
private static final int Ch(int x, int y, int z) { return ((x & y) ^ ((~x) & z)); }
private static final int Maj(int x, int y, int z) { return ((x & y) ^ (x & z) ^ (y & z)); }
private static final int Sigma0(int x) { return (RR(x, 2) ^ RR(x, 13) ^ RR(x, 22)); }
private static final int Sigma1(int x) { return (RR(x, 6) ^ RR(x, 11) ^ RR(x, 25)); }
private static final int RHO0(int x) { return (RR(x, 7) ^ RR(x, 18) ^ SS(x, 3)); }
private static final int RHO1(int x) { return (RR(x, 17) ^ RR(x, 19) ^ SS(x, 10)); }
private static final int abcdefgh_a = 0;
private static final int abcdefgh_b = 1;
private static final int abcdefgh_c = 2;
private static final int abcdefgh_d = 3;
private static final int abcdefgh_e = 4;
private static final int abcdefgh_f = 5;
private static final int abcdefgh_g = 6;
private static final int abcdefgh_h = 7;
private static final void FF(int[] abcdefgh, int a, int b, int c, int d, int e, int f, int g, int h, int[] X, int j) {
long T1;
T1 = Common.intToUnsigned(abcdefgh[h]) + Common.intToUnsigned(Sigma1(abcdefgh[e])) + Common.intToUnsigned(Ch(abcdefgh[e], abcdefgh[f], abcdefgh[g])) + Common.intToUnsigned(SHA256_K[j]) + Common.intToUnsigned(X[j]);
abcdefgh[d] += T1;
abcdefgh[h] = (int)(T1 + Common.intToUnsigned(Sigma0(abcdefgh[a])) + Common.intToUnsigned(Maj(abcdefgh[a], abcdefgh[b], abcdefgh[c])));
}
private static final int GetData(byte[] x, int x_offset) {
return Common.byte_to_int(x, x_offset, ENDIAN);
}
//*********************************************************************************************************************************
// o SHA256_Transform() : 512 비트 단위 블록의 메시지를 입력 받아 연쇄변수를 갱신하는 압축 함수로써
// 4 라운드(64 단계)로 구성되며 8개의 연쇄변수(a, b, c, d, e, f, g, h)를 사용
// o 입력 : Message - 입력 메시지의 포인터 변수
// ChainVar - 연쇄변수의 포인터 변수
// o 출력 :
//*********************************************************************************************************************************
private static void SHA256_Transform(byte[] Message, int[] ChainVar) {
int abcdefgh[] = new int[8];
int T1[] = new int[1];
int X[] = new int[64];
int j;
for (j = 0; j < 16; j++)
X[j] = GetData(Message, j*4);
for (j = 16; j < 64; j++)
X[j] = (int)(Common.intToUnsigned(RHO1(X[j - 2])) + Common.intToUnsigned(X[j - 7]) + Common.intToUnsigned(RHO0(X[j - 15])) + Common.intToUnsigned(X[j - 16]));
abcdefgh[abcdefgh_a] = ChainVar[0];
abcdefgh[abcdefgh_b] = ChainVar[1];
abcdefgh[abcdefgh_c] = ChainVar[2];
abcdefgh[abcdefgh_d] = ChainVar[3];
abcdefgh[abcdefgh_e] = ChainVar[4];
abcdefgh[abcdefgh_f] = ChainVar[5];
abcdefgh[abcdefgh_g] = ChainVar[6];
abcdefgh[abcdefgh_h] = ChainVar[7];
for (j = 0; j < 64; j += 8)
{
FF(abcdefgh, abcdefgh_a, abcdefgh_b, abcdefgh_c, abcdefgh_d, abcdefgh_e, abcdefgh_f, abcdefgh_g, abcdefgh_h, X, j + 0);
FF(abcdefgh, abcdefgh_h, abcdefgh_a, abcdefgh_b, abcdefgh_c, abcdefgh_d, abcdefgh_e, abcdefgh_f, abcdefgh_g, X, j + 1);
FF(abcdefgh, abcdefgh_g, abcdefgh_h, abcdefgh_a, abcdefgh_b, abcdefgh_c, abcdefgh_d, abcdefgh_e, abcdefgh_f, X, j + 2);
FF(abcdefgh, abcdefgh_f, abcdefgh_g, abcdefgh_h, abcdefgh_a, abcdefgh_b, abcdefgh_c, abcdefgh_d, abcdefgh_e, X, j + 3);
FF(abcdefgh, abcdefgh_e, abcdefgh_f, abcdefgh_g, abcdefgh_h, abcdefgh_a, abcdefgh_b, abcdefgh_c, abcdefgh_d, X, j + 4);
FF(abcdefgh, abcdefgh_d, abcdefgh_e, abcdefgh_f, abcdefgh_g, abcdefgh_h, abcdefgh_a, abcdefgh_b, abcdefgh_c, X, j + 5);
FF(abcdefgh, abcdefgh_c, abcdefgh_d, abcdefgh_e, abcdefgh_f, abcdefgh_g, abcdefgh_h, abcdefgh_a, abcdefgh_b, X, j + 6);
FF(abcdefgh, abcdefgh_b, abcdefgh_c, abcdefgh_d, abcdefgh_e, abcdefgh_f, abcdefgh_g, abcdefgh_h, abcdefgh_a, X, j + 7);
}
ChainVar[0] += abcdefgh[abcdefgh_a];
ChainVar[1] += abcdefgh[abcdefgh_b];
ChainVar[2] += abcdefgh[abcdefgh_c];
ChainVar[3] += abcdefgh[abcdefgh_d];
ChainVar[4] += abcdefgh[abcdefgh_e];
ChainVar[5] += abcdefgh[abcdefgh_f];
ChainVar[6] += abcdefgh[abcdefgh_g];
ChainVar[7] += abcdefgh[abcdefgh_h];
}
/**
@brief 연쇄변수와 길이변수를 초기화하는 함수
@param Info : SHA256_Process 호출 사용되는 구조체
*/
public static void SHA256_Init( SHA256_INFO Info ) {
Info.uChainVar[0] = 0x6a09e667;
Info.uChainVar[1] = 0xbb67ae85;
Info.uChainVar[2] = 0x3c6ef372;
Info.uChainVar[3] = 0xa54ff53a;
Info.uChainVar[4] = 0x510e527f;
Info.uChainVar[5] = 0x9b05688c;
Info.uChainVar[6] = 0x1f83d9ab;
Info.uChainVar[7] = 0x5be0cd19;
Info.uHighLength = Info.uLowLength = Info.remainNum = 0;
}
/**
@brief 연쇄변수와 길이변수를 초기화하는 함수
@param Info : SHA256_Init 호출하여 초기화된 구조체(내부적으로 사용된다.)
@param pszMessage : 사용자 입력 평문
@param inLen : 사용자 입력 평문 길이
*/
public static void SHA256_Process( SHA256_INFO Info, byte[] pszMessage, int uDataLen ) {
/*
int pszMessage_offset = Info.remainNum;
if((Info.uLowLength += (uDataLen << 3)) < 0) {
Info.uHighLength++;
}
Info.uHighLength += Common.URShift(uDataLen,29);
while (uDataLen + pszMessage_offset >= SHA256_DIGEST_BLOCKLEN) {
Common.arraycopy_offset(Info.szBuffer, pszMessage_offset, pszMessage, 0, SHA256_DIGEST_BLOCKLEN);
SHA256_Transform(Info.szBuffer, Info.uChainVar);
pszMessage_offset += SHA256_DIGEST_BLOCKLEN - pszMessage_offset;
uDataLen -= SHA256_DIGEST_BLOCKLEN - pszMessage_offset;
pszMessage_offset = 0;
}
Common.arraycopy_offset(Info.szBuffer, pszMessage_offset, pszMessage, 0, uDataLen);
Info.remainNum = pszMessage_offset + uDataLen;
*/
int pszMessage_offset;
if((Info.uLowLength += (uDataLen << 3)) < 0) {
Info.uHighLength++;
}
Info.uHighLength += Common.URShift(uDataLen,29);
pszMessage_offset = 0;
while (uDataLen >= SHA256_DIGEST_BLOCKLEN) {
Common.arraycopy_offset(Info.szBuffer, 0, pszMessage, pszMessage_offset, SHA256_DIGEST_BLOCKLEN);
SHA256_Transform(Info.szBuffer, Info.uChainVar);
pszMessage_offset += SHA256_DIGEST_BLOCKLEN;
uDataLen -= SHA256_DIGEST_BLOCKLEN;
}
Common.arraycopy_offset(Info.szBuffer, 0, pszMessage, pszMessage_offset, uDataLen);
}
/**
@brief 메시지 덧붙이기와 길이 덧붙이기를 수행한 마지막 메시지 블록을 가지고 압축함수를 호출하는 함수
@param Info : SHA256_Init 호출하여 초기화된 구조체(내부적으로 사용된다.)
@param pszDigest : 암호문
*/
public static void SHA256_Close( SHA256_INFO Info, byte[] pszDigest ) {
int i, Index;
Index = Common.URShift(Info.uLowLength, 3) % SHA256_DIGEST_BLOCKLEN;
Info.szBuffer[Index++] = (byte)0x80;
if (Index > SHA256_DIGEST_BLOCKLEN - 8) {
Common.arrayinit_offset(Info.szBuffer, Index, (byte)0, SHA256_DIGEST_BLOCKLEN - Index);
SHA256_Transform(Info.szBuffer, Info.uChainVar);
Common.arrayinit(Info.szBuffer, (byte)0, SHA256_DIGEST_BLOCKLEN - 8);
}
else {
Common.arrayinit_offset(Info.szBuffer, Index, (byte)0, SHA256_DIGEST_BLOCKLEN - Index - 8);
}
if(ENDIAN == Common.LITTLE_ENDIAN) {
Info.uLowLength = ENDIAN_REVERSE_ULONG(Info.uLowLength);
Info.uHighLength = ENDIAN_REVERSE_ULONG(Info.uHighLength);
}
Common.int_to_byte_unit(Info.szBuffer, ((int)(SHA256_DIGEST_BLOCKLEN / 4 - 2))*4, Info.uHighLength, ENDIAN);
Common.int_to_byte_unit(Info.szBuffer, ((int)(SHA256_DIGEST_BLOCKLEN / 4 - 1))*4, Info.uLowLength, ENDIAN);
SHA256_Transform(Info.szBuffer, Info.uChainVar);
for (i = 0; i < SHA256_DIGEST_VALUELEN; i += 4)
BIG_D2B((Info.uChainVar)[i / 4], pszDigest, i);
}
/**
@brief 사용자 입력 평문을 한번에 처리
@param pszMessage : 사용자 입력 평문
@param pszDigest : 암호문
@remarks 내부적으로 SHA256_Init, SHA256_Process, SHA256_Close를 호출한다.
*/
public static void SHA256_Encrpyt( byte[] pszMessage, int uPlainTextLen, byte[] pszDigest ) {
SHA256_INFO info = new SHA256_INFO();
SHA256_Init( info );
SHA256_Process( info, pszMessage, uPlainTextLen );
SHA256_Close( info, pszDigest );
}
public static class SHA256_INFO {
public int uChainVar[] = new int[SHA256_DIGEST_VALUELEN / 4];
public int uHighLength;
public int uLowLength;
public int remainNum;
public byte szBuffer[] = new byte[SHA256_DIGEST_BLOCKLEN];
}
public static class Common {
public static final int BIG_ENDIAN = 0;
public static final int LITTLE_ENDIAN = 1;
public static void arraycopy(byte[] dst, byte[] src, int length) {
for(int i=0; i<length; i++) {
dst[i] = src[i];
}
}
public static void arraycopy_offset(byte[] dst, int dst_offset, byte[] src, int src_offset, int length) {
for(int i=0; i<length; i++) {
dst[dst_offset+i] = src[src_offset+i];
}
}
public static void arrayinit(byte[] dst, byte value, int length) {
for(int i=0; i<length; i++) {
dst[i] = value;
}
}
public static void arrayinit_offset(byte[] dst, int dst_offset, byte value, int length) {
for(int i=0; i<length; i++) {
dst[dst_offset+i] = value;
}
}
public static void memcpy(int[] dst, byte[] src, int length, int ENDIAN) {
int iLen = length / 4;
for(int i=0; i<iLen; i++) {
byte_to_int(dst, i, src, i*4, ENDIAN);
}
}
public static void memcpy(int[] dst, int[] src, int src_offset, int length) {
int iLen = length / 4 + ((length % 4 != 0)?1:0);
for(int i=0; i<iLen; i++) {
dst[i] = src[src_offset+i];
}
}
public static void set_byte_for_int(int[] dst, int b_offset, byte value, int ENDIAN) {
if(ENDIAN == BIG_ENDIAN) {
int shift_value = (3-b_offset%4)*8;
int mask_value = 0x0ff << shift_value;
int mask_value2 = ~mask_value;
int value2 = (value&0x0ff) << shift_value;
dst[b_offset/4] = (dst[b_offset/4] & mask_value2) | (value2 & mask_value);
} else {
int shift_value = (b_offset%4)*8;
int mask_value = 0x0ff << shift_value;
int mask_value2 = ~mask_value;
int value2 = (value&0x0ff) << shift_value;
dst[b_offset/4] = (dst[b_offset/4] & mask_value2) | (value2 & mask_value);
}
}
public static byte get_byte_for_int(int[] src, int b_offset, int ENDIAN) {
if(ENDIAN == BIG_ENDIAN) {
int shift_value = (3-b_offset%4)*8;
int mask_value = 0x0ff << shift_value;
int value = (src[b_offset/4] & mask_value) >> shift_value;
return (byte)value;
} else {
int shift_value = (b_offset%4)*8;
int mask_value = 0x0ff << shift_value;
int value = (src[b_offset/4] & mask_value) >> shift_value;
return (byte)value;
}
}
public static byte[] get_bytes_for_ints(int[] src, int offset, int ENDIAN) {
int iLen = src.length-offset;
byte[] result = new byte[(iLen)*4];
for(int i=0; i<iLen; i++) {
int_to_byte(result, i*4, src, offset+i, ENDIAN);
}
return result;
}
public static void byte_to_int(int[] dst, int dst_offset, byte[] src, int src_offset, int ENDIAN) {
if(ENDIAN == BIG_ENDIAN) {
dst[dst_offset] = ((0x0ff&src[src_offset]) << 24) | ((0x0ff&src[src_offset+1]) << 16) | ((0x0ff&src[src_offset+2]) << 8) | ((0x0ff&src[src_offset+3]));
} else {
dst[dst_offset] = ((0x0ff&src[src_offset])) | ((0x0ff&src[src_offset+1]) << 8) | ((0x0ff&src[src_offset+2]) << 16) | ((0x0ff&src[src_offset+3]) << 24);
}
}
public static int byte_to_int(byte[] src, int src_offset, int ENDIAN) {
if(ENDIAN == BIG_ENDIAN) {
return ((0x0ff&src[src_offset]) << 24) | ((0x0ff&src[src_offset+1]) << 16) | ((0x0ff&src[src_offset+2]) << 8) | ((0x0ff&src[src_offset+3]));
} else {
return ((0x0ff&src[src_offset])) | ((0x0ff&src[src_offset+1]) << 8) | ((0x0ff&src[src_offset+2]) << 16) | ((0x0ff&src[src_offset+3]) << 24);
}
}
public static int byte_to_int_big_endian(byte[] src, int src_offset) {
return ((0x0ff&src[src_offset]) << 24) | ((0x0ff&src[src_offset+1]) << 16) | ((0x0ff&src[src_offset+2]) << 8) | ((0x0ff&src[src_offset+3]));
}
public static void int_to_byte(byte[] dst, int dst_offset, int[] src, int src_offset, int ENDIAN) {
int_to_byte_unit(dst, dst_offset, src[src_offset], ENDIAN);
}
public static void int_to_byte_unit(byte[] dst, int dst_offset, int src, int ENDIAN) {
if(ENDIAN == BIG_ENDIAN) {
dst[dst_offset] = (byte)((src>> 24) & 0x0ff);
dst[dst_offset+1] = (byte)((src >> 16) & 0x0ff);
dst[dst_offset+2] = (byte)((src >> 8) & 0x0ff);
dst[dst_offset+3] = (byte)((src) & 0x0ff);
} else {
dst[dst_offset] = (byte)((src) & 0x0ff);
dst[dst_offset+1] = (byte)((src >> 8) & 0x0ff);
dst[dst_offset+2] = (byte)((src >> 16) & 0x0ff);
dst[dst_offset+3] = (byte)((src >> 24) & 0x0ff);
}
}
public static void int_to_byte_unit_big_endian(byte[] dst, int dst_offset, int src) {
dst[dst_offset] = (byte)((src>> 24) & 0x0ff);
dst[dst_offset+1] = (byte)((src >> 16) & 0x0ff);
dst[dst_offset+2] = (byte)((src >> 8) & 0x0ff);
dst[dst_offset+3] = (byte)((src) & 0x0ff);
}
public static int URShift(int x, int n) {
if(n == 0)
return x;
if(n >= 32)
return 0;
int v = x >> n;
int v_mask = ~(0x80000000 >> (n-1));
return v & v_mask;
}
public static final long INT_RANGE_MAX = (long)Math.pow(2, 32);
public static long intToUnsigned(int x) {
if(x >= 0)
return x;
return x + INT_RANGE_MAX;
}
}
public static void main(String[] args)
{
byte pbData[] = {(byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07,
(byte)0x08, (byte)0x09, (byte)0x0A, (byte)0x0B, (byte)0x0C, (byte)0x0D, (byte)0x0E, (byte)0x0F,
(byte)0x08, (byte)0x09, (byte)0x0A, (byte)0x0B, (byte)0x0C, (byte)0x0D, (byte)0x0E, (byte)0x0F,
(byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07,
(byte)0x08, (byte)0x09, (byte)0x0A, (byte)0x0B, (byte)0x0C, (byte)0x0D, (byte)0x0E, (byte)0x0F,
(byte)0x08, (byte)0x09, (byte)0x0A, (byte)0x0B, (byte)0x0C, (byte)0x0D, (byte)0x0E, (byte)0x0F};
byte pbData1[] = {(byte)0x61};
byte pbCipher[] = new byte[32];
byte pbPlain[] = new byte[16];
System.out.print("[ Test SHA256 reference code ]"+"\n");
System.out.print("\n\n");
System.out.print("[ Test HASH mode ]"+"\n");
System.out.print("\n");
int Plaintext_length = 1;
for(int k=0; k<30; k++)
{
System.out.print("Plaintext\t: ");
for (int i=0; i<Plaintext_length; i++) System.out.print(Integer.toHexString(0xff&pbData[i])+" ");
System.out.print("\n");
// Encryption
SHA256_Encrpyt( pbData, Plaintext_length, pbCipher );
System.out.print("Ciphertext\t: ");
for (int i=0; i<32; i++) System.out.print(Integer.toHexString(0xff&pbCipher[i])+" ");
System.out.print("\n\n");
Plaintext_length++;
}
System.out.print("Plaintext\t: ");
for (int i=0; i<1; i++) System.out.print(Integer.toHexString(0xff&pbData1[i])+" ");
System.out.print("\n");
// Encryption
SHA256_Encrpyt( pbData1, 1, pbCipher );
System.out.print("Ciphertext\t: ");
for (int i=0; i<32; i++) System.out.print(Integer.toHexString(0xff&pbCipher[i])+" ");
System.out.print("\n\n");
}
}

26
data/cns/build.gradle

@ -0,0 +1,26 @@
dependencies {
implementation "$boot:spring-boot-starter-data-jpa"
implementation "com.querydsl:querydsl-jpa:5.0.0:jakarta"
annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
implementation project(":common:config-db")
testRuntimeOnly "com.h2database:h2"
}
def querydslDir = layout.buildDirectory.dir("generated/querydsl").get().asFile
sourceSets {
main.java.srcDir(querydslDir)
}
tasks.withType(JavaCompile) {
options.getGeneratedSourceOutputDirectory().set(file(querydslDir))
}
clean {
delete file(querydslDir)
}

78
data/cns/src/main/java/kr/co/palnet/kac/data/cns/model/CnsFaqBas.java

@ -0,0 +1,78 @@
package kr.co.palnet.kac.data.cns.model;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@TableGenerator(
table = "COM_SEQ_BAS",
name = "CNS_FAQ_BAS_SEQ",
pkColumnValue = "FAQ_SNO",
allocationSize = 1
)
@Entity
@Table(name = "CNS_FAQ_BAS")
public class CnsFaqBas {
// FAQ일련번호
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "CNS_FAQ_BAS_SEQ")
@Column(name = "FAQ_SNO") // mysql :: "int unsigned"
private Long faqSno;
// 카테고리
@Column(name = "CATEGORY", length = 20)
private String category;
// 제목
@Column(name = "TITLE", nullable = false)
private String title;
// 내용
@Lob
@Column(name = "CONTENT", columnDefinition = "text")
private String content;
// 조회수
@ColumnDefault("0")
@Column(name = "VIEW_CNT", nullable = false)
private Integer viewCnt;
// 표출여부
@Column(name = "EXPSR_YN", columnDefinition = "char(1) default 'N'", nullable = false)
private String expsrYn;
// 삭제여부
@Column(name = "DEL_YN", columnDefinition = "char(1) default 'N'", nullable = false)
private String delYn;
// 등록사용자ID
@Column(name = "CREATE_USER_ID", length = 30, updatable = false, nullable = false)
private String createUserId;
// 등록일시
@CreationTimestamp
@Column(name = "CREATE_DT", columnDefinition = "datetime", updatable = false, nullable = false)
private LocalDateTime createDt;
// 수정사용자ID
@Column(name = "UPDATE_USER_ID", length = 30, nullable = false)
private String updateUserId;
// 수정일시
@UpdateTimestamp
@Column(name = "UPDATE_DT", columnDefinition = "datetime", nullable = false)
private LocalDateTime updateDt;
}

104
data/cns/src/main/java/kr/co/palnet/kac/data/cns/model/CnsQnaBas.java

@ -0,0 +1,104 @@
package kr.co.palnet.kac.data.cns.model;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.ColumnDefault;
import java.time.Instant;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@TableGenerator(
table = "COM_SEQ_BAS",
name = "CNS_QNA_BAS_SEQ",
pkColumnValue = "QNA_SNO",
allocationSize = 1
)
@Entity
@Table(name = "CNS_QNA_BAS")
public class CnsQnaBas {
// QNA일련번호
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "CNS_QNA_BAS_SEQ")
@Column(name = "QNA_SNO") // mysql :: "int unsigned"
private Long qnaSno;
// 상위QNA일련번호
@Column(name = "TARGET_SNO") // mysql :: "int unsigned"
private Long targetSno;
// 카테고리
@Column(name = "CATEGORY", length = 20)
private String category;
// 제목
@Column(name = "TITLE", nullable = false)
private String title;
// 내용
@Lob
@Column(name = "CONTENT", columnDefinition = "text")
private String content;
// 연락처
@Column(name = "CONTACT", length = 20)
private String contact;
// 답변내용
@Lob
@Column(name = "ANSER_CONTENT", columnDefinition = "text")
private String anserContent;
// 답변자
@Column(name = "ANSER_USER_NM", length = 50)
private String anserUserNm;
// 답변처리일시
@Column(name = "ANSER_PROC_DT", columnDefinition = "datetime")
private Instant anserProcDt;
// 답변상태
@Column(name = "ANSER_STATUS", length = 10)
private String anserStatus; // 질문, 답변중, 답변완료, 보류
// 파일그룹번호
@Column(name = "FILE_GROUP_NO") // mysql :: "int unsigned"
private Long fileGroupNo;
// 표출여부
@Column(name = "EXPSR_YN", columnDefinition = "char(1) default 'N'", nullable = false)
private String expsrYn;
// 삭제여부
@Column(name = "DEL_YN", columnDefinition = "char(1) default 'N'", nullable = false)
private String delYn;
// 조회수
@ColumnDefault("0")
@Column(name = "VIEW_CNT", nullable = false)
private Integer viewCnt;
// 등록사용자ID
@Column(name = "CREATE_USER_ID", length = 30, updatable = false, nullable = false)
private String createUserId;
// 등록일시
@Column(name = "CREATE_DT", columnDefinition = "datetime", updatable = false, nullable = false)
private Instant createDt;
// 수정사용자ID
@Column(name = "UPDATE_USER_ID", length = 30, nullable = false)
private String updateUserId;
// 수정일시
@Column(name = "UPDATE_DT", columnDefinition = "datetime", nullable = false)
private Instant updateDt;
}

28
data/cns/src/main/java/kr/co/palnet/kac/data/cns/repository/CnsFaqBasRepository.java

@ -0,0 +1,28 @@
package kr.co.palnet.kac.data.cns.repository;
import jakarta.transaction.Transactional;
import kr.co.palnet.kac.data.cns.model.CnsFaqBas;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface CnsFaqBasRepository extends JpaRepository<CnsFaqBas, Integer> {
@Modifying
@Transactional
@Query("update CnsFaqBas c set c.viewCnt = c.viewCnt + 1" +
"where c.faqSno = :sno")
int updateViewCnt(@Param("sno") int sno);
@Modifying
@Transactional
@Query("update CnsFaqBas c set c.delYn = 'Y' " +
"where c.faqSno = :sno")
int deleteFaq(@Param("sno") int sno);
}

165
data/cns/src/main/java/kr/co/palnet/kac/data/cns/repository/CnsFaqQueryRepository.java

@ -0,0 +1,165 @@
package kr.co.palnet.kac.data.cns.repository;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import kr.co.palnet.kac.data.cns.model.CnsFaqBas;
import kr.co.palnet.kac.data.cns.model.QCnsFaqBas;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import java.util.List;
@Slf4j
@Repository
@RequiredArgsConstructor
public class CnsFaqQueryRepository {
private final JPAQueryFactory query;
/**
* 조건값으로 FaQ리스트를 조회하는 SQL기능.
* @param category
* @param word
* @return
*/
public List<CnsFaqBas> getFaqList(String category, String word) {
QCnsFaqBas bas = QCnsFaqBas.cnsFaqBas;
BooleanBuilder builder = new BooleanBuilder();
builder.and(bas.delYn.eq("N"));
builder.and(bas.expsrYn.eq("Y"));
if (category != null) {
builder.and(bas.category.eq(category));
}
if (word != null) {
builder.and(bas.title.contains(word));
}
/**
* 삭제여부[delYn]값이 'N' 조건,
* 표출여부[expsrYn]값이 'Y' 조건,
* 카테고리값[category] 조건,
* 제목[title] 값이 word와의 조건 값으로 조회하는 SQL 입니다.
*
* SELECT
* CFB.FAQ_SNO ,
* CFB.CATEGORY ,
* CFB.TITLE ,
* CFB.CONTENT ,
* CFB.VIEW_CNT ,
* CFB.EXPSR_YN ,
* CFB.CREATE_USER_ID ,
* CFB.CREATE_DT ,
* CFB.UPDATE_USER_ID ,
* CFB.UPDATE_DT
* FROM CNS_FAQ_BAS CFB
* WHERE CFB.DEL_YN = 'N'
* AND CFB.EXPSR_YN = 'Y'
* AND CFB.CATEGORY = #{category}
* AND CFB.TITLE = #{word}
* ORDER BY CFB.CREATE_DT DESC
*/
List<CnsFaqBas> r = query
.select(Projections.bean(
CnsFaqBas.class,
bas.faqSno,
bas.category,
bas.title,
bas.content,
bas.viewCnt,
bas.expsrYn,
bas.createUserId,
bas.createDt,
bas.updateUserId,
bas.updateDt
))
.from(bas)
.where(builder)
.orderBy(bas.createDt.desc())
.fetch();
return r;
}
/**
* 일련번호[sno] 상세정보를 조회하는 SQL 기능.
* @param sno
* @return
*/
public CnsFaqBas getFaqDetail(int sno) {
QCnsFaqBas bas = QCnsFaqBas.cnsFaqBas;
BooleanBuilder builder = new BooleanBuilder();
builder.and(bas.faqSno.eq((long) sno));
builder.and(bas.expsrYn.eq("Y"));
builder.and(bas.delYn.eq("N"));
/**
* 일련번호[faqSno] 조건,
* 표출여부[expsrYn] 'Y' 인지 조건,
* 삭제여부[delYn] 'N' 인지 조건으로 조회하는 SQL 입니다.
*
* SELECT
* CFB.FAQ_SNO ,
* CFB.CATEGORY ,
* CFB.TITLE ,
* CFB.CONTENT ,
* CFB.VIEW_CNT ,
* CFB.EXPSR_YN ,
* CFB.CREATE_USER_ID ,
* CFB.CREATE_DT ,
* CFB.UPDATE_USER_ID ,
* CFB.UPDATE_DT
* FROM CNS_FAQ_BAS CFB
* WHERE CFB.FAQ_SNO = #{sno}
* AND CFB.EXPSR_YN = 'Y'
* AND CFB.DEL_YN = 'N'
*/
CnsFaqBas r = query
.select(Projections.bean(
CnsFaqBas.class,
bas.faqSno,
bas.category,
bas.title,
bas.content,
bas.viewCnt,
bas.expsrYn,
bas.createUserId,
bas.createDt,
bas.updateUserId,
bas.updateDt
))
.from(bas)
.where(builder)
.fetchOne();
return r;
}
public void updateFaq(CnsFaqBas model) {
QCnsFaqBas bas = QCnsFaqBas.cnsFaqBas;
BooleanBuilder builder = new BooleanBuilder();
builder.and(bas.faqSno.eq(model.getFaqSno()));
query.update(bas)
.set(bas.category, model.getCategory())
.set(bas.title, model.getTitle())
.set(bas.content, model.getContent())
.set(bas.viewCnt, model.getViewCnt())
.set(bas.expsrYn, model.getExpsrYn())
.set(bas.updateUserId, model.getUpdateUserId())
.set(bas.updateDt, model.getUpdateDt())
.where(builder)
.execute();
}
}

23
data/cns/src/main/java/kr/co/palnet/kac/data/cns/repository/CnsQnaBasRepository.java

@ -0,0 +1,23 @@
package kr.co.palnet.kac.data.cns.repository;
import kr.co.palnet.kac.data.cns.model.CnsQnaBas;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface CnsQnaBasRepository extends JpaRepository<CnsQnaBas, Integer> {
CnsQnaBas findFirstByTargetSnoAndDelYnAndExpsrYn(int targetSno, String delYn, String expsrYn);
CnsQnaBas findByQnaSnoAndDelYnAndExpsrYn(int qnaSno, String delYn, String expsrYn);
CnsQnaBas findFirstByQnaSnoAndTargetSnoAndDelYnAndExpsrYn(int qnaSno, int targetSno, String delYn, String expsrYn);
@Modifying
@Query("UPDATE CnsQnaBas q SET q.viewCnt = q.viewCnt + 1 WHERE q.qnaSno = :qnaSno")
void pulsViewCount(@Param("qnaSno")int qnaSno);
}

42
data/cns/src/main/java/kr/co/palnet/kac/data/cns/service/CnsFaqDomainService.java

@ -0,0 +1,42 @@
package kr.co.palnet.kac.data.cns.service;
import kr.co.palnet.kac.data.cns.model.CnsFaqBas;
import kr.co.palnet.kac.data.cns.repository.CnsFaqBasRepository;
import kr.co.palnet.kac.data.cns.repository.CnsFaqQueryRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
@RequiredArgsConstructor
public class CnsFaqDomainService {
private final CnsFaqBasRepository cnsFaqBasRepository;
private final CnsFaqQueryRepository query;
public List<CnsFaqBas> getFaqList(String category, String word){
return query.getFaqList(category, word);
}
public void updateViewCnt(int sno){
cnsFaqBasRepository.updateViewCnt(sno);
}
public CnsFaqBas getFaqDetail(int sno){
return query.getFaqDetail(sno);
}
public CnsFaqBas saveFaqBas(CnsFaqBas cnsFaqBas){
return cnsFaqBasRepository.save(cnsFaqBas);
}
public Optional<CnsFaqBas> findById(int faqSno){
return cnsFaqBasRepository.findById(faqSno);
}
public int deleteFaq(int faqSno){
return cnsFaqBasRepository.deleteFaq(faqSno);
}
}

26
data/com/build.gradle

@ -0,0 +1,26 @@
dependencies {
implementation "$boot:spring-boot-starter-data-jpa"
implementation "com.querydsl:querydsl-jpa:5.0.0:jakarta"
annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
implementation project(":common:config-db")
testRuntimeOnly "com.h2database:h2"
}
def querydslDir = layout.buildDirectory.dir("generated/querydsl").get().asFile
sourceSets {
main.java.srcDir(querydslDir)
}
tasks.withType(JavaCompile) {
options.getGeneratedSourceOutputDirectory().set(file(querydslDir))
}
clean {
delete file(querydslDir)
}

53
data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComAdmDistrictBas.java

@ -0,0 +1,53 @@
package kr.co.palnet.kac.data.com.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
@Table(name = "COM_ADM_DISTRICT_BAS")
public class ComAdmDistrictBas {
// 행정코드
@Id
@Column(name = "ADM_CD", length = 10)
private String admCd;
// 행정구역명
@Column(name = "ADM_SECT_NM", length = 100)
private String admSectNm;
// 최하위행정구역명
@Column(name = "LOWEST_ADM_SECT_NM", length = 100)
private String lowestAdmSectNm;
// 레벨
@Column(name = "LEVEL")
private Integer level;
// 상위행정코드
@Column(name = "UP_ADM_CD", length = 10)
private String upAdmCd;
// 삭제일자
@Column(name = "DEL_YMD", length = 8)
private String delYmd;
// 변경전행정구역구분
@Column(name = "CHG_BEF_ADM_SECT_GBN", length = 1)
private String chgBefAdmSectGbn;
// 생성일자
@Column(name = "CRE_YMD", length = 8)
private String creYmd;
// 변경전행정구역코드
@Column(name = "CHG_BEF_ADM_SECT_CD", length = 10)
private String chgBefAdmSectCd;
// 원천시군구코드
@Column(name = "COL_ADM_SECT_CD", length = 5)
private String colAdmSectCd;
}

114
data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComArcrftBas.java

@ -0,0 +1,114 @@
package kr.co.palnet.kac.data.com.domain;
import jakarta.persistence.*;
import lombok.*;
import java.time.Instant;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString(exclude = {"comIdntfBasList"})
@TableGenerator(
table = "COM_SEQ_BAS",
name = "COM_ARCRFT_BAS_SEQ",
pkColumnValue = "ARCRFT_SNO",
allocationSize = 1
)
@Entity
@Table(name = "COM_ARCRFT_BAS")
public class ComArcrftBas {
// 기체일련번호
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "COM_ARCRFT_BAS_SEQ")
@Column(name = "ARCRFT_SNO") // mysql :: "int unsigned"
private Long arcrftSno;
// 그룹ID
@Column(name = "GROUP_ID", length = 50)
private String groupId;
// 제작번호
@Column(name = "PRDCT_NUM", length = 50, nullable = false)
private String prdctNum;
// 기체종류코드
@Column(name = "ARCRFT_TYPE_CD", length = 20, nullable = false)
private String arcrftTypeCd;
// 기체모델명
@Column(name = "ARCRFT_MODEL_NM", length = 50, nullable = false)
private String arcrftModelNm;
// 제작자
@Column(name = "PRDCT_CMPN_NM", length = 50)
private String prdctCmpnNm;
// 제작일자
@Column(name = "PRDCT_DATE", columnDefinition = "datetime")
private Instant prdctDate;
// 기체길이
@Column(name = "ARCRFT_LNGTH", columnDefinition = "double")
private double arcrftLngth;
// 기체폭
@Column(name = "ARCRFT_WDTH", columnDefinition = "double")
private double arcrftWdth;
// 기체높이
@Column(name = "ARCRFT_HGHT", columnDefinition = "double")
private double arcrftHght;
// 자체중량
@Column(name = "ARCRFT_WGHT", columnDefinition = "double")
private double arcrftWght;
// 중량구분코드
@Column(name = "WGHT_TYPE_CD", length = 20, nullable = false)
private String wghtTypeCd;
// 이미지URL
@Column(name = "IMAGE_URL", length = 200)
private String imageUrl;
// 최대이륙중량
@Column(name = "TAKEOFF_WGHT", columnDefinition = "double")
private double takeoffWght;
// 사용여부
@Column(name = "USE_YN", columnDefinition = "char(1) default 'N'", nullable = false)
private String useYn;
// 카메라탑재여부
@Column(name = "CAMERA_YN", columnDefinition = "char(1) default 'N'", nullable = false)
private String cameraYn;
// 보험가입여부
@Column(name = "INSRNC_YN", columnDefinition = "char(1) default 'N'", nullable = false)
private String insrncYn;
// 등록일자
@Column(name = "CREATE_DT", columnDefinition = "datetime", updatable = false, nullable = false)
private Instant createDt;
// 등록사용자ID
@Column(name = "CREATE_USER_ID", length = 30, updatable = false, nullable = false)
private String createUserId;
// 수정일자
@Column(name = "UPDATE_DT", columnDefinition = "datetime", nullable = false)
private Instant updateDt;
// 수정사용자ID
@Column(name = "UPDATE_USER_ID", length = 30, nullable = false)
private String updateUserId;
@OneToMany(mappedBy = "comArcrftBas", fetch = FetchType.LAZY)
private List<ComIdntfBas> comIdntfBasList;
}

63
data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComAuthBas.java

@ -0,0 +1,63 @@
package kr.co.palnet.kac.data.com.domain;
import jakarta.persistence.*;
import lombok.*;
import java.time.Instant;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString(exclude = {"comSiteBas"})
@Entity
@Table(name = "COM_AUTH_BAS")
public class ComAuthBas {
// 권한ID
@Id
@Column(name = "AUTH_ID", length = 50)
private String authId;
// 사이트코드
@Column(name = "SITE_CD", length = 20, nullable = false)
private String siteCd;
// 권한명
@Column(name = "AUTH_NM", length = 100, nullable = false)
private String authNm;
// 사용여부
@Column(name = "USE_YN", columnDefinition = "char(1) default 'N'", nullable = false)
private String useYn;
// 비고
@Lob
@Column(name = "RM", columnDefinition = "mediumtext")
private String rm;
// 생성사용자ID
@Column(name = "CREATE_USER_ID", length = 30, updatable = false, nullable = false)
private String createUserId;
// 생성일시
@Column(name = "CREATE_DT", columnDefinition = "datetime", updatable = false, nullable = false)
private Instant createDt;
// 수정사용자ID
@Column(name = "UPDATE_USER_ID", length = 30, nullable = false)
private String updateUserId;
// 수정일시
@Column(name = "UPDATE_DT", columnDefinition = "datetime", nullable = false)
private Instant updateDt;
@JoinColumn(
name = "SITE_CD", updatable = false, insertable = false,
foreignKey = @ForeignKey(name = "FK_COM_AUTH_BAS_COM_SITE_BAS_SITE_CD")
)
@ManyToOne(fetch = FetchType.LAZY)
private ComSiteBas comSiteBas;
}

103
data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComCdBas.java

@ -0,0 +1,103 @@
package kr.co.palnet.kac.data.com.domain;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.*;
import lombok.*;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString(exclude = {"comCdGroupBas", "comCdLangCtgList"})
@IdClass(ComCdBas.ComCdBasId.class)
@Entity
@Table(name = "COM_CD_BAS")
public class ComCdBas {
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class ComCdBasId implements Serializable {
// 그룹코드
private String groupCd;
// 코드ID
private String cdId;
}
// 그룹코드
@Id
@Column(name = "GROUP_CD", length = 20)
private String groupCd;
// 코드ID
@Id
@Column(name = "CD_ID", length = 30)
private String cdId;
// 상위코드
@Column(name = "UPPER_CD", length = 20)
private String upperCd;
// 정렬순서
@Column(name = "SORT_ORDR", columnDefinition = "tinyint default 0", nullable = false)
private Integer sortOrdr;
// 추가정보값
@Column(name = "ADD_INFO_VALUE", length = 100)
private String addInfoValue;
// 사용여부
@Column(name = "USE_YN", columnDefinition = "char(1) default 'Y'", nullable = false)
private String useYn;
// 생성사용자ID
@Column(name = "CREATE_USER_ID", length = 30, nullable = false, updatable = false)
private String createUserId;
// 생성일시
@Column(name = "CREATE_DT", columnDefinition = "datetime", nullable = false, updatable = false)
private LocalDateTime createDt;
// 수정사용자ID
@Column(name = "UPDATE_USER_ID", length = 30, nullable = false)
private String updateUserId;
// 수정일시
@Column(name = "UPDATE_DT", columnDefinition = "datetime", nullable = false)
private LocalDateTime updateDt;
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "GROUP_CD", updatable = false, insertable = false,
foreignKey = @ForeignKey(name = "FK_COM_CD_BAS_TO_COM_CD_GROUP_BAS")
)
private ComCdGroupBas comCdGroupBas;
@OneToMany(mappedBy = "comCdBas", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
private List<ComCdLangCtg> comCdLangCtgList;
public void update(ComCdBas comCdBas) {
if (comCdBas == null) return;
if (comCdBas.getGroupCd() != null && !comCdBas.getGroupCd().isBlank()) this.groupCd = comCdBas.getGroupCd();
if (comCdBas.getCdId() != null && !comCdBas.getCdId().isBlank()) this.cdId = comCdBas.getCdId();
if (comCdBas.getUpperCd() != null && !comCdBas.getUpperCd().isBlank()) this.upperCd = comCdBas.getUpperCd();
if (comCdBas.getSortOrdr() != null) this.sortOrdr = comCdBas.getSortOrdr();
if (comCdBas.getAddInfoValue() != null && !comCdBas.getAddInfoValue().isBlank())
this.addInfoValue = comCdBas.getAddInfoValue();
if (comCdBas.getUseYn() != null && !comCdBas.getUseYn().isBlank()) this.useYn = comCdBas.getUseYn();
if (comCdBas.getUpdateUserId() != null && !comCdBas.getUpdateUserId().isBlank())
this.updateUserId = comCdBas.getUpdateUserId();
if (comCdBas.getUpdateDt() != null) this.updateDt = comCdBas.getUpdateDt();
}
}

70
data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComCdGroupBas.java

@ -0,0 +1,70 @@
package kr.co.palnet.kac.data.com.domain;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
@Table(name = "COM_CD_GROUP_BAS")
public class ComCdGroupBas {
// 그룹코드
@Id
@Column(name = "GROUP_CD", length = 20)
private String groupCd;
// 사이트코드
@Column(name = "SITE_CD", length = 20, nullable = false)
private String siteCd;
// 그룹코드명
@Column(name = "GROUP_CD_NM", length = 100, nullable = false)
private String groupCdNm;
// 비고
@Lob
@Column(name = "RM", columnDefinition = "mediumtext")
private String rm;
// 생성사용자ID
@Column(name = "CREATE_USER_ID", length = 30, nullable = false, updatable = false)
private String createUserId;
// 생성일시
@Column(name = "CREATE_DT", columnDefinition = "datetime", nullable = false, updatable = false)
private LocalDateTime createDt;
// 수정사용자ID
@Column(name = "UPDATE_USER_ID", length = 30, nullable = false)
private String updateUserId;
// 수정일시
@Column(name = "UPDATE_DT", columnDefinition = "datetime", nullable = false)
private LocalDateTime updateDt;
@OneToMany(mappedBy = "comCdGroupBas", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
private List<ComCdBas> comCdBasList;
public void update(ComCdGroupBas comCdGroupBas) {
if(comCdGroupBas == null) return;
// if(comCdGroupBas.getGroupCd() != null && this.groupCd != null && !this.groupCd.equals(comCdGroupBas.getGroupCd())) return;
if(comCdGroupBas.getGroupCd() != null && !comCdGroupBas.getGroupCd().isBlank()) this.groupCd = comCdGroupBas.getGroupCd();
if(comCdGroupBas.getSiteCd() != null && !comCdGroupBas.getSiteCd().isBlank()) this.siteCd = comCdGroupBas.getSiteCd();
if(comCdGroupBas.getGroupCdNm() != null && !comCdGroupBas.getGroupCdNm().isBlank()) this.groupCdNm = comCdGroupBas.getGroupCdNm();
if(comCdGroupBas.getRm() != null && !comCdGroupBas.getRm().isBlank()) this.rm = comCdGroupBas.getRm();
if(comCdGroupBas.getUpdateUserId() != null && !comCdGroupBas.getUpdateUserId().isBlank()) this.updateUserId = comCdGroupBas.getUpdateUserId();
if(comCdGroupBas.getUpdateDt() != null) this.updateDt = comCdGroupBas.getUpdateDt();
}
}

106
data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComCdLangCtg.java

@ -0,0 +1,106 @@
package kr.co.palnet.kac.data.com.domain;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.*;
import lombok.*;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString(exclude = {"comCdBas"})
@IdClass(ComCdLangCtg.ComCdLangCtgId.class)
@Entity
@Table(name = "COM_CD_LANG_CTG")
public class ComCdLangCtg {
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class ComCdLangCtgId implements Serializable {
// 그룹코드
private String groupCd;
// 코드ID
private String cdId;
// 언어구분코드
private String langDivCd;
}
// 그룹코드
@Id
@Column(name = "GROUP_CD", length = 20)
private String groupCd;
// 코드ID
@Id
@Column(name = "CD_ID", length = 30)
private String cdId;
// 언어구분코드
@Id
@Column(name = "LANG_DIV_CD", length = 5)
private String langDivCd;
// 코드명
@Column(name = "CD_NM", length = 100, nullable = false)
private String cdNm;
// 비고
@Lob
@Column(name = "RM", columnDefinition = "mediumtext")
private String rm;
// 생성사용자ID
@Column(name = "CREATE_USER_ID", length = 30, nullable = false, updatable = false)
private String createUserId;
// 생성일시
@Column(name = "CREATE_DT", columnDefinition = "datetime", nullable = false, updatable = false)
private LocalDateTime createDt;
// 수정사용자ID
@Column(name = "UPDATE_USER_ID", length = 30, nullable = false)
private String updateUserId;
// 수정일시
@Column(name = "UPDATE_DT", columnDefinition = "datetime", nullable = false)
private LocalDateTime updateDt;
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns(
value = {
@JoinColumn(name = "GROUP_CD", referencedColumnName = "GROUP_CD", insertable = false, updatable = false),
@JoinColumn(name = "CD_ID", referencedColumnName = "CD_ID", insertable = false, updatable = false)
},
foreignKey = @ForeignKey(name = "FK_COM_CD_LANG_CTG_COM_CD_BAS")
)
private ComCdBas comCdBas;
public void update(ComCdLangCtg comCdLangCtg) {
if (comCdLangCtg == null) return;
// if(comCdLangCtg.getId() != null) {
// if(comCdLangCtg.getId().getComCdBasId() != null) {
// if(comCdLangCtg.getId().getComCdBasId().getGroupCd() != null && !comCdLangCtg.getId().getComCdBasId().getGroupCd().isBlank()) this.id.comCdBasId.setGroupCd(comCdLangCtg.getId().getComCdBasId().getGroupCd());
// if(comCdLangCtg.getId().getComCdBasId().getCdId() != null && !comCdLangCtg.getId().getComCdBasId().getCdId().isBlank()) this.id.comCdBasId.setCdId(comCdLangCtg.getId().getComCdBasId().getCdId());
// }
// if(comCdLangCtg.getId().getLangDivCd() != null && !comCdLangCtg.getId().getLangDivCd().isBlank()) this.id.langDivCd = comCdLangCtg.getId().getLangDivCd();
// }
if (comCdLangCtg.getGroupCd() != null && !comCdLangCtg.getGroupCd().isBlank()) this.groupCd = comCdLangCtg.getGroupCd();
if (comCdLangCtg.getCdId() != null && !comCdLangCtg.getCdId().isBlank()) this.cdId = comCdLangCtg.getCdId();
if (comCdLangCtg.getLangDivCd() != null && !comCdLangCtg.getLangDivCd().isBlank())
this.langDivCd = comCdLangCtg.getLangDivCd();
if (comCdLangCtg.getCdNm() != null && !comCdLangCtg.getCdNm().isBlank()) this.cdNm = comCdLangCtg.getCdNm();
if (comCdLangCtg.getRm() != null && !comCdLangCtg.getRm().isBlank()) this.rm = comCdLangCtg.getRm();
if (comCdLangCtg.getUpdateUserId() != null && !comCdLangCtg.getUpdateUserId().isBlank())
this.updateUserId = comCdLangCtg.getUpdateUserId();
if (comCdLangCtg.getUpdateDt() != null) this.updateDt = comCdLangCtg.getUpdateDt();
}
}

74
data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComConfirmBas.java

@ -0,0 +1,74 @@
package kr.co.palnet.kac.data.com.domain;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.Instant;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableGenerator(
table = "COM_SEQ_BAS",
name = "COM_CONFIRM_BAS_SEQ",
pkColumnValue = "CONFIRM_SNO",
allocationSize = 1
)
@Entity
@Table(name = "COM_CONFIRM_BAS")
public class ComConfirmBas {
// 확인일련번호
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "COM_CONFIRM_BAS_SEQ")
@Column(name = "CONFIRM_SNO") // mysql :: "int unsigned"
private Long confirmSno;
// 확인키
@Column(name = "CONFIRM_KEY", length = 50, nullable = false)
private String confirmKey;
// 상태
@Column(name = "STATUS", length = 20, nullable = false)
private String status; // GENERATED, RECEIVED, CHECKED, FAILED, EXPIRED
// 대상구분
@Column(name = "TARGET_TYPE", length = 100)
private String targetType;
// RQ 데이터
@Lob
@Column(name = "RQ_DATA", columnDefinition = "text")
private String rqData;
// RS 데이터
@Lob
@Column(name = "RS_DATA", columnDefinition = "text")
private String rsData;
// 비고
@Lob
@Column(name = "RM", columnDefinition = "text")
private String rm;
// 생성사용자ID
@Column(name = "CREATE_USER_ID", length = 30, updatable = false, nullable = false)
private String createUserId;
// 생성일시
@Column(name = "CREATE_DT", columnDefinition = "datetime", updatable = false, nullable = false)
private Instant createDt;
// 수정사용자ID
@Column(name = "UPDATE_USER_ID", length = 30, nullable = false)
private String updateUserId;
// 수정일시
@Column(name = "UPDATE_DT", columnDefinition = "datetime", nullable = false)
private Instant updateDt;
}

85
data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComFileBas.java

@ -0,0 +1,85 @@
package kr.co.palnet.kac.data.com.domain;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.Instant;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@TableGenerator(
table = "COM_SEQ_BAS",
name = "COM_FILE_BAS_SEQ",
pkColumnValue = "FILE_SNO",
allocationSize = 1
)
@Entity
@Table(name = "COM_FILE_BAS")
public class ComFileBas {
// 파일일련번호
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "COM_FILE_BAS_SEQ")
@Column(name = "FILE_SNO") // mysql :: "int unsigned"
private Long fileSno;
// 파일그룹번호
@Column(name = "FILE_GROUP_NO") // mysql :: "int unsigned"
private Long fileGroupNo;
// 저장된파일명
@Column(name = "FILE_SAVE_NM", length = 200, nullable = false)
private String fileSaveNm;
// 실제파일명
@Column(name = "FILE_ORI_NM", length = 200)
private String fileOriNm;
// 파일저장경로
@Column(name = "FILE_PATH", length = 200)
private String filePath;
// 파일확장명
@Column(name = "FILE_EXT", length = 30)
private String fileExt;
// 파일크기
@Column(name = "FILE_SIZE", length = 30)
private String fileSize;
// 삭제여부
@Column(name = "DEL_YN", columnDefinition = "char(1) default 'N'", nullable = false)
private String delYn;
// 삭제사용자ID
@Column(name = "DEL_USER_ID", length = 30)
private String delUserId;
// 삭제일시
@Column(name = "DEL_DT", columnDefinition = "datetime")
private Instant delDt;
// 생성사용자ID
@Column(name = "CREATE_USER_ID", length = 30, updatable = false, nullable = false)
private String createUserId;
// 생성일시
@Column(name = "CREATE_DT", columnDefinition = "datetime", updatable = false, nullable = false)
private Instant createDt;
}

72
data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComIdntfBas.java

@ -0,0 +1,72 @@
package kr.co.palnet.kac.data.com.domain;
import jakarta.persistence.*;
import lombok.*;
import java.io.Serializable;
import java.time.Instant;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString(exclude = {"comArcrftBas"})
@IdClass(ComIdntfBas.ComIdntfBasId.class)
@Entity
@Table(name = "COM_IDNTF_BAS")
public class ComIdntfBas {
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class ComIdntfBasId implements Serializable {
// 식별번호
private String idntfNum;
// 기체일련번호
private Long arcrftSno;
}
// 식별번호
@Id
@Column(name = "IDNTF_NUM", length = 30)
private String idntfNum;
// 기체일련번호
@Id
@Column(name = "ARCRFT_SNO") // mysql :: "int unsigned"
private Long arcrftSno;
// 식별장치종류코드
@Column(name = "IDNTF_TYPE_CD", length = 20, nullable = false)
private String idntfTypeCd;
// 소유자명
@Column(name = "OWNER_NM", length = 100, nullable = false)
private String ownerNm;
// 고객일련번호(소유자)
@Column(name = "CSTMR_SNO") // mysql :: "int unsigned"
private Long cstmrSno;
// 휴대폰번호
@Column(name = "HPNO", length = 100, nullable = false)
private String hpno;
// 등록일자
@Column(name = "CREATE_DT", columnDefinition = "datetime", updatable = false, nullable = false)
private Instant createDt;
// 수정일자
@Column(name = "UPDATE_DT", columnDefinition = "datetime", nullable = false)
private Instant updateDt;
@JoinColumn(
name = "ARCRFT_SNO", updatable = false, insertable = false,
foreignKey = @ForeignKey(name = "FK_COM_IDNTF_BAS_COM_ARCRFT_BAS_ARCRFT_SNO")
)
@ManyToOne(fetch = FetchType.LAZY)
private ComArcrftBas comArcrftBas;
}

111
data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComRiseSetBas.java

@ -0,0 +1,111 @@
package kr.co.palnet.kac.data.com.domain;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.io.Serializable;
import java.time.Instant;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@IdClass(ComRiseSetBas.ComRiseSetBasId.class)
@Entity
@Table(name = "COM_RISE_SET_BAS")
public class ComRiseSetBas {
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class ComRiseSetBasId implements Serializable {
// 날짜
private String locDate;
// 지역
private String location;
}
// 날짜
@Id
@Column(name = "LOC_DATE", length = 8)
private String locDate;
// 지역
@Id
@Column(name = "LOCATION", length = 100)
private String location;
// 경도
@Column(name = "LON", columnDefinition = "double")
private Double lon;
// 위도
@Column(name = "LAT" , columnDefinition = "double")
private Double lat;
// 일출
@Column(name = "SUNRISE", length = 6)
private String sunrise;
// 일증
@Column(name = "SUNTRANSIT", length = 6)
private String suntransit;
// 일몰
@Column(name = "SUNSET", length = 6)
private String sunset;
// 월출
@Column(name = "MOONRISE", length = 6)
private String moonrise;
// 월중
@Column(name = "MOONTRANSIT", length = 6)
private String moontransit;
// 월몰
@Column(name = "MOONSET", length = 6)
private String moonset;
// 시민박명(아침)
@Column(name = "CIVILM", length = 6)
private String civilm;
// 시민박명(저녁)
@Column(name = "CIVILE", length = 6)
private String civile;
// 황해박명(아침)
@Column(name = "NAUTM", length = 6)
private String nautm;
// 황해박명(저녁)
@Column(name = "NAUTE", length = 6)
private String naute;
// 천문박명(아침)
@Column(name = "ASTM", length = 6)
private String astm;
// 춘문박명(저녁)
@Column(name = "ASTE", length = 6)
private String aste;
// 수정일시
@Column(name = "UPDATE_DT", columnDefinition = "datetime")
private Instant updateDt;
// 등록일시
@Column(name = "CREATE_DT", columnDefinition = "datetime", updatable = false)
private Instant createDt;
}

59
data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComSiteBas.java

@ -0,0 +1,59 @@
package kr.co.palnet.kac.data.com.domain;
import jakarta.persistence.*;
import lombok.*;
import java.time.Instant;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString(exclude = {"comAuthBasList"})
@Entity
@Table(name = "COM_SITE_BAS")
public class ComSiteBas {
// 사이트코드
@Id
@Column(name = "SITE_CD", length = 20)
private String siteCd;
// 사이트경로
@Column(name = "SITE_URL", length = 50, nullable = false)
private String siteUrl;
// 사이트명
@Column(name = "SITE_NM", length = 50, nullable = false)
private String siteNm;
// 사이트설명
@Lob
@Column(name = "SITE_DESC", columnDefinition = "text")
private String siteDesc;
// 사용여부
@Column(name = "USE_YN", columnDefinition = "char(1) default 'N'", nullable = false)
private String useYn;
// 등록일자
@Column(name = "CREATE_DT", columnDefinition = "datetime", updatable = false, nullable = false)
private Instant createDt;
// 등록사용자
@Column(name = "CREATE_USER_ID", length = 30, updatable = false, nullable = false)
private String createUserId;
// 수정일자
@Column(name = "UPDATE_DT", columnDefinition = "datetime", nullable = false)
private Instant updateDt;
// 수정사용자
@Column(name = "UPDATE_USER_ID", length = 30, nullable = false)
private String updateUserId;
@OneToMany(mappedBy = "comSiteBas", fetch = FetchType.LAZY)
private List<ComAuthBas> comAuthBasList;
}

58
data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComTrmnlBas.java

@ -0,0 +1,58 @@
package kr.co.palnet.kac.data.com.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.Instant;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
@Table(name = "COM_TRMNL_BAS")
public class ComTrmnlBas {
// 터미널ID
@Id
@Column(name = "TRMNL_ID", length = 20)
private String trmnlId;
// 터미널명
@Column(name = "TRMNL_NM", length = 100, nullable = false)
private String trmnlNm;
// 인증KEY
@Column(name = "AUTH_KEY", length = 100, nullable = false)
private String authKey;
// 터미널설명
@Column(name = "DESC_SN")
private String descSn;
// 사용여부
@Column(name = "USE_YN", columnDefinition = "char(1) default 'N'", nullable = false)
private String useYn;
// 등록일시
@Column(name = "CREATE_DT", columnDefinition = "datetime", updatable = false, nullable = false)
private Instant createDt;
// 등록사용자ID
@Column(name = "CREATE_USER_ID", length = 30, updatable = false, nullable = false)
private String createUserId;
// 수정일시
@Column(name = "UPDATE_DT", columnDefinition = "datetime", nullable = false)
private Instant updateDt;
// 수정사용자ID
@Column(name = "UPDATE_USER_ID", length = 30, nullable = false)
private String updateUserId;
}

7
data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComAdmDistrictBasRepository.java

@ -0,0 +1,7 @@
package kr.co.palnet.kac.data.com.repository;
import kr.co.palnet.kac.data.com.domain.ComAdmDistrictBas;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ComAdmDistrictBasRepository extends JpaRepository<ComAdmDistrictBas, String> {
}

7
data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComArcrftBasRepository.java

@ -0,0 +1,7 @@
package kr.co.palnet.kac.data.com.repository;
import kr.co.palnet.kac.data.com.domain.ComArcrftBas;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ComArcrftBasRepository extends JpaRepository<ComArcrftBas, Integer> {
}

7
data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComAuthBasRepository.java

@ -0,0 +1,7 @@
package kr.co.palnet.kac.data.com.repository;
import kr.co.palnet.kac.data.com.domain.ComAuthBas;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ComAuthBasRepository extends JpaRepository<ComAuthBas, String>{
}

14
data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComCdBasRepository.java

@ -0,0 +1,14 @@
package kr.co.palnet.kac.data.com.repository;
import kr.co.palnet.kac.data.com.domain.ComCdBas;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ComCdBasRepository extends JpaRepository<ComCdBas, ComCdBas.ComCdBasId> {
List<ComCdBas> findByGroupCdAndUseYnOrderBySortOrdrAsc(String groupCd, String y);
ComCdBas findByGroupCdAndCdIdAndUseYn(String groupCd, String cdId, String useYn);
}

10
data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComCdGroupBasRepository.java

@ -0,0 +1,10 @@
package kr.co.palnet.kac.data.com.repository;
import kr.co.palnet.kac.data.com.domain.ComCdGroupBas;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ComCdGroupBasRepository extends JpaRepository<ComCdGroupBas, String> {
List<ComCdGroupBas> findBySiteCd(String siteCd);
}

10
data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComCdLangCtgRepository.java

@ -0,0 +1,10 @@
package kr.co.palnet.kac.data.com.repository;
import kr.co.palnet.kac.data.com.domain.ComCdLangCtg;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ComCdLangCtgRepository extends JpaRepository<ComCdLangCtg, ComCdLangCtg.ComCdLangCtgId> {
List<ComCdLangCtg> findByGroupCdAndCdId(String groupCd, String cdId);
}

8
data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComConfirmBasRepository.java

@ -0,0 +1,8 @@
package kr.co.palnet.kac.data.com.repository;
import kr.co.palnet.kac.data.com.domain.ComConfirmBas;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ComConfirmBasRepository extends JpaRepository<ComConfirmBas, Integer> {
}

8
data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComFileBasRepository.java

@ -0,0 +1,8 @@
package kr.co.palnet.kac.data.com.repository;
import kr.co.palnet.kac.data.com.domain.ComFileBas;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ComFileBasRepository extends JpaRepository<ComFileBas, Integer> {
}

8
data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComIdntBasRepository.java

@ -0,0 +1,8 @@
package kr.co.palnet.kac.data.com.repository;
import kr.co.palnet.kac.data.com.domain.ComIdntfBas;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ComIdntBasRepository extends JpaRepository<ComIdntfBas, String> {
}

8
data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComRiseSetBasRepository.java

@ -0,0 +1,8 @@
package kr.co.palnet.kac.data.com.repository;
import kr.co.palnet.kac.data.com.domain.ComRiseSetBas;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ComRiseSetBasRepository extends JpaRepository<ComRiseSetBas, ComRiseSetBas.ComRiseSetBasId> {
}

7
data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComSiteBasRepository.java

@ -0,0 +1,7 @@
package kr.co.palnet.kac.data.com.repository;
import kr.co.palnet.kac.data.com.domain.ComSiteBas;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ComSiteBasRepository extends JpaRepository<ComSiteBas, String>{
}

7
data/com/src/main/java/kr/co/palnet/kac/data/com/repository/ComTrmnlBasRepository.java

@ -0,0 +1,7 @@
package kr.co.palnet.kac.data.com.repository;
import kr.co.palnet.kac.data.com.domain.ComTrmnlBas;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ComTrmnlBasRepository extends JpaRepository<ComTrmnlBas, String>{
}

212
data/com/src/main/java/kr/co/palnet/kac/data/com/service/ComCodeDomainService.java

@ -0,0 +1,212 @@
package kr.co.palnet.kac.data.com.service;
import kr.co.palnet.kac.data.com.domain.ComCdBas;
import kr.co.palnet.kac.data.com.domain.ComCdGroupBas;
import kr.co.palnet.kac.data.com.domain.ComCdLangCtg;
import kr.co.palnet.kac.data.com.repository.ComCdBasRepository;
import kr.co.palnet.kac.data.com.repository.ComCdGroupBasRepository;
import kr.co.palnet.kac.data.com.repository.ComCdLangCtgRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
@Slf4j
@Transactional
@RequiredArgsConstructor
@Service
public class ComCodeDomainService {
private final ComCdGroupBasRepository comCdGroupBasRepository;
private final ComCdBasRepository comCdBasRepository;
private final ComCdLangCtgRepository comCdLangCtgRepository;
// 그룹 조회
@Transactional(readOnly = true)
public List<ComCdGroupBas> getComCdGroupBasList() {
return comCdGroupBasRepository.findAll();
}
@Transactional(readOnly = true)
public List<ComCdGroupBas> getComCdGroupBasList(String siteCd) {
return comCdGroupBasRepository.findBySiteCd(siteCd);
}
@Transactional(readOnly = true)
public ComCdGroupBas getComCdGroupBas(String groupCd) {
return comCdGroupBasRepository.findById(groupCd).orElse(null);
}
// 코드 조회
@Transactional(readOnly = true)
public List<ComCdBas> getComCdBasList(String groupCd) {
return comCdBasRepository.findByGroupCdAndUseYnOrderBySortOrdrAsc(groupCd, "Y");
}
@Transactional(readOnly = true)
public ComCdBas getComCdBas(String groupCd, String cdId) {
return comCdBasRepository.findByGroupCdAndCdIdAndUseYn(groupCd, cdId, "Y");
}
// 언어 조회
@Transactional(readOnly = true)
public List<ComCdLangCtg> getComCdLangCtgList(String groupCd, String cdId) {
return comCdLangCtgRepository.findByGroupCdAndCdId(groupCd, cdId);
}
@Transactional(readOnly = true)
public ComCdLangCtg getComCdLangCtg(String groupCd, String cdId, String langDivCd) {
ComCdLangCtg.ComCdLangCtgId id = ComCdLangCtg.ComCdLangCtgId.builder()
.groupCd(groupCd)
.cdId(cdId)
.langDivCd(langDivCd)
.build();
return comCdLangCtgRepository.findById(id).orElse(null);
}
// TODO Exception 처리
// 그룹 등록
public ComCdGroupBas createComCdGroupBas(ComCdGroupBas comCdGroupBas) {
comCdGroupBasRepository.findById(comCdGroupBas.getGroupCd()).ifPresent(bas -> {
throw new RuntimeException("이미 존재하는 코드 그룹입니다.");
});
// TODO 일자 및 사용자 넣기
comCdGroupBas.setCreateDt(LocalDateTime.now());
comCdGroupBas.setCreateUserId("CREATE_USER");
comCdGroupBas.setUpdateDt(LocalDateTime.now());
comCdGroupBas.setUpdateUserId("CREATE_USER");
return comCdGroupBasRepository.save(comCdGroupBas);
}
// TODO 일자 및 사용자 넣기
// TODO Exception 처리
// 코드 등록
public ComCdBas createComCdBas(ComCdBas comCdBas) {
var id = ComCdBas.ComCdBasId.builder()
.groupCd(comCdBas.getGroupCd())
.cdId(comCdBas.getCdId())
.build();
comCdBasRepository.findById(id).ifPresent(bas -> {
throw new RuntimeException("이미 존재하는 코드입니다.");
});
// TODO 일자 및 사용자 넣기
comCdBas.setCreateDt(LocalDateTime.now());
comCdBas.setCreateUserId("CREATE_USER");
comCdBas.setUpdateDt(LocalDateTime.now());
comCdBas.setUpdateUserId("CREATE_USER");
return comCdBasRepository.save(comCdBas);
}
// 언어 등록
public ComCdLangCtg createComCdLangCtg(ComCdLangCtg comCdLangCtg) {
// comCdLangCtgRepository.findById(comCdLangCtg.getId()).ifPresent(bas -> {
// throw new RuntimeException("이미 존재하는 코드 언어입니다.");
// });
var id = ComCdLangCtg.ComCdLangCtgId.builder()
.groupCd(comCdLangCtg.getGroupCd())
.cdId(comCdLangCtg.getCdId())
.langDivCd(comCdLangCtg.getLangDivCd())
.build();
comCdLangCtgRepository.findById(id).ifPresent(bas -> {
throw new RuntimeException("이미 존재하는 코드 언어입니다.");
});
// TODO 일자 및 사용자 넣기
comCdLangCtg.setCreateDt(LocalDateTime.now());
comCdLangCtg.setCreateUserId("CREATE_USER");
comCdLangCtg.setUpdateDt(LocalDateTime.now());
comCdLangCtg.setUpdateUserId("CREATE_USER");
return comCdLangCtgRepository.save(comCdLangCtg);
}
// TODO Exception 처리
// 그룹 수정
public ComCdGroupBas updateComCdGroupBas(ComCdGroupBas comCdGroupBas) {
var bas = comCdGroupBasRepository.findById(comCdGroupBas.getGroupCd()).orElseThrow(() -> {
throw new RuntimeException("존재하지 않는 코드 그룹입니다.");
});
bas.update(comCdGroupBas);
// TODO 일자 및 사용자 넣기
bas.setUpdateDt(LocalDateTime.now());
bas.setUpdateUserId("UPDATE_USER");
return comCdGroupBasRepository.save(bas);
}
// TODO 일자 및 사용자 넣기
// TODO Exception 처리
// 코드 수정
public ComCdBas updateComCdBas(ComCdBas comCdBas) {
var id = ComCdBas.ComCdBasId.builder()
.groupCd(comCdBas.getGroupCd())
.cdId(comCdBas.getCdId())
.build();
var bas = comCdBasRepository.findById(id).orElseThrow(() -> {
throw new RuntimeException("존재하지 않는 코드입니다.");
});
bas.update(comCdBas);
// TODO 일자 및 사용자 넣기
bas.setUpdateDt(LocalDateTime.now());
bas.setUpdateUserId("UPDATE_USER");
return comCdBasRepository.save(bas);
}
// TODO 일자 및 사용자 넣기
// TODO Exception 처리
// 언어 수정
public ComCdLangCtg updateComCdLangCtg(ComCdLangCtg comCdLangCtg) {
var id = ComCdLangCtg.ComCdLangCtgId.builder()
.groupCd(comCdLangCtg.getGroupCd())
.cdId(comCdLangCtg.getCdId())
.langDivCd(comCdLangCtg.getLangDivCd())
.build();
var bas = comCdLangCtgRepository.findById(id).orElseThrow(() -> {
throw new RuntimeException("존재하지 않는 코드 언어입니다.");
});
bas.update(comCdLangCtg);
// TODO 일자 및 사용자 넣기
bas.setUpdateDt(LocalDateTime.now());
bas.setUpdateUserId("UPDATE_USER");
return comCdLangCtgRepository.save(bas);
}
// 그룹 삭제
public void deleteComCdGroupBas(String groupCd) {
comCdGroupBasRepository.deleteById(groupCd);
}
// 코드 삭제
public void deleteComCdBas(String groupCd, String cdId) {
var id = ComCdBas.ComCdBasId.builder()
.groupCd(groupCd)
.cdId(cdId)
.build();
comCdBasRepository.deleteById(id);
}
// 언어 삭제
public void deleteComCdLangCtg(String groupCd, String cdId, String langDivCd) {
var id = ComCdLangCtg.ComCdLangCtgId.builder()
.groupCd(groupCd)
.cdId(cdId)
.langDivCd(langDivCd)
.build();
comCdLangCtgRepository.deleteById(id);
}
}

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

Loading…
Cancel
Save