commit aec2526c7dd6672c711306422f6af343b8f46df6 Author: Lim Jonguk Date: Fri Jan 7 23:50:08 2022 +0900 init commit 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'