From aec2526c7dd6672c711306422f6af343b8f46df6 Mon Sep 17 00:00:00 2001 From: Lim Jonguk Date: Fri, 7 Jan 2022 23:50:08 +0900 Subject: [PATCH] init commit --- .dockerignore | 22 ++++ .gitignore | 37 ++++++ Dockerfile | 46 ++++++++ HELP.md | 154 ++++++++++++++++++++++++ Jenkinsfile | 148 +++++++++++++++++++++++ appspec.yml | 26 +++++ build.gradle | 285 +++++++++++++++++++++++++++++++++++++++++++++ deploy.sh | 25 ++++ docker-compose.yml | 27 +++++ gradle.properties | 52 +++++++++ gradlew | 234 +++++++++++++++++++++++++++++++++++++ gradlew.bat | 91 +++++++++++++++ settings.gradle | 5 + 13 files changed, 1152 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 HELP.md create mode 100644 Jenkinsfile create mode 100644 appspec.yml create mode 100644 build.gradle create mode 100644 deploy.sh create mode 100644 docker-compose.yml create mode 100644 gradle.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6f9c5df --- /dev/null +++ b/.dockerignore @@ -0,0 +1,22 @@ +node_modules +npm-debug.log + +# .git 과 .cache 폴더를 무시 +.git +.cache + +# ignore all *.class files in all folders, including build root +# 모든 폴더안에 있는 모든, *.class 파일들을 무시 +**/*.class + +# 모든 마크다운 파일들 (md) 파일들을 무시, +# 모든 README*.md 파일 무시 +*.md +IREADME*.md + +.gradle +build +.idea +out +work +data \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e2f6364 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +.mvn + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ +/out/ +/work/ +/.gradle/ +/src/main/generated/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..394ad63 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,46 @@ +FROM gradle:7-jdk8 AS build +WORKDIR /application +COPY --chown=gradle:gradle ./ ./ +#COPY ./ ./ +#RUN chmod +x ./gradlew +RUN gradle clean bootWar + +FROM openjdk:8-jre-slim +WORKDIR /app +COPY --from=build /application/build/libs/*.war ./ROOT.war +EXPOSE 8090 +#ENTRYPOINT ["java", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-Dspring.profiles.active=dev","-jar"," /app/ROOT.war"] +ENTRYPOINT ["java", "-jar", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-Dspring.profiles.active=dev", "/app/ROOT.war"] +#ENTRYPOINT ["java", "-Dspring.profiles.active=dev", "-jar", "/application/build/libs/core-0.0.1-SNAPSHOT.war"] + +#FROM openjdk:8-jdk-alpine as builder +#WORKDIR application +#COPY ./ ./ +#RUN chmod +x ./gradlew +##--args='--spring.profiles.active=dev' +#RUN ./gradlew clean bootWar +##CMD["./gradlew", "-Dspring.profiles.active=local", "clean", "bootWar"] +# +#EXPOSE 8090 8443 +#ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=dev", "/application/build/libs/core-0.0.1-SNAPSHOT.war"] + +#FROM postgres +#FROM tomcat:9.0 +#ENV TZ="Asia/Seoul" +#RUN ln -fns /usr/share/zoneinfo/$TZ /etc/localtime +#RUN echo $TZ > /etc/timezone +#CMD ["/usr/local/tomcat/bin/catalina.sh", "stop"] +#CMD sleep 3 +# +#RUN rm -rf /usr/local/tomcat/webapps/ROOT +#COPY --from=builder /application/build/libs/core-0.0.1-SNAPSHOT.war /usr/local/tomcat/webapps/ROOT.war +#EXPOSE 8090 8443 +#CMD ["/usr/local/tomcat/bin/catalina.sh", "run"] + +#FROM tomcat:9.0 +#ENV TZ="Asia/Seoul" +#RUN ln -fns /usr/share/zoneinfo/$TZ /etc/localtime +#RUN echo $TZ > /etc/timezone +##RUN rm -rf /usr/local/tomcat/webapps/ROOT +#COPY repo/target/kuaa-management.war /usr/local/tomcat/webapps/ROOT.war +#EXPOSE 8009 8080 8443 \ No newline at end of file diff --git a/HELP.md b/HELP.md new file mode 100644 index 0000000..dba70c9 --- /dev/null +++ b/HELP.md @@ -0,0 +1,154 @@ +# Getting Started + +## Configuration +### Logging +``` +JpaAndRequestLoggingConfig.java : JPA / Web + P6spySqlFormatConfiguration.java - decorator.datasource.p6spy.enable-logging: true + CustomCommonsRequestLoggingFilter.java - org.springframework.web.filter: debug 필수 + decorator.datasource.p6spy + +Security 비활성 +@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class}) +SecurityJavaConfig.java - 예외 등록 + - h2, swagger + +Swagger 설정 : SwaggerConfig + +resources 설정 + WebAndFluxCommonConfig.java - MVC / Flux 공통 사용 + +MVC / Flux 동시 사용 설정 + @EnableWebMvc 만 설정 - @EnableWebFlux는 미사용(사용시 충돌) + MVC application + - @EnableWebMvc + - @SpringBootApplication : exclude에 WebMvcAutoConfiguration.class +``` + +### swagger +```java + //파라메터 값을 모두 String으로 취급 + //String이 아닌 경우 example 값을 부여해야 compile시 WARN 발생 안함 + @ApiImplicitParam(name="cmmUserId", value="사용자ID-PK", example = "1") + +``` + +### Reference Documentation +For further reference, please consider the following sections: + +* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) +* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.5.0/maven-plugin/reference/html/) +* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.5.0/maven-plugin/reference/html/#build-image) + +# **Tailwind CSS** +- [Tailwind CSS](https://tailwindcss.com/): 경량의 **CSS** 프레임워크이다. 덩치가 큰 **Bootstrap**과 달리 **CSS**로만 작동하면서 사용자에게 **UI** 구현을 맡기는 컨셉이다. 구현이 직관적이고 자유도가 높아 최근 급속도로 생태계가 확장되고 있다. +- [Tailwind Cheat Sheet](https://nerdcave.com/tailwind-cheat-sheet): **Tailwind CSS**의 모든 클래스를 한 눈에 조회 검색 가능한 사이트이다. 사용이 편리하여 레퍼런스 사이트보다 더 찾게 된다. +- [Tailwind Toolbox](https://www.tailwindtoolbox.com/): **Tailwind CSS** 기반으로 **UI** 구현에 참고할만한 여러 완성 템플릿을 제공한다. +- [Tailwind Components](https://tailwindcomponents.com/): **Tailwind CSS** 기반으로 **UI** 구현에 참고할만한 여러 완성 컴포넌트를 제공한다. +- [Awesome Tailwind CSS](https://github.com/aniftyco/awesome-tailwindcss): **Tailwind CSS** 관련 유용한 유용한 정보들을 소개한다. +- [We build a login using TailwindCSS](https://stefanbauer.me/building-pingping/we-build-a-login-using-tailwindcss): **Tailwind CSS**을 이용한 로그인 폼 제작 과정을 설명한다. + +# **Webflux 지원 Database** +1. Postgres (io.r2dbc:r2dbc-postgresql) +2. H2 (io.r2dbc:r2dbc-h2) +3. Microsoft SQL Server (io.r2dbc:r2dbc-mssql) +4. MySQL (com.github.mirromutth:r2dbc-mysql) +5. jasync-sql MySQL (com.github.jasync-sql:jasync-r2dbc-mysql) + +### mysql 사용시 +```xml + + io.r2dbc + r2dbc-pool + 0.8.0.RELEASE + + + + io.r2dbc + r2dbc-pool + 0.8.0.BUILD-SNAPSHOT + + + + dev.miku + r2dbc-mysql + 0.8.1.RELEASE + +``` +### sample +```java +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.HashMap; + +import javax.annotation.PostConstruct; +import org.springframework.stereotype.Repository; +import io.r2dbc.pool.ConnectionPool; +import io.r2dbc.pool.ConnectionPoolConfiguration; +import io.r2dbc.spi.ConnectionFactories; +import io.r2dbc.spi.ConnectionFactory; +import io.r2dbc.spi.Result; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Repository +public class DatabaseConfig { + private ConnectionFactory factory; + private ConnectionPool pool; + + //연결 + @PostConstruct + public void init() { + factory = ConnectionFactories.get("r2dbcs:pool:mysql://비번:아이디@주소:포트/db명"); + ConnectionPoolConfiguration configuration = ConnectionPoolConfiguration.builder(factory) + .maxIdleTime(Duration.ofMillis(1000)) + .maxSize(20) + .build(); + pool = new ConnectionPool(configuration); + } + + //단일 셀렉트, 조회할 테이블 데이터가 n개이면 이런식으로 쓰면 안된다. + public Mono> selectSingle() { + Mono> mono = Mono.from(pool.create()).map(connection -> //커넥션 가공 + Flux.from(connection.createStatement("select name, desc, date from test where id_=?ids").bind("ids", "2").execute()) + .concatMap( result-> //1차 변환 + result.map((row, rowMetadata)-> { //결과 재 조립 후 리턴 + HashMap item = new HashMap<>(); + item.put("names", row.get("name",String.class)); + item.put("desc", row.get("desc",String.class)); + item.put("date", row.get("date",Object.class)); + return item; + }) + ).doFinally( (st)->{connection.close();}) + ).flatMap( ccc -> Mono.from(ccc)); //2차 변환 + return mono; + } + + //단순 셀렉트 예제 + public Flux> selectMany() { + Flux> flux = Flux.from(pool.create()).concatMap(connection -> //커넥션 가공 및 1차 변환 + Flux.from(connection.createStatement("select name, desc, date from test where id_=?ids").bind("ids", "2").execute()) + .concatMap( result-> //2차 변환 + result.map((row, rowMetadata)-> { //결과 재 조립 후 리턴 + HashMap item = new HashMap<>(); + item.put("names", row.get("name",String.class)); + item.put("desc", row.get("desc",String.class)); + item.put("date", row.get("date",Object.class)); + return item; + }) + ).doFinally( (st)->{connection.close();}) + ); + return flux; + } + + //저장 예제 + public Mono insertTest() { + return Mono.from(pool.create()).map( con -> + Mono.from( + con.createStatement(" insert into test(name, desc, date) values (?name, ?desc, ?date) ") + .bind("name", "abcd").bind("desc", "desc").bind("date", LocalDateTime.now()).execute() + ).doFinally( st-> con.close()).map( result -> result) + ).flatMap( c-> Mono.from(c)); + } +} +``` diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..6c44b43 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,148 @@ +pipeline { + agent any + stages { + stage('Git Pull') { + steps { + script { + try { + //echo 'prepare' + //git branch: "master", credentialsId: "$GIT_CREDENTIALS_ID", url: 'git@github.com:minuk926/xit-framework.git/' + git branch: 'master', url: 'git@github.com:minuk926/xit-framework.git', credentialsId: 'jenkins_aws_connect_key' + sh rm -rf .git + sh 'ls -al' + env.cloneResult=true + } catch (error) { + print(error) + env.cloneResult=false + currentBuild.result = 'FAILURE' + } + } + } + } + stage('Build WAR') { + when { + expression { + return env.cloneResult ==~ /(?i)(Y|YES|T|TRUE|ON|RUN)/ + } + } + steps { + script{ + try { + sh """ + rm -rf deploy + mkdir deploy + """ + sh "sudo sed -i \"s/module_name=.*/module_name=${env.JOB_NAME}\\:${env.BUILD_NUMBER}/g\" /var/lib/jenkins/workspace/${env.JOB_NAME}/src/main/resources/application.properties" + sh "cat /var/lib/jenkins/workspace/${env.JOB_NAME}/src/main/resources/application.properties" + sh 'gradlew clean bootWar' + sh """ + cd deploy + cp /var/lib/jenkins/workspace/${env.JOB_NAME}/build/libs/*.war ./ROOT.war + """ + env.gradleBuildResult=true + } catch (error) { + print(error) + echo 'Remove Deploy Files' + sh "sudo rm -rf /var/lib/jenkins/workspace/${env.JOB_NAME}/*" + env.gradleBuildResult=false + currentBuild.result = 'FAILURE' + } + } + } + post { + success { + slackSend channel: '#pipeline-deploy', color: 'good', message: "The pipeline ${currentBuild.fullDisplayName} stage Build WAR successfully." + } + failure { + slackSend channel: '#pipeline-deploy', color: 'danger', message: "The pipeline ${currentBuild.fullDisplayName} stage Build WAR failed." + } + } + } + stage('Docker Build'){ + when { + expression { + return env.mavenBuildResult ==~ /(?i)(Y|YES|T|TRUE|ON|RUN)/ + } + } + steps { + script{ + try { + sh""" + #!/bin/bash + cd ./deploy + cat>Dockerfile<<-EOF +FROM ${ECR_BASE_URL}:latest +ADD ${env.JOB_NAME}.jar /home/${env.JOB_NAME}.jar +CMD nohup java -jar /home/${env.JOB_NAME}.jar 1> /dev/null 2>&1 +EXPOSE 9000 +EOF""" + sh""" + cd ./deploy + docker rmi -f \$(docker images -q) + \$(aws ecr get-login --no-include-email --region ap-northeast-2) + docker build -t ${SERVICE_NAME.toLowerCase()} . + docker tag ${SERVICE_NAME.toLowerCase()}:latest ${ECR_TASK_URL}:ver${env.BUILD_NUMBER} + docker push ${ECR_TASK_URL}:ver${env.BUILD_NUMBER} + """ + echo 'Remove Deploy Files' + sh "sudo rm -rf /var/lib/jenkins/workspace/${env.JOB_NAME}/*" + env.dockerBuildResult=true + } catch (error) { + print(error) + echo 'Remove Deploy Files' + sh "sudo rm -rf /var/lib/jenkins/workspace/${env.JOB_NAME}/*" + env.dockerBuildResult=false + currentBuild.result = 'FAILURE' + } + } + } + post { + success { + slackSend channel: '#jenkins', color: 'good', message: "The pipeline ${currentBuild.fullDisplayName} stage Docker Build successfully." + } + failure { + slackSend channel: '#jenkins', color: 'danger', message: "The pipeline ${currentBuild.fullDisplayName} stage Docker Build failed." + } + } + } + stage('Deploy'){ + when { + expression { + return env.dockerBuildResult ==~ /(?i)(Y|YES|T|TRUE|ON|RUN)/ + } + } + steps { + script{ + try { + withAWS(credentials:"$AWS_CREDENTIALS") { + sh "aws ecs describe-task-definition --task-definition ${TASK_DEFINITION} --region ap-northeast-2 --query \"taskDefinition.{\"family\": family, \"containerDefinitions\": containerDefinitions, \"executionRoleArn\": executionRoleArn,\"requiresCompatibilities\": requiresCompatibilities}\" --output json > task-definition.json" + def task_repository_name = sh( + script:""" + echo \"${ECR_TASK_URL}\" | awk \'{ split(\$0, arr, \"/\"); print arr[2] }\' + """, + returnStdout: true + ).trim() + sh "sudo sed -i \"9s/${task_repository_name}:.*/${task_repository_name}:ver${env.BUILD_NUMBER}\\\",/g\" task-definition.json" + sh "cat task-definition.json" + sh "aws ecs register-task-definition --cli-input-json file://task-definition.json --region ap-northeast-2" + sh "aws ecs update-service --cluster ${CLUSTER_NAME} --service ${SERVICE_NAME} --task-definition ${TASK_DEFINITION} --region ap-northeast-2" + } + } catch (error) { + print(error) + echo 'Remove Deploy Files' + sh "sudo rm -rf /var/lib/jenkins/workspace/${env.JOB_NAME}/*" + currentBuild.result = 'FAILURE' + } + } + } + post { + success { + slackSend channel: '#jenkins', color: 'good', message: "The pipeline ${currentBuild.fullDisplayName} successfully." + } + failure { + slackSend channel: '#jenkins', color: 'danger', message: "The pipeline ${currentBuild.fullDisplayName} failed." + } + } + } + } +} \ No newline at end of file diff --git a/appspec.yml b/appspec.yml new file mode 100644 index 0000000..8a04999 --- /dev/null +++ b/appspec.yml @@ -0,0 +1,26 @@ +version: 0.0 +os: linux + +files: + - source: / + destination: /home/ubuntu/admin/bo # 배포 파일 도착 폴더 + overwrite: yes # 안돼면, 아래 hooks BeforeInstall 추가, 파일 삭제 +permissions: + - object: / + pattern: "**" # 모든 파일의 권한 설정 + owner: ubuntu + group: ubuntu +# mode: 755 + +hooks: +# BeforeInstall: "BeforeInstallHookFunctionName" +# AfterInstall: "AfterInstallHookFunctionName" +# ApplicationStop: +# - timeout: 2 + ApplicationStart: # 파일이 도착 후 실행 + - location: deploy.sh + timeout: 60 # 60 안에 실행, 60 뒤엔 배포 실패로 변경 + runas: ubuntu +# ValidateService: # deplo 실행 후, 빌드파일이 배포가 되었다면, 서버체크 +# - location: server-check.sh +# timeout: 60 \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..4493f5a --- /dev/null +++ b/build.gradle @@ -0,0 +1,285 @@ +//-------------------------------------------------------------------------------------- +// gradle에서는 스크립트 위치 중요 +// plugins{} 전에는 buildscript{}와 plugins{} 만 가능 +//-------------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------------- + +buildscript { + ext { + springBootVersion ='2.6.1' + } + + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion") + + // JPA querydsl + //classpath("gradle.plugin.com.ewerk.gradle.plugins:querydsl-plugin:1.0.10") + } +} + +plugins { + //id 'application' + id 'org.springframework.boot' version '2.6.1' + id 'io.spring.dependency-management' version '1.0.11.RELEASE' + id 'java' + id 'war' + //id 'net.ltgt.apt' version '0.21' + // querydsl + //id 'com.ewerk.gradle.plugins.querydsl' version '1.0.10' + //id 'org.openapi.generator' version '5.1.1' + + // docker : jib + // bootWar --> jibDockerBuild + //id 'com.google.cloud.tools.jib' version '3.1.2' // +} + +// buildscript +group = 'com.xit' +version = '0.0.1-SNAPSHOT' +description = 'xit-framework' +sourceCompatibility = '11' + +// WAS로 배포하는 경우 : bootWar.enabled = false +bootWar.enabled = true +war.enabled = true + +repositories { + mavenCentral() + google() +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +dependencies { + //dependency is used by the application. + implementation 'com.google.guava:guava:30.1.1-jre' + + //-----------------------------------------------------------------------------------// + // Core + //-----------------------------------------------------------------------------------// + // spring boot core + implementation 'org.springframework.boot:spring-boot-starter' + // spring-boot-starter-validation을 포함 + // 2.3 이상 부터 제외, 따라서 반드시 Validation 필요 + implementation 'org.springframework.boot:spring-boot-starter-web' + + + implementation 'org.springframework.boot:spring-boot-starter-hateoas' + implementation 'org.springframework.boot:spring-boot-configuration-processor' + implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-jdbc' + + // yaml 다국화 lib + implementation 'net.rakugakibox.util:yaml-resource-bundle:1.1' + + // spring-boot 2.3 까지는 사용 불가 - spring-boot-starter-web에 포함되어 있다 + // hibernate-validator:5.2.4.Final 사용 + implementation 'org.springframework.boot:spring-boot-starter-validation' + // spring-boot 2.3 까지는 아래 lib 사용 + //implementation 'org.hibernate:hibernate-validator:5.2.4.Final' + + // social login + implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' + //-----------------------------------------------------------------------------------// + + //-----------------------------------------------------------------------------------// + // Java Web Token + //-----------------------------------------------------------------------------------// + implementation 'io.jsonwebtoken:jjwt-api:0.11.2' + runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2' + runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.2' + //-----------------------------------------------------------------------------------// + + //-----------------------------------------------------------------------------------// + // Mybatis + //-----------------------------------------------------------------------------------// + implementation 'org.mybatis:mybatis:3.5.9' + implementation 'org.mybatis:mybatis-typehandlers-jsr310:1.0.2' + implementation 'org.mybatis:mybatis-spring:2.0.6' + //-----------------------------------------------------------------------------------// + + //-----------------------------------------------------------------------------------// + // JPA + //-----------------------------------------------------------------------------------// + // JPA logging p6spy + implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.8.0' + implementation 'p6spy:p6spy:3.9.1' + + // JPA querydsl + //compileOnly 'com.querydsl:querydsl-jpa' + //compileOnly 'com.querydsl:querydsl-apt' + + // JPA mapstruct : lombok 과 함께 사용시 반드시 순서 지겨야 함다 - lombok이 먼저 선언된 경우 + implementation 'org.projectlombok:lombok-mapstruct-binding:0.2.0' + implementation 'org.projectlombok:lombok' + implementation 'org.mapstruct:mapstruct:1.4.2.Final' + annotationProcessor "org.projectlombok:lombok-mapstruct-binding:0.2.0" + annotationProcessor 'org.projectlombok:lombok' + annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final' + + // JPA mapstruct : lombok 과 함께 사용시 반드시 순서 지겨야 함다 - ㅡmapstruct이 먼저 선언된 경우 + // target class 에 @Builder 가 있어도 무시하고 생성자 + setter 를 사용하므로 정상적으로 Mapper 클래스를 Generation 하기 위해서 + // @NoArgsConstructor, @Setter 가 필요 + // but, 최근 Setter 사용을 지양하는 추세라 mapstruct를 먼저 오도록 해서 @Builder 방식으로 Generation +// implementation 'org.mapstruct:mapstruct:1.4.2.Final' +// implementation 'org.projectlombok:lombok-mapstruct-binding:0.2.0' +// implementation 'org.projectlombok:lombok' +// annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final' +// annotationProcessor "org.projectlombok:lombok-mapstruct-binding:0.2.0" +// annotationProcessor 'org.projectlombok:lombok' + //-----------------------------------------------------------------------------------// + + //-----------------------------------------------------------------------------------// + // Springdoc : swagger + //-----------------------------------------------------------------------------------// + implementation 'org.springdoc:springdoc-openapi-ui:1.6.3' + implementation 'org.springdoc:springdoc-openapi-security:1.6.3' + implementation 'org.springdoc:springdoc-openapi-data-rest:1.6.3' + implementation 'org.springdoc:springdoc-openapi-webmvc-core:1.6.3' + + //-----------------------------------------------------------------------------------// + // Xss Injection avoid : Naver lucy-xss + //-----------------------------------------------------------------------------------// + implementation 'com.navercorp.lucy:lucy-xss-servlet:2.0.1' + //-----------------------------------------------------------------------------------// + + //-----------------------------------------------------------------------------------// + // slack webhook : logback slack webhook + //-----------------------------------------------------------------------------------// + implementation 'com.github.maricn:logback-slack-appender:1.4.0' + //-----------------------------------------------------------------------------------// + + //-----------------------------------------------------------------------------------// + // DB driver + //-----------------------------------------------------------------------------------// + runtimeOnly 'com.h2database:h2:1.4.199' // 2.0.202 사용시 에러 발생 + implementation 'org.postgresql:postgresql:42.3.1' + //-----------------------------------------------------------------------------------// + + //-----------------------------------------------------------------------------------// + // Webflux + //-----------------------------------------------------------------------------------// + //implementation 'org.springframework.boot:spring-boot-starter-webflux' + //-----------------------------------------------------------------------------------// + + //-----------------------------------------------------------------------------------// + // 3rd-party lib + //-----------------------------------------------------------------------------------// + // AOP + implementation 'org.aspectj:aspectjrt' + implementation 'org.aspectj:aspectjweaver' + + // simple captcha + implementation fileTree(dir: 'repo', include: ['*.jar']) + + // amazon aws s3 + implementation 'com.amazonaws:aws-java-sdk-s3:1.12.131' + + // excel poi + implementation 'org.apache.poi:poi-ooxml:4.1.2' //5.0.0 사용시 에러 : poi-ooxml-schemas + implementation 'org.apache.poi:poi:4.1.2' //5.0.0 사용시 에러 implementation 'org.apache.commons:commons-lang3:3.12.0' + + // Object Deep-copy : Cloner + implementation 'uk.com.robust-it:cloning:1.9.12' + + // Get Device 정보 : Device / UserAgent + implementation 'org.springframework.mobile:spring-mobile-device:1.1.5.RELEASE' + implementation 'eu.bitwalker:UserAgentUtils:1.21' + + // 문자열 type check : UniversalDetector - excel + implementation 'com.googlecode.juniversalchardet:juniversalchardet:1.0.3' + + implementation 'org.apache.httpcomponents:httpcore:4.4.15' + implementation 'commons-collections:commons-collections:3.2.2' + implementation 'commons-fileupload:commons-fileupload:1.4' + implementation 'javax.mail:mail:1.4.7' + implementation 'org.codehaus.jackson:jackson-core-asl:1.9.13' + + // google json + implementation 'com.googlecode.json-simple:json-simple:1.1.1' + implementation 'com.google.code.gson:gson:2.8.9' + + + implementation 'com.fasterxml.jackson.core:jackson-core:2.13.1' + implementation 'com.fasterxml.jackson.core:jackson-annotations:2.13.1' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.13.1' + implementation 'com.fasterxml.jackson.module:jackson-module-afterburner:2.13.1' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.1' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-joda:2.13.1' + //implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.12.5' + //-----------------------------------------------------------------------------------// + + //-----------------------------------------------------------------------------------// + // Test + //-----------------------------------------------------------------------------------// + testImplementation 'org.springframework.security:spring-security-test' + testImplementation ('org.springframework.boot:spring-boot-starter-test'){ + exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' + } + testImplementation("org.junit.vintage:junit-vintage-engine") { + exclude group: "org.hamcrest", module: "hamcrest-core" + } + testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2' //'junit:junit:4.13.2' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' //'junit:junit:4.13.2' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2' //'junit:junit:4.13.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' //'junit:junit:4.13.2' + implementation 'org.assertj:assertj-core:3.21.0' + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' + //-----------------------------------------------------------------------------------// + + //-----------------------------------------------------------------------------------// + // Development environment + //-----------------------------------------------------------------------------------// + runtimeOnly 'org.springframework.boot:spring-boot-devtools' + providedCompile 'org.springframework.boot:spring-boot-starter-tomcat' + //-----------------------------------------------------------------------------------// + + + + + //-----------------------------------------------------------------------------------// + // Template engine : thymeleaf + //-----------------------------------------------------------------------------------// + //implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + //implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:2.5.3' + //implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE' + //-----------------------------------------------------------------------------------// + + //-----------------------------------------------------------------------------------// + // JSP + //-----------------------------------------------------------------------------------// + //compileOnly 'org.apache.tomcat.embed:tomcat-embed-jasper' + //compileOnly 'javax.servlet:jstl' + //-----------------------------------------------------------------------------------// + + //-----------------------------------------------------------------------------------// + // Web library + //-----------------------------------------------------------------------------------// +// implementation 'org.webjars:webjars-locator:0.41' +// implementation 'org.webjars:webjars-locator-core:0.47' +// implementation 'org.webjars:bootstrap:5.1.0' +// implementation 'org.webjars:font-awesome:5.15.3' +// implementation 'org.webjars:popper.js:2.9.3' +// implementation 'org.webjars:jquery:3.6.0' +// implementation 'org.webjars:jquery-i18n-properties:1.10.2' +// implementation 'org.webjars:momentjs:2.29.1' + //-----------------------------------------------------------------------------------// +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} + + +test { + //exclude '**/*' + useJUnitPlatform() +} diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 0000000..63c8fd0 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +REPOSITORY=/home/ubuntu/xit-framework/bo +cd $REPOSITORY + +APP_NAME=xit-framework-bo +WAR_NAME=$(ls $REPOSITORY | grep '.war' | tail -n 1) +WAR_PATH=$REPOSITORY/$WAR_NAME +echo "> war 파일명: $WAR_NAME" >> /home/ubuntu/xit-framework/bo/deploy.log +echo "> war 파일명: $WAR_PATH" >> /home/ubuntu/xit-framework/bo/deploy.log + +CURRENT_PID=$(pgrep -f $APP_NAME) +echo "> CURRENT_PID : $CURRENT_PID" >> /home/ubuntu/xit-framework/bo/deploy.log + +if [ -z $CURRENT_PID ] +then + echo "> 종료할것 없음." +else + echo "> kill -9 $CURRENT_PID" + kill -9 $CURRENT_PID + sleep 5 +fi +rm -rf work/ +echo "> $WAR_PATH 배포" +nohup java -jar -Dspring.profiles.active=local $WAR_PATH > /dev/null 2> /dev/null < /dev/null & \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..5825c42 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,27 @@ +version: "3" +services: + backend: + build: + context: . + dockerfile: Dockerfile + ports: + - "8090:8090" + stdin_open: true +# volumes: +# - /app/node_modules +# - ./backend:/app +# environment: +# MYSQL_HOST: mysql +# MYSQL_USER: root +# MYSQL_ROOT_PASSWORD: johnahn777 +# MYSQL_DATABASE: myapp +# MYSQL_PORT: 3306 +# +# +# nginx: +# restart: always +# build: +# dockerfile: ../Dockerfile +# context: ./nginx +# ports: +# - "3000:80" \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..ddb3f27 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,52 @@ +#org.gradle.java.home=d:\\tools\\java\\jdk8144 +# org.gradle.warning.mode=(all,fail,none,summary) +org.gradle.warning.mode=all + +# Gradle이 데몬으로 떠서 실행되기 때문에 초기 로딩 시간이 줄어든다 +# 3시간동안 gradle 작업이 없으면 종료 +org.gradle.daemon=true +# memory allotted to JVM +org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +# configure on demand +org.gradle.configureondemand=true +# parallel builds +org.gradle.parallel=true +# build Cache +android.enableBuildCache=true +# gradle caching +org.gradle.caching=true + +# build.gradle에서 사용하는 인증정보 +#mavenUser=admin +#mavenPassword=admin! +# +# +#javaVersion=1.8 +#thymeleaf.layout.dialect.version=2.5.3 +#mapstruct.version=1.4.2.Final +#mapstruct-processor.version=1.3.1.Final +#lombok-mapstruct-binding.version=0.2.0 +#lombok.version=1.18.20 +#swagger.version=3.0.0 +#springdoc.openapi.version=1.5.9 +#javax.validation.version=1.1.0.Final +## 가장 안정화된 버전 +#hibernate-validator.version=5.2.4.Final +#jsonwebtoken.version=0.11.2 +# +#mybatis.version=3.4.4 +#mybatis.spring.version=1.3.1 +#fasterxml.jackson.version=2.11.2 +# +#webjars-locator.version=0.41 +#webjars-locator-core.version=0.47 +#bootstrap.version=5.0.1 +#tailwindcss.version=2.1.2 +#jquery.version=3.6.0 +#popper.version=2.9.2 +#font-awesome.version=5.15.3 +#momentjs.version=2.29.1 +#jquery-i18n-properties.version=1.2.7 +# +#com.amazonaws.sdk.version=1.11.15 +#com.amazonaws.ses.version=1.4.7 \ No newline at end of file diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..1b6c787 --- /dev/null +++ b/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..64a2f73 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +set JAVA_HOME=D:\tools\java\jdk8144 + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..15f7773 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,5 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +rootProject.name = 'xit-framework'