초기셋팅

This commit is contained in:
jazz
2025-12-18 10:04:46 +09:00
commit b68aa39bfb
387 changed files with 54028 additions and 0 deletions

2
.codetogether.ignore Normal file
View File

@@ -0,0 +1,2 @@
src/main/resources/application.yaml
/**

37
.gitignore vendored Normal file
View File

@@ -0,0 +1,37 @@
HELP.md
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/

208
Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,208 @@
pipeline {
agent any
tools {
jdk 'JDK17'
}
// parameters {
// choice(name: 'ENVIRONMENT', choices: ['dev'], description: '배포할 어플리케이션 profile 선택')
// choice(name: 'DEPLOY_SERVER_IP', choices: ['172.31.20.11'], description: '배포할 WAS 서버 IP 선택')
// string(name: 'GIT_REPO', defaultValue: 'http://172.31.18.11:3000/gcone/gcone_batch.git', description: 'Git 레파지토리 주소')
// }
environment {
SERVER_IP = "${DEPLOY_SERVER_IP}"
SERVER_USER = "tomcat"
TOMCAT_HOME = "${ENVIRONMENT == 'dev' ? '/var/lib/tomcat' : '/usr/local/tomcat'}"
DEPLOY_PATH = "${TOMCAT_HOME}/webapps"
BACKUP_PATH = "${DEPLOY_PATH}/backup"
APP_NAME = "gcone_batch"
WAR_FILE = "${APP_NAME}.war"
DEPLOY_FILE = "${DEPLOY_PATH}/${WAR_FILE}"
BACKUP_FILE = "${BACKUP_PATH}/${WAR_FILE}.bak"
GIT_BRANCH = "${ENVIRONMENT == 'dev' ? 'develop' : 'master'}"
// SSH_KEY_PATH = "C:/Users/CHAMDAHAN-41/.ssh/id_rsa"
}
stages {
stage('Setup parameters') {
steps {
script {
try {
echo "Setup parameters ${ENVIRONMENT}"
echo "tomcat home here ${env.TOMCAT_HOME}"
if("${ENVIRONMENT}" == "dev" ) {
properties([
parameters([
choice(name: 'ENVIRONMENT', choices: ['dev'], description: '배포할 어플리케이션 profile 선택'),
choice(name: 'DEPLOY_SERVER_IP', choices: ['172.31.20.11'], description: '배포할 WAS 서버 IP 선택'),
string(name: 'GIT_REPO', defaultValue: 'http://172.31.18.11:3000/gcone/gcone_batch.git', description: 'Git 레파지토리 주소')
])
])
}else{
properties([
parameters([
choice(name: 'ENVIRONMENT', choices: ['stage'], description: '배포할 어플리케이션 profile 선택'),
choice(name: 'DEPLOY_SERVER_IP', choices: ['10.100.241.11'], description: '배포할 WAS 서버 IP 선택'),
string(name: 'GIT_REPO', defaultValue: 'http://172.31.18.11:3000/gcone/gcone_batch.git', description: 'Git 레파지토리 주소')
])
])
}
} catch (Exception e) {
error "Setup parameters 실패: ${e.getMessage()}"
}
}
}
}
stage('Checkout') {
steps {
script {
try {
echo "Checking out ${env.GIT_BRANCH} branch for ${params.ENVIRONMENT} environment"
git branch: "${env.GIT_BRANCH}", url: "${params.GIT_REPO}"
echo "Checkout 성공: 브랜치 ${env.GIT_BRANCH}, 저장소 ${params.GIT_REPO}"
} catch (Exception e) {
error "Checkout 실패: ${e.getMessage()}"
}
}
}
}
stage('Build') {
steps {
script {
try {
if("${RUNNING_OS}" == "linux" ) {
sh 'chmod +x gradlew'
sh "./gradlew clean war -x test -Pprofile=${params.ENVIRONMENT}"
}else{
bat "./gradlew.bat clean build -Pprofile=${params.ENVIRONMENT}"
}
echo "Build 성공"
} catch (Exception e) {
error "Build 실패: ${e.getMessage()}"
}
}
}
}
stage('Unit Tests') {
steps {
script {
try {
if("${RUNNING_OS}" == "linux" ) {
sh "./gradlew test"
}else{
bat "./gradlew.bat test"
}
echo "Unit Tests 성공"
} catch (Exception e) {
error "Unit Tests 실패: ${e.getMessage()}"
}
}
}
}
stage('Backup') {
steps {
script {
sshCommand remote: [
name: 'WAS Server',
host: "${env.SERVER_IP}",
user: "${env.SERVER_USER}",
identityFile: "${env.SSH_KEY_PATH}",
allowAnyHosts: true
], command: """
if [ -f ${env.DEPLOY_FILE} ]; then
mkdir -p ${env.BACKUP_PATH}
cp ${env.DEPLOY_FILE} ${env.BACKUP_FILE}
rm -r ${env.TOMCAT_HOME}/webapps/${env.WAR_FILE}
echo "기존 WAR 파일 백업 완료"
else
echo "백업할 WAR 파일이 없습니다"
fi
"""
}
}
}
stage('Deploy to Tomcat') {
steps {
script {
sshPut remote: [
name: 'WAS Server',
host: "${env.SERVER_IP}",
user: "${env.SERVER_USER}",
identityFile: "${env.SSH_KEY_PATH}",
allowAnyHosts: true
], from: "build/libs/${env.WAR_FILE}", into: "${env.DEPLOY_FILE}"
sshCommand remote: [
name: 'WAS Server',
host: "${env.SERVER_IP}",
user: "${env.SERVER_USER}",
identityFile: "${env.SSH_KEY_PATH}",
allowAnyHosts: true
], command: """
if nc -z localhost 8005; then
echo "Tomcat이 실행 중입니다. 종료 중..."
${env.TOMCAT_HOME}/bin/shutdown.sh
sleep 2
rm -r ${env.TOMCAT_HOME}/webapps/${env.APP_NAME}
sleep 10
else
echo "Tomcat이 실행 중이지 않습니다."
fi
${env.TOMCAT_HOME}/bin/startup.sh
"""
echo "Deploy 완료 (${params.ENVIRONMENT} 환경, ${env.GIT_BRANCH} 브랜치)"
}
}
}
}
post {
success {
echo '배포가 성공적으로 완료되었습니다.'
}
failure {
script {
echo '배포에 실패했습니다. 이전 버전으로 롤백을 시도합니다.'
sshCommand remote: [
name: 'WAS Server',
host: "${env.SERVER_IP}",
user: "${env.SERVER_USER}",
identityFile: "${env.SSH_KEY_PATH}",
allowAnyHosts: true
], command: """
if [ -f ${env.BACKUP_FILE} ]; then
cp ${env.BACKUP_FILE} ${env.DEPLOY_FILE}
if nc -z localhost 8005; then
echo "Tomcat이 실행 중입니다. 종료 중..."
${env.TOMCAT_HOME}/bin/shutdown.sh
sleep 10
else
echo "Tomcat이 실행 중이지 않습니다."
fi
${env.TOMCAT_HOME}/bin/startup.sh
echo "롤백 완료"
else
echo "백업 파일이 존재하지 않아 롤백할 수 없습니다."
fi
"""
}
}
always {
echo '파이프라인 실행이 종료되었습니다.'
}
}
}

12
WEB-INF/web.xml Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" id="WebApp_ID">
<display-name>gcone_batch</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>

92
build.gradle Normal file
View File

@@ -0,0 +1,92 @@
plugins {
id 'java'
// id 'org.springframework.boot' version '3.1.2'
// id 'io.spring.dependency-management' version '1.1.2'
id 'org.springframework.boot' version '3.0.6'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'war'
}
war {
archiveBaseName = 'gcone_batch'
archiveFileName = 'gcone_batch.war'
archiveVersion = "0.0.0"
}
bootWar.enabled = false
war.enabled = true
group = 'com.wb'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
implementation 'org.springframework.boot:spring-boot-starter-batch'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation:3.0.2'
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.2'
implementation 'org.apache.commons:commons-collections4:4.4'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.2'
testImplementation 'org.springframework.batch:spring-batch-test'
// xml
implementation 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.0'
implementation 'org.glassfish.jaxb:jaxb-runtime:4.0.0'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
// 멀티데이터소스,JTA 설정
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'com.atomikos:transactions-spring-boot3-starter:6.0.0'
implementation 'jakarta.transaction:jakarta.transaction-api:2.0.1'
runtimeOnly 'mysql:mysql-connector-java:8.0.33'
implementation 'org.apache.commons:commons-email:1.5'
implementation 'com.googlecode.json-simple:json-simple:1.1.1'
implementation 'org.bouncycastle:bcprov-jdk15to18:1.68'
implementation 'org.bouncycastle:bcpkix-jdk15to18:1.68'
//email html parse
implementation group: 'org.jsoup', name: 'jsoup', version: '1.15.3'
// implementation 'jakarta.mail:jakarta.mail-api:2.1.3'
implementation 'org.eclipse.angus:jakarta.mail:1.1.0'
implementation 'jakarta.activation:jakarta.activation-api:2.1.2'
implementation 'org.springframework.boot:spring-boot-starter-mail:3.1.2'
// firebase
implementation 'com.google.firebase:firebase-admin:9.3.0'
}

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

248
gradlew vendored Normal file
View File

@@ -0,0 +1,248 @@
#!/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/HEAD/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
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# 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
if ! command -v java >/dev/null 2>&1
then
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
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
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
# 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"'
# 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 \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# 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" "$@"

92
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,92 @@
@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 ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
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% equ 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% equ 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!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

1
settings.gradle Normal file
View File

@@ -0,0 +1 @@
rootProject.name = 'sake_batch'

18
shell/appPushJob_run.sh Normal file
View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="appPushJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="atmcPurchsDcsnJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="changeDlvySttusJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="crmGetExtOrdrJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

2
shell/crontab.txt Normal file
View File

@@ -0,0 +1,2 @@
# 시퀀스 초기화(일배치) - 매일 00시 00분
* * * * * cd /home/batch_shell/shell; ./sampleJob_run.sh > /dev/null 2>&1

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="mbrGradUpdtJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="mqGetMbrAppnJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

18
shell/mqReq30DeleteJob.sh Normal file
View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="mqReq30DeleteJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="mssageCartJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="mssageCartSaleJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="mssageCouponEndJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="mssageDepositRequestJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="mssageUpdtSttusJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="mssageMlgExpJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

18
shell/mssageRvwJob_run.sh Normal file
View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="mssageRvwJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="mssageUpdtSttusJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="nonMbrTrgtJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

18
shell/npayRvwJob_run.sh Normal file
View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="npayRvwJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

18
shell/sampleJob_run.sh Normal file
View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="sampleJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="strStockUpdtJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

18
shell/strUpdtJob.sh Normal file
View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="strUpdtJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="tmpTrgtCartJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="tmpTrgtCartJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="tmpTrgtCouponEndJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="tmpTrgtDepositRequestJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="tmpTrgtMlgExpJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="tmpTrgtNonMbrMarktAgreJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,18 @@
#!/bin/sh
# JOB_NAME을 sampleJob으로 설정
JOB_NAME="tmpTrgtRvwJob"
# Tomcat이 실행 중인 호스트와 포트
HOST="172.31.20.11"
PORT="18210"
# REST API 호출
curl -X POST "http://${HOST}:${PORT}/gcone_batch/batch/run/${JOB_NAME}" -H "Content-Type: application/json"
# 결과 확인
if [ $? -eq 0 ]; then
echo "Batch job ${JOB_NAME} executed successfully."
else
echo "Failed to execute batch job ${JOB_NAME}."
fi

View File

@@ -0,0 +1,82 @@
package com.wb.domainserver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.*;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.StringUtils;
import java.util.Properties;
import java.util.Random;
@SpringBootApplication(exclude = {
HibernateJpaAutoConfiguration.class,
DataSourceAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class
})
@EnableAsync
@EnableScheduling
@EnableCaching
@EnableTransactionManagement(proxyTargetClass = true)
public class BatchApplication {
private static final Logger logger = LoggerFactory.getLogger(BatchApplication.class);
public static void main(String[] args) throws JobParametersInvalidException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {
SpringApplication app = new SpringApplication(BatchApplication.class);
app.setWebApplicationType(WebApplicationType.NONE);
//TODO: 프로그램 실행 처리
//app.run(BatchApplication.class, args);
ConfigurableApplicationContext ctx = app.run(args);
JobLauncher jobLauncher = ctx.getBean(JobLauncher.class);
logger.info(":::A args Length ::: " + args.length);
if (args.length > 0) {
Job job = ctx.getBean(args[0], Job.class);
JobParametersBuilder builder = new JobParametersBuilder();
builder.addLong("currTime", System.currentTimeMillis());
if (args.length > 1) {
Properties props = StringUtils.splitArrayElementsIntoProperties(args, "=");
int idx = 1;
for (Object okey : props.keySet() ) {
String key = (String) okey;
logger.info("parameter[" + idx + "] :::: " + key + "=" + props.get(key));
builder.addString(key, (String) props.get(key));
idx++;
}
}
JobExecution jobExecution = jobLauncher.run(job, builder.toJobParameters());
if (!jobExecution.getExitStatus().equals(ExitStatus.COMPLETED)) {
throw new RuntimeException(args[0] + " Job execution failed.");
}
} else {
throw new RuntimeException("배치JOB명은 필수 입니다. EX) java -jar app.jar 배치JOB명");
}
System.exit(0);
}
}

View File

@@ -0,0 +1,41 @@
package com.wb.domainserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableCaching
@EnableScheduling
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(BatchApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(ServletInitializer.class, args);
}
}
//@SpringBootApplication
//public class ServletInitializer extends SpringBootServletInitializer {
//
// @Override
// protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
// return application.sources(ServletInitializer.class);
// }
//
// public static void main(String[] args) {
// SpringApplication.run(ServletInitializer.class, args);
// }
//
//}

View File

@@ -0,0 +1,148 @@
package com.wb.domainserver.analysis.jobs;
import com.wb.domainserver.analysis.tasklet.*;
import com.wb.domainserver.crm.tasklet.InsertTsDelMbrAppnRegistTasklet;
import com.wb.domainserver.crm.tasklet.InsertTsMbrAppnRegistTasklet;
import com.wb.domainserver.crm.tasklet.InsertTsRegMbrAppnRegistTasklet;
import lombok.RequiredArgsConstructor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.listener.ExecutionContextPromotionListener;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
/**
* 주간보고 자동화 관련 배치
*
* @author 이동호
* @since 2024.06.10
* @version 1.0
*/
@RequiredArgsConstructor
@Configuration
@EnableBatchProcessing
public class AnalysisOrderListConfig extends DefaultBatchConfiguration{
private static final Logger logger = LoggerFactory.getLogger(AnalysisOrderListConfig.class);
private final SqlSessionFactory sqlSessionFactory;
private final InsertErpTotalStatisticsListTasklet insertErpTotalStatisticsListTasklet;
private final InsertShoppingMallOrderListTasklet insertShoppingMallOrderListTasklet;
private final InsertSmartStoreOrderListTasklet insertSmartStoreOrderListTasklet;
private final InsertErpGoodsTasklet insertErpGoodsTasklet;
private final InsertErpSetGoodsTasklet insertErpSetGoodsTasklet;
@Bean
public ExecutionContextPromotionListener promotionListener() {
ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener();
listener.setKeys(new String[]{"message"});
return listener;
}
/* ##############################################################################################
ERP,자사몰,스마트스토어 모든 주문정보 가져오기
################################################################################################# */
/* @param jobRepository
* @param transactionManager
* @return
*/
@Bean
public Job analysisOrderListJob(JobRepository jobRepository, PlatformTransactionManager transactionManager, ExecutionContextPromotionListener promotionListener) {
return new JobBuilder("analysisOrderListJob", jobRepository)
.start(insertErpTotalStatisticsListStep(jobRepository, transactionManager, promotionListener))
.next(insertSmartStoreOrderListStep(jobRepository, transactionManager, promotionListener))
//.next(insertShoppingMallOrderListStep(jobRepository, transactionManager, promotionListener))
.incrementer(new RunIdIncrementer())
.build();
}
/**
* 1. mq -> gcone db로 erp 주문 데이터 추출후 insert
*/
@Bean
public Step insertErpTotalStatisticsListStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, ExecutionContextPromotionListener promotionListener) {
return new StepBuilder("insertErpTotalStatisticsListStep", jobRepository)
.tasklet(insertErpTotalStatisticsListTasklet, transactionManager)
.listener(promotionListener)
.build();
}
/**
* 2. 자사몰 주문 목록 추출후 insert
*/
@Bean
public Step insertShoppingMallOrderListStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, ExecutionContextPromotionListener promotionListener) {
return new StepBuilder("insertShoppingMallOrderListStep", jobRepository)
.tasklet(insertShoppingMallOrderListTasklet, transactionManager)
.listener(promotionListener)
.build();
}
/**
* 3. 스마트스토어 주문 목록 추출후 insert
*/
@Bean
public Step insertSmartStoreOrderListStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, ExecutionContextPromotionListener promotionListener) {
return new StepBuilder("insertSmartStoreOrderListStep", jobRepository)
.tasklet(insertSmartStoreOrderListTasklet, transactionManager)
.listener(promotionListener)
.build();
}
/* ##############################################################################################
MQ -> ERP 제상품 현황, 세트코드 가져오기
################################################################################################# */
/* @param jobRepository
* @param transactionManager
* @return
*/
@Bean
public Job analysisErpGoodsJob(JobRepository jobRepository, PlatformTransactionManager transactionManager, ExecutionContextPromotionListener promotionListener) {
return new JobBuilder("analysisErpGoodsJob", jobRepository)
.start(insertErpGoodsStep(jobRepository, transactionManager, promotionListener))
.next(insertErpSetGoodsStep(jobRepository, transactionManager, promotionListener))
.incrementer(new RunIdIncrementer())
.build();
}
/**
* 1. MQ -> ERP 제상품 현황 INSERT
*/
@Bean
public Step insertErpGoodsStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, ExecutionContextPromotionListener promotionListener) {
return new StepBuilder("insertErpGoodsStep", jobRepository)
.tasklet(insertErpGoodsTasklet, transactionManager)
.listener(promotionListener)
.build();
}
/**
* 2. MQ -> ERP 세트상품 현황 INSERT
*/
@Bean
public Step insertErpSetGoodsStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, ExecutionContextPromotionListener promotionListener) {
return new StepBuilder("insertErpSetGoodsStep", jobRepository)
.tasklet(insertErpSetGoodsTasklet, transactionManager)
.listener(promotionListener)
.build();
}
}

View File

@@ -0,0 +1,75 @@
package com.wb.domainserver.analysis.tasklet;
import com.wb.domainserver.analysis.vo.TsAnalysisErpGoodsVO;
import com.wb.domainserver.analysis.vo.TsAnalysisErpSetGoodsVO;
import com.wb.domainserver.crm.tasklet.InsertTsRegMbrAppnRegistTasklet;
import com.wb.domainserver.crm.vo.TsMemberAppnVO;
import com.wb.domainserver.mapper.gcone.AnalysisMapper;
import com.wb.domainserver.mapper.gcone.MemberAppnMapper;
import com.wb.domainserver.mapper.mq.MqReqCommMapper;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.scope.context.StepContext;
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
@JobScope
@Slf4j
public class InsertErpGoodsTasklet implements Tasklet {
private static final Logger logger = LoggerFactory.getLogger(InsertTsRegMbrAppnRegistTasklet.class);
@Autowired
private MqReqCommMapper mqReqCommMapper;
@Autowired
private AnalysisMapper analysisMapper;
private StepExecution stepExecution;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
StepContext stepContext = StepSynchronizationManager.getContext();
System.out.println("==========================================");
System.out.println("InsertErpGoodsTasklet 실행");
Map<String,Object> message = new HashMap<>();
try {
List<TsAnalysisErpGoodsVO> goodsVOList = mqReqCommMapper.selectErpGoodsList();
if (goodsVOList!=null && !goodsVOList.isEmpty()) {
analysisMapper.deleteErpGoods();
analysisMapper.insertErpGoods(goodsVOList);
}
} catch (Exception e) {
e.printStackTrace();
message.put("status", "0");
message.put("message", "GC_ANALYSIS_ERP_GOODS 테이블에 insert 실패!!");
}
stepContext = StepSynchronizationManager.getContext();
stepContext.getStepExecution().getExecutionContext().put("message", message);
System.out.println("InsertErpSetGoodsTasklet 종료");
System.out.println("==========================================");
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,75 @@
package com.wb.domainserver.analysis.tasklet;
import com.wb.domainserver.analysis.vo.TsAnalysisErpSetGoodsVO;
import com.wb.domainserver.crm.tasklet.InsertTsRegMbrAppnRegistTasklet;
import com.wb.domainserver.crm.vo.TsMemberAppnVO;
import com.wb.domainserver.mapper.gcone.AnalysisMapper;
import com.wb.domainserver.mapper.gcone.GconeMqReqCommMapper;
import com.wb.domainserver.mapper.gcone.MemberAppnMapper;
import com.wb.domainserver.mapper.mq.MqReqCommMapper;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.scope.context.StepContext;
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
@JobScope
@Slf4j
public class InsertErpSetGoodsTasklet implements Tasklet {
private static final Logger logger = LoggerFactory.getLogger(InsertTsRegMbrAppnRegistTasklet.class);
@Autowired
private MqReqCommMapper mqReqCommMapper;
@Autowired
private AnalysisMapper analysisMapper;
private StepExecution stepExecution;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
StepContext stepContext = StepSynchronizationManager.getContext();
System.out.println("==========================================");
System.out.println("InsertErpSetGoodsTasklet 실행");
Map<String,Object> message = new HashMap<>();
try {
List<TsAnalysisErpSetGoodsVO> setGoodsVOList = mqReqCommMapper.selectErpSetGoodsList();
if (setGoodsVOList!=null && !setGoodsVOList.isEmpty()) {
analysisMapper.deleteErpSetGoods();
analysisMapper.insertErpSetGoods(setGoodsVOList);
}
} catch (Exception e) {
e.printStackTrace();
message.put("status", "0");
message.put("message", "GC_ANALYSIS_ERP_SET_GOODS 테이블에 insert 실패!!");
}
stepContext = StepSynchronizationManager.getContext();
stepContext.getStepExecution().getExecutionContext().put("message", message);
System.out.println("InsertErpSetGoodsTasklet 종료");
System.out.println("==========================================");
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,64 @@
package com.wb.domainserver.analysis.tasklet;
import com.wb.domainserver.analysis.vo.TsAnalysisErpTotalStatisticsVO;
import com.wb.domainserver.analysis.vo.TsAnalysisOrderListVO;
import com.wb.domainserver.crm.tasklet.InsertTsRegMbrAppnRegistTasklet;
import com.wb.domainserver.mapper.gcone.AnalysisMapper;
import com.wb.domainserver.mapper.mq.MqReqCommMapper;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.scope.context.StepContext;
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
@Component
@JobScope
@Slf4j
public class InsertErpTotalStatisticsListTasklet implements Tasklet {
private static final Logger logger = LoggerFactory.getLogger(InsertErpTotalStatisticsListTasklet.class);
@Autowired
private AnalysisMapper mapper;
@Autowired
private MqReqCommMapper mqReqCommMapper;
private StepExecution stepExecution;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
StepContext stepContext = StepSynchronizationManager.getContext();
System.out.println("==========================================");
System.out.println("MemberAppnLogDelTasklet 실행");
Map<String,Object> message = new HashMap<>();
List<TsAnalysisErpTotalStatisticsVO> mqErpTotalStatisticsList = mqReqCommMapper.selectMqErpTotalStatisticsList();
List<TsAnalysisErpTotalStatisticsVO> orderList = new ArrayList<>();
if (mqErpTotalStatisticsList.size() > 0 ) {
mapper.insertTotalList(mqErpTotalStatisticsList);
}
stepContext = StepSynchronizationManager.getContext();
stepContext.getStepExecution().getExecutionContext().put("message", message);
System.out.println("InsertErpTotalStatisticsListTasklet 종료");
System.out.println("==========================================");
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,142 @@
package com.wb.domainserver.analysis.tasklet;
import com.wb.domainserver.analysis.vo.TsAnalysisOrderListVO;
import com.wb.domainserver.crm.tasklet.InsertTsRegMbrAppnRegistTasklet;
import com.wb.domainserver.mapper.gcone.AnalysisMapper;
import com.wb.domainserver.util.dataaccess.DataMap;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.scope.context.StepContext;
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
@Component
@JobScope
@Slf4j
public class InsertShoppingMallOrderListTasklet implements Tasklet {
private static final Logger logger = LoggerFactory.getLogger(InsertTsRegMbrAppnRegistTasklet.class);
@Autowired
private AnalysisMapper mapper;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
StepContext stepContext = StepSynchronizationManager.getContext();
log.info("==========================================");
log.info("InsertShoppingMallOrderListTasklet 실행");
Date sDate = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(sDate);
calendar.add(Calendar.DAY_OF_MONTH, -3);
Date eDate = calendar.getTime();
DataMap params = new DataMap();
params.put("sDate", sDate);
params.put("eDate", eDate);
Map<String, Object> message = new HashMap<>();
List<TsAnalysisOrderListVO> tsAnalysisOrderListVOS = mapper.selectShoppingMallOrderList(params);
List<DataMap> goodsMapList;
List<TsAnalysisOrderListVO> allTsAnalysisOrderList = new ArrayList<>();
DataMap paramMap = new DataMap();
int iCount = 0;
int jCount = 0;
if (tsAnalysisOrderListVOS != null && !tsAnalysisOrderListVOS.isEmpty()) {
for (int i = 0; i < tsAnalysisOrderListVOS.size(); i++) {
goodsMapList = mapper.selectbarcodeGoodsInfo(tsAnalysisOrderListVOS.get(i).getBarcode());
if (goodsMapList != null && !goodsMapList.isEmpty()) {
allTsAnalysisOrderList.add(tsAnalysisOrderListVOS.get(i));
iCount++;
} else {
BigDecimal rlSetleAmt = BigDecimal.ZERO;
paramMap.put("goodsCode", tsAnalysisOrderListVOS.get(i).getBarcode());
if("".equals(tsAnalysisOrderListVOS.get(i).getBarcode()) || tsAnalysisOrderListVOS.get(i).getBarcode() == null) {
continue;
}
goodsMapList = mapper.selectsetCodeGoodsInfo(paramMap);
if (goodsMapList != null && !goodsMapList.isEmpty()) {
Set<String> sameBarcodeSet = goodsMapList.stream()
.map(p -> p != null ? (String) p.get("barcode") : null)
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(
barcode -> barcode,
Collectors.counting()
))
.entrySet().stream()
.filter(p -> p.getValue() > 1)
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
int barcodeQy = goodsMapList.stream()
.filter(map -> sameBarcodeSet.contains(map.get("barcode").toString()))
.mapToInt(map -> (int) map.getOrDefault("barcodeQy", 1))
.sum();
for (int j = 0; j < goodsMapList.size(); j++) {
jCount++;
if (j == 0) {
rlSetleAmt = tsAnalysisOrderListVOS.get(i).getRlSetleAmt();
}
if (barcodeQy != 0) {
tsAnalysisOrderListVOS.get(i).setBarcodeQy(barcodeQy);
} else {
tsAnalysisOrderListVOS.get(i).setBarcodeQy(
Optional.ofNullable(goodsMapList.get(j))
.map(map -> (int) map.get("barcodeQy"))
.orElse(1)
);
}
tsAnalysisOrderListVOS.get(i).setShopSetCd(
Optional.ofNullable(goodsMapList.get(j))
.map(map -> (String) map.get("setCode"))
.orElse("")
);
tsAnalysisOrderListVOS.get(i).setBarcode(
Optional.ofNullable(goodsMapList.get(j))
.map(map -> (String) map.get("barcode"))
.orElse("")
);
tsAnalysisOrderListVOS.get(i).setRlSetleAmt(rlSetleAmt);
allTsAnalysisOrderList.add(tsAnalysisOrderListVOS.get(i));
}
}
}
}
System.out.println("iCount : " + iCount);
System.out.println("jCount : " + jCount);
mapper.insertOrderList(allTsAnalysisOrderList);
}
stepContext = StepSynchronizationManager.getContext();
stepContext.getStepExecution().getExecutionContext().put("message", message);
log.info("InsertShoppingMallOrderListTasklet 종료");
log.info("==========================================");
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,698 @@
package com.wb.domainserver.analysis.tasklet;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wb.domainserver.analysis.vo.TsAnalysisOrderListVO;
import com.wb.domainserver.crm.tasklet.InsertTsRegMbrAppnRegistTasklet;
import static java.util.Map.entry;
import com.wb.domainserver.mapper.gcone.AnalysisMapper;
import com.wb.domainserver.util.dataaccess.DataMap;
import lombok.extern.slf4j.Slf4j;
import org.json.simple.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.scope.context.StepContext;
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import com.wb.domainserver.analysis.vo.SmartStoreProperties;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
@Component
@JobScope
@Slf4j
public class InsertSmartStoreOrderListTasklet implements Tasklet {
private static final Logger logger = LoggerFactory.getLogger(InsertTsRegMbrAppnRegistTasklet.class);
private static final String PAYMENT_WAITING = "PAYMENT_WAITING";
private static final String CANCELED_BY_NOPAYMENT = "CANCELED_BY_NOPAYMENT";
private static final String ACCOUNT_ID_NC = "nutricore";
private static final String ACCOUNT_ID_DT = "ncp_1ns2z5_01";
private static final String ACCOUNT_ID_CH = "shadow222";
private static final String ACCOUNT_ID_LF = "ncp_1np5dl_01";
private static final String ACCOUNT_ID_TZ = "thezac";
private static final String ACCOUNT_ID_NB = "ncp_1nlp35_01";
private static final String ACCOUNT_ID_PL = "proslab";
private static final String ACCOUNT_ID_AF = "ncp_1nm5zw_01";
private static final String ACCOUNT_ID_BD = "ncp_1nprdw_01";
private static final String ACCOUNT_ID_DL = "ncp_1nsmcy_01";
private static final String ACCOUNT_ID_HMALL = "ncp_1nxwne_01";
@Autowired
private final SmartStoreProperties smartStoreProperties;
@Autowired
private final Environment env;
@Autowired
private AnalysisMapper analysisMapper;
@Value("${smartstoreurl.tokenurl}")
private String tokenUri;
@Value("${smartstoreurl.orderlisturl}")
private String orderListUrl;
@Value("${smartstoreurl.orderdetailurl}")
private String orderdetailurl;
private StepExecution stepExecution;
public InsertSmartStoreOrderListTasklet(SmartStoreProperties smartStoreProperties, Environment env) {
this.smartStoreProperties = smartStoreProperties;
this.env = env;
}
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
StepContext stepContext = StepSynchronizationManager.getContext();
System.out.println("==========================================");
System.out.println("InsertSmartStoreOrderListTasklet 실행");
Long timestamp = System.currentTimeMillis();
Map<String,Object> message = new HashMap<>();
List<DataMap> orderCodeList = new ArrayList<>();
List<Map<String,Object>> orginDataList = new ArrayList<>();
List<String> sopmalCd = new ArrayList<>();
Map<String ,Map<String,String>> properties = null;
String clientSecretSign = "";
String accessToken = "";
List<TsAnalysisOrderListVO> allTsAnalysisOrderListVOList = new ArrayList<>();
List<TsAnalysisOrderListVO> tsAnalysisOrderListVOList = new ArrayList<>();
sopmalCd = smartStoreProperties.getStoreCodes();
String clientId = "";
String clientSecret = "";
// 쇼핑몰별 네이버 토큰 api 생성
for (String sopmal : sopmalCd) {
properties = smartStoreProperties.getStores();
clientId = properties.get(sopmal).get("clientId");
clientSecret = properties.get(sopmal).get("clientSecret");
clientSecretSign = generateSignature(clientId,clientSecret,timestamp);
System.out.println("clientId : " + clientId);
System.out.println("clientSecret : " + clientSecret);
System.out.println("clientSecretSign : " + clientSecretSign);
accessToken = getAccessToken (clientId,timestamp,clientSecretSign);
System.out.println("accessToken" + accessToken);
properties.get(sopmal).put("accessToken : ", accessToken);
orderCodeList = getOrderCodeList(accessToken);
tsAnalysisOrderListVOList = ApiOrder(accessToken,orderCodeList,tsAnalysisOrderListVOList,sopmal);
allTsAnalysisOrderListVOList.addAll(tsAnalysisOrderListVOList);
tsAnalysisOrderListVOList.clear();
orginDataList.clear();
orderCodeList.clear();
}
analysisMapper.insertOrderList(allTsAnalysisOrderListVOList);
stepContext = StepSynchronizationManager.getContext();
stepContext.getStepExecution().getExecutionContext().put("message", message);
System.out.println("InsertSmartStoreOrderListTasklet 종료");
System.out.println("==========================================");
System.out.println("allTsAnalysisOrderListVOList 사이즈 : " + allTsAnalysisOrderListVOList.size());
return RepeatStatus.FINISHED;
}
public String generateSignature(String clientId, String clientSecret, Long timestamp) {
// 밑줄로 연결하여 password 생성
String password = String.join("_", clientId, timestamp.toString());
// bcrypt 해싱
String hashedPw = BCrypt.hashpw(password, clientSecret);
// base64 인코딩
return Base64.getUrlEncoder().encodeToString(hashedPw.getBytes(StandardCharsets.UTF_8));
}
public String getAccessToken(String clientId, Long timestamp, String clientSecretSign) {
HttpURLConnection httpURLConnection = null;
ObjectMapper objectMapper = new ObjectMapper();
BufferedReader reader = null;
OutputStream outputStream = null;
try {
URL url = new URL(tokenUri);
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
httpURLConnection.setDoOutput(true);
StringBuilder sb = new StringBuilder();
sb.append("client_id=").append(clientId)
.append("&timestamp=").append(timestamp)
.append("&client_secret_sign=").append(clientSecretSign)
.append("&type=SELF")
.append("&grant_type=client_credentials");
outputStream = httpURLConnection.getOutputStream();
byte[] input = sb.toString().getBytes(StandardCharsets.UTF_8);
outputStream.write(input, 0, input.length);
int responseCode = httpURLConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
reader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), StandardCharsets.UTF_8));
String response = reader.lines().collect(java.util.stream.Collectors.joining());
Map<String, Object> mapResponse = objectMapper.readValue(response, Map.class);
JSONObject jsonResponse = new JSONObject(mapResponse);
return jsonResponse.get("access_token").toString();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 자원 반납
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (httpURLConnection != null) {
System.out.println("TOKEN HttpURLConnection is being disconnected");
httpURLConnection.disconnect();
}
}
return null;
}
public List<DataMap> getOrderCodeList(String accessToken) {
List<DataMap> allResults = new ArrayList<>();
for (int day = -3; day <= 0; day++) {
final int currentDay = day;
allResults.addAll(fetchSequentialDataForDay(accessToken, currentDay));
}
System.out.println("allresults : " + allResults.size());
return allResults;
}
private List<DataMap> fetchSequentialDataForDay(String accessToken, int day) {
List<String> results = new ArrayList<>();
String moreSequence = null;
String moreFrom = null;
List<DataMap> changeDateList = new ArrayList<>();
do {
Map<String, Object> response = new HashMap<>();
try {
if (moreFrom != null) {
response = fetchOrderData(accessToken, moreFrom,getLastChangedTo(day), moreSequence);
} else {
response = fetchOrderData(accessToken, getLastChangedFrom(day), getLastChangedTo(day), moreSequence);
}
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
if (response == null) break;
Map<String, Object> data = (Map<String, Object>) response.get("data");
if (data == null) break;
List<Map<String, Object>> lastChangeStatuses = (List<Map<String, Object>>) data.get("lastChangeStatuses");
for (Map<String, Object> status : lastChangeStatuses) {
DataMap changeDateMap = new DataMap();
results.add((String) status.get("productOrderId"));
changeDateMap.put("ordrId", (String) status.get("productOrderId"));
changeDateMap.put("lastChangedDate", (String) status.get("lastChangedDate"));
changeDateList.add(changeDateMap);
}
Map<String, Object> moreMap = (Map<String, Object>) data.get("more");
moreSequence = moreMap != null ? (String) moreMap.get("moreSequence") : null;
moreFrom = moreMap != null ? (String) moreMap.get("moreFrom") : null;
} while (moreSequence != null);
return changeDateList;
}
private String getLastChangedFrom(int day) {
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Asia/Seoul"));
calendar.add(Calendar.DAY_OF_MONTH, day);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
OffsetDateTime startDate = calendar.toInstant().atOffset(ZoneOffset.ofHours(9));
return startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"));
}
private String getLastChangedTo(int day) {
OffsetDateTime startDate;
if (day == 0) {
startDate = OffsetDateTime.now(ZoneId.of("Asia/Seoul"));
} else {
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Asia/Seoul"));
calendar.add(Calendar.DAY_OF_MONTH, day);
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
calendar.set(Calendar.MILLISECOND, 59);
startDate = calendar.toInstant().atOffset(ZoneOffset.ofHours(9));
}
return startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"));
}
private Map<String, Object> fetchOrderData(String accessToken, String lastChangedFrom, String lastChangedTo, String moreSequence) throws IOException {
String urlParam = String.format("%s?lastChangedFrom=%s&lastChangedTo=%s",
orderListUrl,
URLEncoder.encode(lastChangedFrom, StandardCharsets.UTF_8),
URLEncoder.encode(lastChangedTo, StandardCharsets.UTF_8));
if (moreSequence != null) {
urlParam += "&moreSequence=" + moreSequence;
}
HttpURLConnection connection = null;
InputStream inputStream = null;
BufferedReader reader = null;
try {
connection = (HttpURLConnection) new URL(urlParam).openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", "Bearer " + accessToken);
connection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
String response = "";
int responseCode = connection.getResponseCode();
if (responseCode >= 400) {
inputStream = connection.getErrorStream();
reader = new BufferedReader(new InputStreamReader(inputStream));
String errorResponse = reader.lines().collect(Collectors.joining());
System.out.println("Error Response: " + errorResponse);
} else {
inputStream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream));
response = reader.lines().collect(Collectors.joining());
}
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(response, Map.class);
} catch (IOException e) {
e.printStackTrace();
throw e;
}
}
public List<TsAnalysisOrderListVO> getOrderDetailList (String accessToken, List<DataMap> orderCodeList,List<TsAnalysisOrderListVO> tsAnalysisOrderListVOList, String sopmalCd) {
Map<String, Object> requestBody = new HashMap<>();
List<String> productOrderIdList = new ArrayList<>();
List<Map<String, String>> orderDetailsList = new ArrayList<>();
Map<String, Object> result = new HashMap<>();
Instant start = Instant.now();
// productOrderId만 넘기기위한 작업
for (DataMap status : orderCodeList) {
String productOrderId = (String) status.get("ordrId");
String lastChangedDate = (String) status.get("lastChangedDate");
if (productOrderId != null) {
productOrderIdList.add(productOrderId);
Map<String, String> orderDetail = new HashMap<>();
orderDetail.put(productOrderId, lastChangedDate);
orderDetailsList.add(orderDetail);
}
}
requestBody.put("productOrderIds", productOrderIdList);
Map<String, String> accountMap = new HashMap<>();
accountMap = accountIdMapping();
HttpURLConnection httpURLConnection = null;
try {
URL url = new URL(orderdetailurl);
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Authorization", "Bearer " + accessToken);
httpURLConnection.setRequestProperty("content-type", "application/json");
httpURLConnection.setDoOutput(true);
try (OutputStream os = httpURLConnection.getOutputStream()) {
byte[] input = new ObjectMapper().writeValueAsBytes(requestBody);
os.write(input, 0, input.length);
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), StandardCharsets.UTF_8))) {
String input;
StringBuffer response = new StringBuffer();
while ((input = reader.readLine()) != null) {
response.append(input);
}
reader.close();
httpURLConnection.disconnect();
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> responseMap = objectMapper.readValue(response.toString(), Map.class);
List<Map<String, Object>> dataMap = (List<Map<String, Object>>) responseMap.get("data");
//List<Map<String, Object>> productOrderMap = (List<Map<String, Object>>) dataMap.get("productOrder");
if (!dataMap.isEmpty()) {
for (int i = 0; i < dataMap.size(); i++) {
Map<String, Object> order = (Map<String, Object>) dataMap.get(i).get("order");
Map<String, Object> productOrder = (Map<String, Object>) dataMap.get(i).get("productOrder");
String claimType = (String) productOrder.get("claimType");
LocalDateTime lastChangedDate = null;
String ordrStatus = (String) productOrder.get("productOrderStatus");
String goodsCode = (String) productOrder.get("optionManageCode");
if (PAYMENT_WAITING.equals(ordrStatus) || CANCELED_BY_NOPAYMENT.equals(ordrStatus)) {
continue;
}
if ("".equals(goodsCode) || goodsCode == null) {
goodsCode = (String) productOrder.get("sellerProductCode");
}
// 마지막 변화일 저장을 위한 비교후 데이터 저장
for (Map<String, String> lastChangeMap : orderDetailsList) {
String productOrderId = (String) productOrder.get("productOrderId");
if (lastChangeMap.containsKey(productOrderId)) {
lastChangedDate = convertToLocalDateTime(lastChangeMap.get(productOrderId));
}
}
DataMap goodsMap = new DataMap();
DataMap param = new DataMap();
List<DataMap> goodsMapList = new ArrayList<>();
String setCode = "";
String missingFlag = "N";
BigDecimal goodsPrice = BigDecimal.ZERO;
BigDecimal totalPaymentAmount = BigDecimal.ZERO;
List<String> sopmalCdList = new ArrayList<>();
TsAnalysisOrderListVO tsAnalysisOrderListVO = null;
String productOption = Optional.ofNullable(productOrder.get("productOption") != null ? (String) productOrder.get("productOption") : null)
.orElse("");
String claimStatus = Optional.ofNullable(productOrder.get("claimStatus") != null ? (String) productOrder.get("claimStatus") : null)
.orElse("");
String decisionDate = Optional.ofNullable(productOrder.get("decisionDate") != null ? (String) productOrder.get("decisionDate") : null)
.orElse(null);
//바코드 상품조회
goodsMapList = analysisMapper.selectbarcodeGoodsInfo(goodsCode);
if (goodsMapList != null && goodsMapList.size() > 0) {
goodsCode = (String) goodsMapList.get(0).get("barcode");
if (sopmalCd.equals("HMALL") || sopmalCd.equals("AF")) {
sopmalCd = (String) goodsMapList.get(0).get("sopmalCd");
}
totalPaymentAmount = BigDecimal.valueOf((Integer) productOrder.get("totalPaymentAmount"));
goodsPrice = calCulate(
BigDecimal.valueOf((Integer) productOrder.get("totalPaymentAmount")),
BigDecimal.valueOf((Integer) productOrder.get("productDiscountAmount")),
BigDecimal.valueOf((Integer) productOrder.get("sellerBurdenDiscountAmount")),
BigDecimal.valueOf((Integer) productOrder.get("deliveryFeeAmount"))
);
tsAnalysisOrderListVO = createBaseOrderListVO(order, productOrder, sopmalCd, claimType, goodsPrice, totalPaymentAmount, goodsCode, 1, "", ordrStatus, lastChangedDate, productOption, claimStatus, decisionDate, missingFlag);
tsAnalysisOrderListVOList.add(tsAnalysisOrderListVO);
} else {
sopmalCd = accountMap.get((String) productOrder.get("mallId"));
param.put("goodsCode", goodsCode);
goodsMapList = analysisMapper.selectsetCodeGoodsInfo(param);
//세트 코드 제품 분할작업
if (goodsMapList.size() > 0) {
//중복 바코드 추리기
Set<String> sameBarcodeSet = goodsMapList.stream().map(p -> p != null ? (String) p.get("barcode") : null)
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(barcode -> barcode, Collectors.counting()))
.entrySet().stream()
.filter(p -> p.getValue() > 1)
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
// 단일 세트상품 수량합치기
int barcodeQy = goodsMapList.stream()
.filter(map -> sameBarcodeSet.contains(map.get("barcode").toString()))
.mapToInt(map -> (int) map.getOrDefault("barcodeQy", 0))
.sum();
for (int k = 0; k < goodsMapList.size(); k++) {
// 세트상품 첫 제품에 금액 몰아주기
if (k == 0) {
goodsPrice = calCulate(
BigDecimal.valueOf((Integer) productOrder.get("totalPaymentAmount")),
BigDecimal.valueOf((Integer) productOrder.get("productDiscountAmount")),
BigDecimal.valueOf((Integer) productOrder.get("sellerBurdenDiscountAmount")),
BigDecimal.valueOf((Integer) productOrder.get("deliveryFeeAmount"))
);
totalPaymentAmount = BigDecimal.valueOf((Integer) productOrder.get("totalPaymentAmount"));
} else {
totalPaymentAmount = BigDecimal.ZERO;
goodsPrice = BigDecimal.ZERO;
}
//단일 세트상품일 경우 가격은 같게 갯수는 더해줌
if (sameBarcodeSet.contains(goodsMapList.get(k).get("barcode"))) {
goodsPrice = calCulate(
BigDecimal.valueOf((Integer) productOrder.get("totalPaymentAmount")),
BigDecimal.valueOf((Integer) productOrder.get("productDiscountAmount")),
BigDecimal.valueOf((Integer) productOrder.get("sellerBurdenDiscountAmount")),
BigDecimal.valueOf((Integer) productOrder.get("deliveryFeeAmount"))
);
totalPaymentAmount = BigDecimal.valueOf((Integer) productOrder.get("totalPaymentAmount"));
} else {
barcodeQy = Optional.ofNullable(goodsMapList.get(k) != null ? (int) goodsMapList.get(k).get("barcodeQy") : 1)
.orElse(1);
}
goodsCode = Optional.ofNullable(goodsMapList.get(k) != null ? (String) goodsMapList.get(k).get("barcode") : null)
.orElse((String) productOrder.get("optionManageCode"));
if (sopmalCd.equals("HMALL") || sopmalCd.equals("AF")) {
sopmalCd = goodsMapList.get(k) != null ? (String) goodsMapList.get(k).get("sopmalCd") : sopmalCd;
}
setCode = Optional.ofNullable(goodsMapList.get(k) != null ? (String) goodsMapList.get(k).get("setCode") : null)
.orElse("");
tsAnalysisOrderListVO = createBaseOrderListVO(
order, productOrder, sopmalCd, claimType, goodsPrice, totalPaymentAmount, goodsCode, barcodeQy, setCode, ordrStatus, lastChangedDate, productOption, claimStatus, decisionDate, missingFlag
);
tsAnalysisOrderListVOList.add(tsAnalysisOrderListVO);
}
} else {
totalPaymentAmount = BigDecimal.valueOf((Integer) productOrder.get("totalPaymentAmount"));
goodsPrice = calCulate(
BigDecimal.valueOf((Integer) productOrder.get("totalPaymentAmount")),
BigDecimal.valueOf((Integer) productOrder.get("productDiscountAmount")),
BigDecimal.valueOf((Integer) productOrder.get("sellerBurdenDiscountAmount")),
BigDecimal.valueOf((Integer) productOrder.get("deliveryFeeAmount"))
);
int barcodeQy = 1;
// UPSERT를 위한 초기화
if (goodsCode == null) goodsCode = "";
if (setCode == null) setCode = "";
missingFlag = "Y";
tsAnalysisOrderListVO = createBaseOrderListVO(
order, productOrder, sopmalCd, claimType, goodsPrice, totalPaymentAmount, goodsCode, barcodeQy, setCode, ordrStatus, lastChangedDate, productOption, claimStatus, decisionDate, missingFlag
);
tsAnalysisOrderListVOList.add(tsAnalysisOrderListVO);
}
}
}
}
//log.debug("데이터입니당" + tsAnalysisOrderListVOList);
}
} catch (Exception apiException) {
System.err.println("API 호출 실패: " + apiException.getMessage());
apiException.printStackTrace();
} finally {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
return tsAnalysisOrderListVOList;
}
public String setOrderStatusCode (String ordrSttusCd) {
Map<String, Integer> statusPriority = Map.ofEntries(
entry("PAYMENT_WAITING", 15),
entry("PAYED", 25),
entry("DELIVERING", 65),
entry("DELIVERED", 75),
entry("PURCHASE_DECIDED", 75),
entry("CANCELED", 85),
entry("RETURN", 85),
entry("EXCHANGE", 85),
entry("PURCHASE_DECISION_HOLDBACK", 85),
entry("CANCELED_BY_NOPAYMENT", 99)
);
Integer priority = statusPriority.get(ordrSttusCd);
return (priority != null) ? priority.toString() : "15";
}
public static LocalDateTime convertToLocalDateTime(String isoDate) {
return LocalDateTime.parse(isoDate, DateTimeFormatter.ISO_DATE_TIME);
}
public List<TsAnalysisOrderListVO> ApiOrder (String accessToken, List<DataMap> orderCodeList,List<TsAnalysisOrderListVO> tsAnalysisOrderListVOList, String sopmal) {
final int MAX_ORDER_SIZE = 300;
int totalOrderCnt = orderCodeList.size();
Instant startTime = Instant.now();
for (int i = 0; i < totalOrderCnt; i += MAX_ORDER_SIZE) {
int end = Math.min(i + MAX_ORDER_SIZE, totalOrderCnt);
List<DataMap> maxList = orderCodeList.subList(i, end);
tsAnalysisOrderListVOList = getOrderDetailList(accessToken,maxList , tsAnalysisOrderListVOList, sopmal);
}
Instant ends = Instant.now();
// 시작 시간과 종료 시간 차이 계산
long timeElapsedInMillis = ends.toEpochMilli() - startTime.toEpochMilli();
long timeElapsedInSeconds = timeElapsedInMillis / 1000; // 밀리초를 초로 변환
System.out.println("디테일 경과 시간: " + timeElapsedInSeconds + "초");
return tsAnalysisOrderListVOList;
}
public Date formatDate(String date) {
try {
ZonedDateTime zonedDateTime = ZonedDateTime.parse(date);
return Date.from(zonedDateTime.toInstant());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public BigDecimal calCulate (BigDecimal totalPaymentAmount, BigDecimal productDiscountAmount, BigDecimal sellerBurdenDiscountAmount, BigDecimal deliveryFeeAmount ) {
return totalPaymentAmount.add(productDiscountAmount).subtract(sellerBurdenDiscountAmount).add(deliveryFeeAmount);
}
public Map<String,String> accountIdMapping () {
Map<String,String> accountMap = new HashMap<>();
accountMap.put(ACCOUNT_ID_AF,"AF");
accountMap.put(ACCOUNT_ID_NC,"NC");
accountMap.put(ACCOUNT_ID_BD,"BD");
accountMap.put(ACCOUNT_ID_CH,"CH");
accountMap.put(ACCOUNT_ID_DL,"DL");
accountMap.put(ACCOUNT_ID_DT,"DT");
accountMap.put(ACCOUNT_ID_LF,"LF");
accountMap.put(ACCOUNT_ID_TZ,"TZ");
accountMap.put(ACCOUNT_ID_NB,"NB");
accountMap.put(ACCOUNT_ID_PL,"PL");
accountMap.put(ACCOUNT_ID_HMALL,"HMALL");
return accountMap;
}
private TsAnalysisOrderListVO createBaseOrderListVO(
Map<String, Object> order,
Map<String, Object> productOrder,
String sopmalCd,
String claimType,
BigDecimal goodsPrice,
BigDecimal totalPaymentAmount,
String goodsCode,
int barcodeQy,
String setCode,
String ordrStatus,
LocalDateTime lastChangedDate,
String productOption,
String claimStatus,
String decisionDate,
String missingFlag
) {
return TsAnalysisOrderListVO.builder()
.productOrdrInnb((String) productOrder.get("productOrderId"))
.ordrInnb((String) order.get("orderId"))
.paymentDt(formatDate((String) order.get("paymentDate")))
.goodsNm((String) productOrder.get("productName"))
.goodsQy((int) productOrder.get("quantity"))
.ordrSttusCd(setOrderStatusCode(ordrStatus))
.sopmalDv("스마트스토어")
.totalPaymentAmount(totalPaymentAmount)
.barcode(goodsCode)
.barcodeQy(barcodeQy)
.shopSetCd(setCode)
.sopmalCd(sopmalCd)
.baesongBi(BigDecimal.valueOf((Integer) productOrder.get("deliveryFeeAmount")))
.claimType(claimType)
.rlSetleAmt(goodsPrice)
.lastChangedDate(lastChangedDate)
.productOption(productOption)
.claimStatus(claimStatus)
.decisionDate(decisionDate != null ? formatDate(decisionDate) : null)
.missingFlag(missingFlag)
.build();
}
}

View File

@@ -0,0 +1,20 @@
package com.wb.domainserver.analysis.vo;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Component
@ConfigurationProperties(prefix = "smartstore.sopmal")
@Data
public class SmartStoreProperties {
private Map<String, Map<String, String>> stores;
public List<String> getStoreCodes() {
return new ArrayList<>(stores.keySet());
}
}

View File

@@ -0,0 +1,20 @@
package com.wb.domainserver.analysis.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
@Data
@EqualsAndHashCode(callSuper = false)
public class TsAnalysisErpGoodsVO {
private String barcode;
private String sopmalCd;
private String goodsNm;
private BigDecimal goodsPrice;
}

View File

@@ -0,0 +1,25 @@
package com.wb.domainserver.analysis.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class TsAnalysisErpSetGoodsVO {
private String setCode;
private String barcode;
private Integer barcodeQy;
private String sopmalCd;
private String giftYn;
private String setGoodsNm;
private String goodsNm;
private String regNo;
}

View File

@@ -0,0 +1,49 @@
package com.wb.domainserver.analysis.vo;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = false)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TsAnalysisErpTotalStatisticsVO {
private String coCd;
private String strgrp1Cd;
private String strgrp2Cd;
private String strgrp3Cd;
private String strgrp4Cd;
private LocalDateTime saleDt;
private String brandNm;
private String itmNm;
private String barcode;
private BigDecimal salAmt;
private int qty;
private BigDecimal salAmt2;
private String itmId;
private LocalDateTime registDt;
private LocalDateTime updateDt;
private String cancType;
}

View File

@@ -0,0 +1,60 @@
package com.wb.domainserver.analysis.vo;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = false)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TsAnalysisOrderListVO {
private String ordrInnb;
private String productOrdrInnb;
private String sopmalCd;
private String ordrSttusCd;
private String barcode;
private int goodsQy;
private BigDecimal rlSetleAmt;
private BigDecimal totalPaymentAmount;
private Date paymentDt;
private Date decisionDate;
private String giftYn;
private String sopmalDv;
private String goodsNm;
private int shipNoSeq;
private String shopSetCd;
private BigDecimal baesongBi;
private String claimType;
private int barcodeQy;
private LocalDateTime lastChangedDate;
private String productOption;
private String claimStatus;
private String missingFlag;
}

View File

@@ -0,0 +1,92 @@
package com.wb.domainserver.app.jobs;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import com.wb.domainserver.app.tasklet.AppPushEvtDtTasklet;
import com.wb.domainserver.app.tasklet.AppPushEvtNcTasklet;
import com.wb.domainserver.app.tasklet.AppPushResveDtTasklet;
import com.wb.domainserver.app.tasklet.AppPushResveNcTasklet;
/**
*
* App Push 발송 배치
*
* @author 이훈영
* @since 2025-05-16
* @version 1.0
* @see
*
* 수정일 수정자 수정내용
* ------- -------- ---------------------------
* 2025-05-16 이훈영 최초 생성
*
* </pre>
*/
@Configuration
@EnableBatchProcessing
public class AppPushConfig {
@Autowired
private AppPushEvtNcTasklet appPushEvtNcTasklet;
@Autowired
private AppPushEvtDtTasklet appPushEvtDtTasklet;
@Autowired
private AppPushResveNcTasklet appPushResveNcTasklet;
@Autowired
private AppPushResveDtTasklet appPushResveDtTasklet;
@Bean
public Job appPushJob(JobRepository jobRepository, Step appPushEvtNcStep, Step appPushEvtDtStep, Step appPushResveNcStep, Step appPushResveDtStep) {
return new JobBuilder("appPushJob", jobRepository)
.start(appPushEvtNcStep)
.next(appPushResveNcStep)
.next(appPushEvtDtStep)
.next(appPushResveDtStep)
.incrementer(new RunIdIncrementer())
.build();
}
@Bean
public Step appPushEvtNcStep(JobRepository jobRepository, @Qualifier("gconeTransactionManager") PlatformTransactionManager transactionManager) {
return new StepBuilder("appPushEvtNcStep", jobRepository)
.tasklet(appPushEvtNcTasklet, transactionManager)
.build();
}
@Bean
public Step appPushEvtDtStep(JobRepository jobRepository, @Qualifier("gconeTransactionManager") PlatformTransactionManager transactionManager) {
return new StepBuilder("appPushEvtDtStep", jobRepository)
.tasklet(appPushEvtDtTasklet, transactionManager)
.build();
}
@Bean
public Step appPushResveNcStep(JobRepository jobRepository, @Qualifier("gconeTransactionManager") PlatformTransactionManager transactionManager) {
return new StepBuilder("appPushResveNcStep", jobRepository)
.tasklet(appPushResveNcTasklet, transactionManager)
.build();
}
@Bean
public Step appPushResveDtStep(JobRepository jobRepository, @Qualifier("gconeTransactionManager") PlatformTransactionManager transactionManager) {
return new StepBuilder("appPushResveDtStep", jobRepository)
.tasklet(appPushResveDtTasklet, transactionManager)
.build();
}
}

View File

@@ -0,0 +1,51 @@
package com.wb.domainserver.app.jobs;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.messaging.FirebaseMessaging;
import java.io.IOException;
@Configuration
public class FCMConfig {
@Bean(name = "NCFirebaseMessaging")
public FirebaseMessaging nutricoreFirebaseMessaging() throws IOException {
return createFirebaseMessaging(
"nutricoreeventapp-firebase-adminsdk-iliil-bd9d39ca9c.json",
"nutricore"
);
}
@Bean(name = "DTFirebaseMessaging")
public FirebaseMessaging doctorleanFirebaseMessaging() throws IOException {
return createFirebaseMessaging(
"doctorleaneventapp-firebase-adminsdk-ysdbz-3e5496cb84.json",
"doctorlean"
);
}
private FirebaseMessaging createFirebaseMessaging(String fileName, String appName) throws IOException {
ClassPathResource serviceAccount = new ClassPathResource("firebase/" + fileName);
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount.getInputStream()))
.build();
FirebaseApp firebaseApp;
if (FirebaseApp.getApps().stream().noneMatch(app -> app.getName().equals(appName))) {
// FirebaseApp이 존재하지 않으면 새로 초기화
firebaseApp = FirebaseApp.initializeApp(options, appName);
} else {
// 이미 초기화된 FirebaseApp 사용
firebaseApp = FirebaseApp.getInstance(appName);
}
return FirebaseMessaging.getInstance(firebaseApp);
}
}

View File

@@ -0,0 +1,179 @@
package com.wb.domainserver.app.tasklet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.FirebaseMessagingException;
import com.google.firebase.messaging.Message;
import com.google.firebase.messaging.Notification;
import com.wb.domainserver.app.vo.AppPushVO;
import com.wb.domainserver.mapper.gcone.AppPushMapper;
import com.wb.domainserver.service.AppPushSendService;
import com.wb.domainserver.util.dataaccess.DataMap;
@Component
public class AppPushEvtDtTasklet implements Tasklet {
private static final Logger logger = LoggerFactory.getLogger(AppPushEvtDtTasklet.class);
@Autowired
private AppPushMapper appPushMapper;
@Autowired
private AppPushSendService pushSendService;
@Qualifier("DTFirebaseMessaging")
@Autowired
private FirebaseMessaging dtFirebaseMessaging;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
logger.info("푸시 이벤트건 전송 : DT");
AppPushVO vo = new AppPushVO();
vo.setSopmalCd("DT");
// 푸시 콜백 데이터 설정
Map<String, String> dataMap = new HashMap<>();
dataMap.put("url", "/sopmal/bnft/bnftMain");
dataMap.put("key", "");
dataMap.put("ext", "");
ObjectMapper objectMapper = new ObjectMapper();
String jsonData = objectMapper.writeValueAsString(dataMap);
List<DataMap> trgetList = appPushMapper.selectBOBnftPushTrgetList(vo);
for (DataMap trgetItem : trgetList) {
String bnfDvCd = trgetItem.get("bnfDvCd").toString();
String sndngYn = trgetItem.get("sndngYn").toString();
// 섭취챌린지를 제외한.. 나머지 혜택은 해당일&발송완료 일때 스킵
if (!"100".equals(bnfDvCd) && "Y".equals(sndngYn)) {
logger.info("기발송 혜택 스킵됨 - bnfDvCd={}, bnfPushEvtSetupInnb={}", bnfDvCd, trgetItem.get("bnfPushEvtSetupInnb"));
continue;
}
// 1. 푸시 발송 이력 insert
AppPushVO histVO = new AppPushVO();
histVO.setSopmalCd(vo.getSopmalCd());
histVO.setBnfPushEvtSetupInnb(Long.valueOf(trgetItem.get("bnfPushEvtSetupInnb").toString()));
histVO.setSndngAt("N");
histVO.setSndngTrgetCnt(0);
appPushMapper.insertBOBnftPushSndngDtls(histVO);
Long sndngDtlsInnb = histVO.getBnfPushSndngDtlsInnb();
int succCnt = 0;
int failCnt = 0;
List<DataMap> mbrList = null;
if ("070".equals(bnfDvCd)) { // 라이브쇼핑
AppPushVO lvVO = new AppPushVO();
lvVO.setSopmalCd(vo.getSopmalCd());
DataMap lvData = appPushMapper.selectBOBnftPushLvshopInfo(lvVO);
if (lvData == null) continue;
if (lvData.get("bnfInnb") != null) {
histVO.setBnfInnb(Long.valueOf(lvData.get("bnfInnb").toString()));
}
AppPushVO mbrVO = new AppPushVO();
mbrVO.setSopmalCd(vo.getSopmalCd());
mbrVO.setBnfDvCd("070");
mbrList = appPushMapper.selectBOBnftPushMbrList(mbrVO);
} else if ("100".equals(bnfDvCd)) { // 섭취챌린지
mbrList = appPushMapper.selectBOBnftPushNtakchlMbrList(vo);
} else { // 출석, ox퀴즈등
AppPushVO mbrVO = new AppPushVO();
mbrVO.setSopmalCd(vo.getSopmalCd());
mbrVO.setBnfDvCd(bnfDvCd);
mbrList = appPushMapper.selectBOBnftPushMbrList(mbrVO);
}
if (mbrList == null || mbrList.isEmpty()) continue;
// 발송최적화를 위해 한번에 200건씩 발송 (추후 조절이 필요하더라도 500건 미만으로 설정할것)
int pushSize = 200;
int mbrTotal = mbrList.size();
for (int i = 0; i < mbrTotal; i += pushSize) {
int end = Math.min(i + pushSize, mbrTotal);
List<DataMap> batchList = mbrList.subList(i, end);
logger.info("푸시 배치 처리: {} ~ {} (총 {}건 중)", i + 1, end, mbrTotal);
for (DataMap mbrItem : batchList) {
String fcmToken = Optional.ofNullable(mbrItem.get("fcmToken")).map(Object::toString).orElse("");
String pushSj = Optional.ofNullable(trgetItem.get("pushSj")).map(Object::toString).orElse("");
String pushCn = Optional.ofNullable(trgetItem.get("pushCn")).map(Object::toString).orElse("");
DataMap resultMap = pushSendService.sendPush(
dtFirebaseMessaging,
fcmToken,
pushSj,
pushCn,
"notice",
jsonData,
""
);
String resultCode = resultMap.get("resultCode").toString();
String resultStts = resultMap.get("resultStts").toString();
// 섭취챌린지의 경우 마지막 푸시발송일시를 업데이트한다
if ("100".equals(bnfDvCd)) {
AppPushVO ntakVO = new AppPushVO();
ntakVO.setBnfNtkNtcnInnb(Long.valueOf(mbrItem.get("bnfNtkNtcnInnb").toString()));
appPushMapper.updateBOBnftPushNtakchlSendDt(ntakVO);
}
if ("200".equals(resultCode)) {
succCnt++;
} else {
failCnt++;
AppPushVO errVO = new AppPushVO();
errVO.setBnfPushSndngDtlsInnb(sndngDtlsInnb);
errVO.setErrorCode(resultStts);
errVO.setFcmToken(fcmToken);
errVO.setPushSj(pushSj);
errVO.setPushCn(pushCn);
errVO.setPushData(jsonData);
errVO.setImgFilCours("");
appPushMapper.insertBOBnftPushSndngErrlog(errVO);
}
}
// 발송최적화를 위한 딜레이
Thread.sleep(100);
}
// 3. 이력 업데이트
AppPushVO updVO = new AppPushVO();
updVO.setBnfPushSndngDtlsInnb(sndngDtlsInnb);
updVO.setBnfInnb(histVO.getBnfInnb());
updVO.setSndngAt("Y");
updVO.setSndngTrgetCnt(mbrList.size());
updVO.setSndngSuccesCnt(succCnt);
updVO.setSndngFailrCnt(failCnt);
appPushMapper.updateBOBnftPushSndngDtls(updVO);
}
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,176 @@
package com.wb.domainserver.app.tasklet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.firebase.messaging.FirebaseMessaging;
import com.wb.domainserver.app.vo.AppPushVO;
import com.wb.domainserver.mapper.gcone.AppPushMapper;
import com.wb.domainserver.service.AppPushSendService;
import com.wb.domainserver.util.dataaccess.DataMap;
@Component
public class AppPushEvtNcTasklet implements Tasklet {
private static final Logger logger = LoggerFactory.getLogger(AppPushEvtNcTasklet.class);
@Autowired
private AppPushMapper appPushMapper;
@Autowired
private AppPushSendService pushSendService;
@Qualifier("NCFirebaseMessaging")
@Autowired
private FirebaseMessaging ncFirebaseMessaging;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
logger.info("푸시 이벤트건 전송 : NC");
AppPushVO vo = new AppPushVO();
vo.setSopmalCd("NC");
// 푸시 콜백 데이터 설정
Map<String, String> dataMap = new HashMap<>();
dataMap.put("url", "/sopmal/bnft/bnftMain");
dataMap.put("key", "");
dataMap.put("ext", "");
ObjectMapper objectMapper = new ObjectMapper();
String jsonData = objectMapper.writeValueAsString(dataMap);
List<DataMap> trgetList = appPushMapper.selectBOBnftPushTrgetList(vo);
for (DataMap trgetItem : trgetList) {
String bnfDvCd = trgetItem.get("bnfDvCd").toString();
String sndngYn = trgetItem.get("sndngYn").toString();
// 섭취챌린지를 제외한.. 나머지 혜택은 해당일&발송완료 일때 스킵
if (!"100".equals(bnfDvCd) && "Y".equals(sndngYn)) {
logger.info("기발송 혜택 스킵됨 - bnfDvCd={}, bnfPushEvtSetupInnb={}", bnfDvCd, trgetItem.get("bnfPushEvtSetupInnb"));
continue;
}
// 1. 푸시 발송 이력 insert
AppPushVO histVO = new AppPushVO();
histVO.setSopmalCd(vo.getSopmalCd());
histVO.setBnfPushEvtSetupInnb(Long.valueOf(trgetItem.get("bnfPushEvtSetupInnb").toString()));
histVO.setSndngAt("N");
histVO.setSndngTrgetCnt(0);
appPushMapper.insertBOBnftPushSndngDtls(histVO);
Long sndngDtlsInnb = histVO.getBnfPushSndngDtlsInnb();
int succCnt = 0;
int failCnt = 0;
List<DataMap> mbrList = null;
if ("070".equals(bnfDvCd)) { // 라이브쇼핑
AppPushVO lvVO = new AppPushVO();
lvVO.setSopmalCd(vo.getSopmalCd());
DataMap lvData = appPushMapper.selectBOBnftPushLvshopInfo(lvVO);
if (lvData == null) continue;
if (lvData.get("bnfInnb") != null) {
histVO.setBnfInnb(Long.valueOf(lvData.get("bnfInnb").toString()));
}
AppPushVO mbrVO = new AppPushVO();
mbrVO.setSopmalCd(vo.getSopmalCd());
mbrVO.setBnfDvCd("070");
mbrList = appPushMapper.selectBOBnftPushMbrList(mbrVO);
} else if ("100".equals(bnfDvCd)) { // 섭취챌린지
mbrList = appPushMapper.selectBOBnftPushNtakchlMbrList(vo);
} else { // 출석, ox퀴즈등
AppPushVO mbrVO = new AppPushVO();
mbrVO.setSopmalCd(vo.getSopmalCd());
mbrVO.setBnfDvCd(bnfDvCd);
mbrList = appPushMapper.selectBOBnftPushMbrList(mbrVO);
}
if (mbrList == null || mbrList.isEmpty()) continue;
// 발송최적화를 위해 한번에 200건씩 발송 (추후 조절이 필요하더라도 500건 미만으로 설정할것)
int pushSize = 200;
int mbrTotal = mbrList.size();
for (int i = 0; i < mbrTotal; i += pushSize) {
int end = Math.min(i + pushSize, mbrTotal);
List<DataMap> batchList = mbrList.subList(i, end);
logger.info("푸시 배치 처리: {} ~ {} (총 {}건 중)", i + 1, end, mbrTotal);
for (DataMap mbrItem : batchList) {
String fcmToken = Optional.ofNullable(mbrItem.get("fcmToken")).map(Object::toString).orElse("");
String pushSj = Optional.ofNullable(trgetItem.get("pushSj")).map(Object::toString).orElse("");
String pushCn = Optional.ofNullable(trgetItem.get("pushCn")).map(Object::toString).orElse("");
DataMap resultMap = pushSendService.sendPush(
ncFirebaseMessaging,
fcmToken,
pushSj,
pushCn,
"notice",
jsonData,
""
);
String resultCode = resultMap.get("resultCode").toString();
String resultStts = resultMap.get("resultStts").toString();
// 섭취챌린지의 경우 마지막 푸시발송일시를 업데이트한다
if ("100".equals(bnfDvCd)) {
AppPushVO ntakVO = new AppPushVO();
ntakVO.setBnfNtkNtcnInnb(Long.valueOf(mbrItem.get("bnfNtkNtcnInnb").toString()));
appPushMapper.updateBOBnftPushNtakchlSendDt(ntakVO);
}
if ("200".equals(resultCode)) {
succCnt++;
} else {
failCnt++;
AppPushVO errVO = new AppPushVO();
errVO.setBnfPushSndngDtlsInnb(sndngDtlsInnb);
errVO.setErrorCode(resultStts);
errVO.setFcmToken(fcmToken);
errVO.setPushSj(pushSj);
errVO.setPushCn(pushCn);
errVO.setPushData(jsonData);
errVO.setImgFilCours("");
appPushMapper.insertBOBnftPushSndngErrlog(errVO);
}
}
// 발송최적화를 위한 딜레이
Thread.sleep(100);
}
// 3. 이력 업데이트
AppPushVO updVO = new AppPushVO();
updVO.setBnfPushSndngDtlsInnb(sndngDtlsInnb);
updVO.setBnfInnb(histVO.getBnfInnb());
updVO.setSndngAt("Y");
updVO.setSndngTrgetCnt(mbrList.size());
updVO.setSndngSuccesCnt(succCnt);
updVO.setSndngFailrCnt(failCnt);
appPushMapper.updateBOBnftPushSndngDtls(updVO);
}
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,143 @@
package com.wb.domainserver.app.tasklet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.firebase.messaging.FirebaseMessaging;
import com.wb.domainserver.app.vo.AppPushVO;
import com.wb.domainserver.mapper.gcone.AppPushMapper;
import com.wb.domainserver.service.AppPushSendService;
import com.wb.domainserver.util.dataaccess.DataMap;
@Component
public class AppPushResveDtTasklet implements Tasklet {
private static final Logger logger = LoggerFactory.getLogger(AppPushResveNcTasklet.class);
@Autowired
private AppPushMapper appPushMapper;
@Autowired
private AppPushSendService pushSendService;
@Qualifier("DTFirebaseMessaging")
@Autowired
private FirebaseMessaging dtFirebaseMessaging;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
logger.info("푸시 예약건 전송 : DT");
AppPushVO vo = new AppPushVO();
vo.setSopmalCd("DT");
List<DataMap> resveList = appPushMapper.selectBOBnftPushResveList(vo);
ObjectMapper objectMapper = new ObjectMapper();
for (DataMap resveItem : resveList) {
String bnfDvCd = resveItem.get("bnfPushTrgetDvCd").toString();
// 푸시 콜백 데이터 설정
Map<String, String> dataMap = new HashMap<>();
dataMap.put("url", Optional.ofNullable(resveItem.get("dataUrl")).map(Object::toString).orElse(""));
dataMap.put("key", Optional.ofNullable(resveItem.get("dataKey")).map(Object::toString).orElse(""));
dataMap.put("ext", Optional.ofNullable(resveItem.get("dataExt")).map(Object::toString).orElse(""));
String jsonData = objectMapper.writeValueAsString(dataMap);
// 1. 푸시 발송 이력 insert
AppPushVO histVO = new AppPushVO();
histVO.setSopmalCd(vo.getSopmalCd());
histVO.setBnfPushInfoInnb(Long.valueOf(resveItem.get("bnfPushInfoInnb").toString()));
histVO.setSndngAt("N");
histVO.setSndngTrgetCnt(0);
appPushMapper.insertBOBnftPushSndngDtls(histVO);
Long sndngDtlsInnb = histVO.getBnfPushSndngDtlsInnb();
int succCnt = 0;
int failCnt = 0;
List<DataMap> mbrList = null;
AppPushVO mbrVO = new AppPushVO();
mbrVO.setSopmalCd(vo.getSopmalCd());
mbrVO.setBnfDvCd(bnfDvCd);
mbrList = appPushMapper.selectBOBnftPushMbrList(mbrVO);
if (mbrList == null || mbrList.isEmpty()) continue;
// 발송최적화를 위해 한번에 200건씩 발송 (추후 조절이 필요하더라도 500건 미만으로 설정할것)
int pushSize = 200;
int mbrTotal = mbrList.size();
for (int i = 0; i < mbrTotal; i += pushSize) {
int end = Math.min(i + pushSize, mbrTotal);
List<DataMap> batchList = mbrList.subList(i, end);
logger.info("푸시 배치 처리: {} ~ {} (총 {}건 중)", i + 1, end, mbrTotal);
for (DataMap mbrItem : batchList) {
String fcmToken = Optional.ofNullable(mbrItem.get("fcmToken")).map(Object::toString).orElse("");
String pushSj = Optional.ofNullable(resveItem.get("pushSj")).map(Object::toString).orElse("");
String pushCn = Optional.ofNullable(resveItem.get("pushCn")).map(Object::toString).orElse("");
String imgFilCours = Optional.ofNullable(resveItem.get("imgFilCours")).map(Object::toString).orElse("");
DataMap resultMap = pushSendService.sendPush(
dtFirebaseMessaging,
fcmToken,
pushSj,
pushCn,
"notice",
jsonData,
imgFilCours
);
String resultCode = resultMap.get("resultCode").toString();
String resultStts = resultMap.get("resultStts").toString();
if ("200".equals(resultCode)) {
succCnt++;
} else {
failCnt++;
AppPushVO errVO = new AppPushVO();
errVO.setBnfPushSndngDtlsInnb(sndngDtlsInnb);
errVO.setErrorCode(resultStts);
errVO.setFcmToken(fcmToken);
errVO.setPushSj(pushSj);
errVO.setPushCn(pushCn);
errVO.setPushData(jsonData);
errVO.setImgFilCours(imgFilCours);
appPushMapper.insertBOBnftPushSndngErrlog(errVO);
}
}
// 발송최적화를 위한 딜레이
Thread.sleep(100);
}
// 3. 이력 업데이트
AppPushVO updVO = new AppPushVO();
updVO.setBnfPushSndngDtlsInnb(sndngDtlsInnb);
updVO.setBnfInnb(histVO.getBnfInnb());
updVO.setSndngAt("Y");
updVO.setSndngTrgetCnt(mbrList.size());
updVO.setSndngSuccesCnt(succCnt);
updVO.setSndngFailrCnt(failCnt);
appPushMapper.updateBOBnftPushSndngDtls(updVO);
}
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,143 @@
package com.wb.domainserver.app.tasklet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.firebase.messaging.FirebaseMessaging;
import com.wb.domainserver.app.vo.AppPushVO;
import com.wb.domainserver.mapper.gcone.AppPushMapper;
import com.wb.domainserver.service.AppPushSendService;
import com.wb.domainserver.util.dataaccess.DataMap;
@Component
public class AppPushResveNcTasklet implements Tasklet {
private static final Logger logger = LoggerFactory.getLogger(AppPushResveNcTasklet.class);
@Autowired
private AppPushMapper appPushMapper;
@Autowired
private AppPushSendService pushSendService;
@Qualifier("NCFirebaseMessaging")
@Autowired
private FirebaseMessaging ncFirebaseMessaging;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
logger.info("푸시 예약건 전송 : NC");
AppPushVO vo = new AppPushVO();
vo.setSopmalCd("NC");
List<DataMap> resveList = appPushMapper.selectBOBnftPushResveList(vo);
ObjectMapper objectMapper = new ObjectMapper();
for (DataMap resveItem : resveList) {
String bnfDvCd = resveItem.get("bnfPushTrgetDvCd").toString();
// 푸시 콜백 데이터 설정
Map<String, String> dataMap = new HashMap<>();
dataMap.put("url", Optional.ofNullable(resveItem.get("dataUrl")).map(Object::toString).orElse(""));
dataMap.put("key", Optional.ofNullable(resveItem.get("dataKey")).map(Object::toString).orElse(""));
dataMap.put("ext", Optional.ofNullable(resveItem.get("dataExt")).map(Object::toString).orElse(""));
String jsonData = objectMapper.writeValueAsString(dataMap);
// 1. 푸시 발송 이력 insert
AppPushVO histVO = new AppPushVO();
histVO.setSopmalCd(vo.getSopmalCd());
histVO.setBnfPushInfoInnb(Long.valueOf(resveItem.get("bnfPushInfoInnb").toString()));
histVO.setSndngAt("N");
histVO.setSndngTrgetCnt(0);
appPushMapper.insertBOBnftPushSndngDtls(histVO);
Long sndngDtlsInnb = histVO.getBnfPushSndngDtlsInnb();
int succCnt = 0;
int failCnt = 0;
List<DataMap> mbrList = null;
AppPushVO mbrVO = new AppPushVO();
mbrVO.setSopmalCd(vo.getSopmalCd());
mbrVO.setBnfDvCd(bnfDvCd);
mbrList = appPushMapper.selectBOBnftPushMbrList(mbrVO);
if (mbrList == null || mbrList.isEmpty()) continue;
// 발송최적화를 위해 한번에 200건씩 발송 (추후 조절이 필요하더라도 500건 미만으로 설정할것)
int pushSize = 200;
int mbrTotal = mbrList.size();
for (int i = 0; i < mbrTotal; i += pushSize) {
int end = Math.min(i + pushSize, mbrTotal);
List<DataMap> batchList = mbrList.subList(i, end);
logger.info("푸시 배치 처리: {} ~ {} (총 {}건 중)", i + 1, end, mbrTotal);
for (DataMap mbrItem : batchList) {
String fcmToken = Optional.ofNullable(mbrItem.get("fcmToken")).map(Object::toString).orElse("");
String pushSj = Optional.ofNullable(resveItem.get("pushSj")).map(Object::toString).orElse("");
String pushCn = Optional.ofNullable(resveItem.get("pushCn")).map(Object::toString).orElse("");
String imgFilCours = Optional.ofNullable(resveItem.get("imgFilCours")).map(Object::toString).orElse("");
DataMap resultMap = pushSendService.sendPush(
ncFirebaseMessaging,
fcmToken,
pushSj,
pushCn,
"notice",
jsonData,
imgFilCours
);
String resultCode = resultMap.get("resultCode").toString();
String resultStts = resultMap.get("resultStts").toString();
if ("200".equals(resultCode)) {
succCnt++;
} else {
failCnt++;
AppPushVO errVO = new AppPushVO();
errVO.setBnfPushSndngDtlsInnb(sndngDtlsInnb);
errVO.setErrorCode(resultStts);
errVO.setFcmToken(fcmToken);
errVO.setPushSj(pushSj);
errVO.setPushCn(pushCn);
errVO.setPushData(jsonData);
errVO.setImgFilCours(imgFilCours);
appPushMapper.insertBOBnftPushSndngErrlog(errVO);
}
}
// 발송최적화를 위한 딜레이
Thread.sleep(100);
}
// 3. 이력 업데이트
AppPushVO updVO = new AppPushVO();
updVO.setBnfPushSndngDtlsInnb(sndngDtlsInnb);
updVO.setBnfInnb(histVO.getBnfInnb());
updVO.setSndngAt("Y");
updVO.setSndngTrgetCnt(mbrList.size());
updVO.setSndngSuccesCnt(succCnt);
updVO.setSndngFailrCnt(failCnt);
appPushMapper.updateBOBnftPushSndngDtls(updVO);
}
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,156 @@
package com.wb.domainserver.app.vo;
import java.util.HashMap;
import java.util.List;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class AppPushVO {
/** 쇼핑몰코드 */
private String sopmalCd;
// 알림 내용 항목
/** 혜택 알림 정보 고유번호 */
private Long bnfPushInfoInnb;
/** 알림 대상 구분 코드 */
private String bnfPushTrgetDvCd;
/** 알림 대상 구분 명 */
private String bnfPushTrgetDvNm;
/** 알림 대상 구분 */
private String trgetDv;
/** 알림 대상 전체수 */
private Integer trgetAllCnt;
/** 알림 제목 */
private String pushSj;
/** 알림 내용 */
private String pushCn;
/** 알림 내용 - 개행처리 */
private String pushCnRpl;
/** 알림 발송 일시 */
private String pushSendDt;
/** 알림 발송 일자 */
private String pushSendDe;
/** 알림 발송 시간 */
private String pushSendTme;
/** 이미지파일경로 */
private String imgFilCours;
/** 이미지파일명 */
private String imgFilNm;
/** 예약 여부 */
private String resveAt;
/** 예약 상태 */
private String resveSttus;
/** 삭제 여부 */
private String delAt;
/** 알림 유형 */
private String pushType;
/** callback 데이터 */
private String pushData;
/** callback 데이터 - url */
private String dataUrl;
/** callback 데이터 - key */
private String dataKey;
/** callback 데이터 - ext */
private String dataExt;
// 알림 발송 항목
/** 혜택 알림 발송내역 고유번호 */
private Long bnfPushSndngDtlsInnb;
/** 혜택 알림 이벤트별 설정 고유번호 */
private Long bnfPushEvtSetupInnb;
/** 혜택 섭취챌린지 알림 고유번호 */
private Long bnfNtkNtcnInnb;
/** 발송 여부 */
private String sndngAt;
/** 발송 상태 */
private String sndngSttus;
/** 발송 대상수 */
private Integer sndngTrgetCnt;
/** 발송 성공수 */
private Integer sndngSuccesCnt;
/** 발송 실패수 */
private Integer sndngFailrCnt;
/** 에러코드 */
private String errorCode;
// 알림 설정
/** 테스트 대상 회원ID 문자열 */
private String trgetMbrIds;
/** 발송제한 시작 시간1 */
private String lmttBgnTme1;
/** 발송제한 종료 시간1 */
private String lmttEndTme1;
/** 발송제한 시작 시간2 */
private String lmttBgnTme2;
/** 발송제한 종료 시간2 */
private String lmttEndTme2;
// 대상 회원 항목
/** 회원 디바이스 고유번호 */
private Long mbrDeviceInnb;
/** 회원 디바이스 고유번호 배열 */
private Long[] arrMbrDeviceInnb;
/** 회원고유번호 */
private Long mbrInnb;
/** 회원구분코드 */
private String mbrDvCd;
/** 회원ID */
private String mbrId;
/** 회원명 */
private String mbrNm;
/** FCM 토큰 */
private String fcmToken;
/** FCM 토큰 배열 */
private String[] arrFcmToken;
/** 알림 동의 여부 */
private String pushAgreAt;
/** 디바이스 고유ID */
private String deviceId;
/** 운영체제 이름 */
private String deviceOsNm;
/** 운영체제 버전 */
private String deviceOsVer;
/** 앱 버전 */
private String deviceAppVer;
// 혜택별 동의 항목
/** 혜택 동의 고유번호 */
private Long bnfAgreInnb;
/** 혜택 구분코드 */
private String bnfDvCd;
/** 혜택 동의 구분코드 */
private String bnfAgreDvCd;
/** 혜택 설정 고유번호 */
private Long bnfInnb;
/** 동의여부 */
private String agreAt;
/** 이미지 파일 업로드 */
private List<HashMap<String, Object>> fileInfo;
/** CDN URL */
private String imgCdnurl;
// 검색 조건
/** 검색구분 */
private String srchDv;
/** 검색_검색어 */
private String srchKeyword;
/** 검색_날짜_구분 */
private String srchPdDv;
/** 검색_상태_구분 */
private String srchSttDv;
/** 검색_사용여부_구분 */
private String srchUseAt;
/** 검색_시작일 */
private String srchStartDt;
/** 검색_종료일 */
private String srchEndDt;
}

View File

@@ -0,0 +1,175 @@
package com.wb.domainserver.atmcrcpmny.jobs;
import com.wb.domainserver.atmcrcpmny.tasklet.*;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Configuration
@EnableBatchProcessing
public class AtmcrcpmnyConfig extends DefaultBatchConfiguration{
private static final Logger logger = LoggerFactory.getLogger(AtmcrcpmnyConfig.class);
private final SqlSessionFactory sqlSessionFactory;
private final InsertTsRcpmnyDtlsColctTasklet insertTsRcpmnyDtlsColctTasklet;
private final UpdateTsRcpmnyCnfirmAtmcMtchgTasklet updateTsRcpmnyCnfirmAtmcMtchgTasklet;
private final UpdateTsCshRciptRegistTasklet updateTsCshRciptRegistTasklet;
private final SelectTsOrderCancelTasklet selectTsOrderCancelTasklet;
private final UpdateClearPersonalInfoShopTasklet updateClearPersonalInfoShopTasklet;
/**
* 뱅크다 api 호출 후 입금내역 테이블에 insert, update
* 배치 30분에 한번 실행
*/
@Bean
public Job autodepositCronJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new JobBuilder("autodepositCronJob", jobRepository)
.start(insertRcpmnyDtlsColct(jobRepository, transactionManager))
.incrementer(new RunIdIncrementer())
.build();
}
/**
* 뱅크다 api 호출 후 입금내역 테이블에 insert, update
*/
@Bean
public Step insertRcpmnyDtlsColct(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("insertRcpmnyDtlsColct", jobRepository)
.tasklet(insertTsRcpmnyDtlsColctTasklet, transactionManager)
.build();
}
/** ------------------------------------------------------------------------------------------------------------------ */
/**
* 입금내역(주문접수+무통장)에 대하여 자동 매칭
* 입금내역(주문접수+무통장) 조회 후
* 주문 테이블, 입금내역 테이블 update
* 배치 30분에 한번 실행
*/
@Bean
public Job rcpmnyCnfirmAtmcMtchgJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new JobBuilder("rcpmnyCnfirmAtmcMtchgJob", jobRepository)
.start(updateRcpmnyCnfirmAtmcMtchg(jobRepository, transactionManager))
.incrementer(new RunIdIncrementer())
.build();
}
/**
* 입금내역(주문접수+무통장)에 대하여 자동 매칭
* 입금내역(주문접수+무통장) 조회 후
* 주문 테이블, 입금내역 테이블 update
*/
@Bean
public Step updateRcpmnyCnfirmAtmcMtchg(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("updateRcpmnyCnfirmAtmcMtchg", jobRepository)
.tasklet(updateTsRcpmnyCnfirmAtmcMtchgTasklet, transactionManager)
.build();
}
/** ------------------------------------------------------------------------------------------------------------------ */
/**
* 현금영수증 신청할 데이터 조회 후 현금영수증 신청.
* 매출증빙 테이블 update, 매출증빙로그 테이블 insert
* 배치 시간 미정
*/
@Bean
public Job cshRciptRegistJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new JobBuilder("cshRciptRegistJob", jobRepository)
.start(updateCshRciptRegist(jobRepository, transactionManager))
.incrementer(new RunIdIncrementer())
.build();
}
/**
* 현금영수증 신청할 데이터 조회 후 현금영수증 신청.
* 매출증빙 테이블 update, 매출증빙로그 테이블 insert
*/
@Bean
public Step updateCshRciptRegist(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("updateCshRciptRegist", jobRepository)
.tasklet(updateTsCshRciptRegistTasklet, transactionManager)
.build();
}
/** ------------------------------------------------------------------------------------------------------------------ */
/** ------------------------------------------------------------------------------------------------------------------ */
/**
* 자동주문무효
* step=15, 접수일 7일전, Npay가 아닌거
* 새벽 1시 배치
*/
@Bean
public Job orderCancelJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new JobBuilder("orderCancelJob", jobRepository)
.start(selectOrderCancel(jobRepository, transactionManager))
.incrementer(new RunIdIncrementer())
.build();
}
/**
* 자동주문무효
* step=15, 접수일 7일전, Npay가 아닌거
*
*/
@Bean
public Step selectOrderCancel(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("selectOrderCancel", jobRepository)
.tasklet(selectTsOrderCancelTasklet, transactionManager)
.build();
}
/** ------------------------------------------------------------------------------------------------------------------ */
/**
* 자사몰/독립몰 개인정보 마스킹 처리
* (1년 경과 후 문자/메일 로그, 주문관련)
* 배치 시간 :
*/
@Bean
public Job clearPersonalInfoShopJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new JobBuilder("clearPersonalInfoShopJob", jobRepository)
.start(updateClearPersonalInfoShop(jobRepository, transactionManager))
.incrementer(new RunIdIncrementer())
.build();
}
/**
*
*/
@Bean
public Step updateClearPersonalInfoShop(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("updateClearPersonalInfoShop", jobRepository)
.tasklet(updateClearPersonalInfoShopTasklet, transactionManager)
.build();
}
/** ------------------------------------------------------------------------------------------------------------------ */
}

View File

@@ -0,0 +1,308 @@
package com.wb.domainserver.atmcrcpmny.tasklet;
import com.wb.domainserver.mapper.gcone.MssageMapper;
import com.wb.domainserver.ntcn.vo.TsEmailVO;
import com.wb.domainserver.ntcn.vo.TsMssageVO;
import com.wb.domainserver.util.dataaccess.DataMap;
import com.wb.domainserver.util.ntcn.DataShareBean;
import com.wb.domainserver.util.string.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
@Slf4j
@RequiredArgsConstructor
public class InsertTsDepositTrgtListTasklet implements Tasklet {
private static final Logger logger = LoggerFactory.getLogger(InsertTsDepositTrgtListTasklet.class);
@Autowired
private MssageMapper mapper;
private final DataShareBean dataShareBean;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
Map<String, Object> message = dataShareBean.getData("message");
//조회 양식 코드 세팅
DataMap paramMap = new DataMap();
paramMap.put("formDtlDvCd", StringUtil.isNullToString(message.get("formDtlDvCd")));
paramMap.put("formDvCd", StringUtil.isNullToString(message.get("formDvCd")));
List<DataMap> atmcsndngMngtEmailList = (List<DataMap>) message.get("atmcsndngMngtEmailList");
List<DataMap> atmcsndngMngtSmsList = (List<DataMap>) message.get("atmcsndngMngtSmsList");
List<DataMap> atmcsndngMngtNtcnTalkList = (List<DataMap>) message.get("atmcsndngMngtNtcnTalkList");
List<DataMap> mbrGradTrgtList = mapper.selectCouponEndTrgtList(paramMap);
log.debug("mbrGradTrgtList {}", mbrGradTrgtList);
//이메일
if (atmcsndngMngtEmailList != null || !atmcsndngMngtEmailList.isEmpty()) {
//이메일 가능 브랜드
List<String> emailSopmalCd = atmcsndngMngtSmsList.stream()
.map(map -> StringUtil.isNullToString(map.get("sopmalCd")))
.toList();
//쇼핑몰로 필터링
List<DataMap> selectMbrGardEmailTrgtList = mbrGradTrgtList.stream()
.filter(map ->
emailSopmalCd.contains(StringUtil.isNullToString(map.get("mainSopmalCd"))))
.toList();
log.debug("selectMbrGardEmailTrgtList {}", selectMbrGardEmailTrgtList);
Map<String, List<TsEmailVO>> makeGroupedEmailData = makeGroupedEmailData(selectMbrGardEmailTrgtList);
List<BigInteger> emailSndngInnbList = processGroupedEmailData(makeGroupedEmailData);
message.put("emailSndngInnbList", emailSndngInnbList);
}
//sms
if (!atmcsndngMngtSmsList.isEmpty()) {
String dv = "";
//sms 가능 브랜드
List<String> smsSopmalCd = atmcsndngMngtSmsList.stream()
.map(map -> StringUtil.isNullToString(map.get("sopmalCd")))
.toList();
//쇼핑몰로 필터링
List<DataMap> selectMbrGradSmsTrgtList = mbrGradTrgtList.stream()
.filter(map ->
smsSopmalCd.contains(StringUtil.isNullToString(map.get("mainSopmalCd"))))
.toList();
log.debug("selectMbrGradSmsTrgtList {}", selectMbrGradSmsTrgtList);
//양식 조회
Map<String, List<TsMssageVO>> makeGroupedSmsData
= makeGroupedMssageData(selectMbrGradSmsTrgtList, dv);
log.debug("makeGroupedSmsData {}", makeGroupedSmsData);
List<BigInteger> smsInnbList = processGroupedMssageData(makeGroupedSmsData);
message.put("smsInnbList", smsInnbList);
}
//알림톡
if (!atmcsndngMngtNtcnTalkList.isEmpty()) {
String dv = "AT";
//sms 가능 브랜드
List<String> ntcnSopmalCd = atmcsndngMngtNtcnTalkList.stream()
.map(map -> StringUtil.isNullToString(map.get("sopmalCd")))
.toList();
//쇼핑몰로 필터링
List<DataMap> selectMbrGradNtcnTalkTrgtList = mbrGradTrgtList.stream()
.filter(map ->
ntcnSopmalCd.contains(StringUtil.isNullToString(map.get("mainSopmalCd"))))
.toList();
log.debug("selectMarktAgreNtcnTalkTrgtList {}", selectMbrGradNtcnTalkTrgtList);
//양식 조회
Map<String, List<TsMssageVO>> makeGroupeNtcnTalkData
= makeGroupedMssageData(selectMbrGradNtcnTalkTrgtList, dv);
List<BigInteger> smsInnbNtcnList = processGroupedMssageData(makeGroupeNtcnTalkData);
message.put("smsInnbNtcnList", smsInnbNtcnList);
}
return RepeatStatus.FINISHED;
}
/**
* 발송 대상 그룹 처리
* 발송 대상 목록을 쇼핑몰 별로 그룹화하여 새로운 리스트로 분리 생성
*
* @param groupedData
*/
public Map<String, List<TsMssageVO>> makeGroupedMssageData(List<DataMap> selectedList, String dv) {
return selectedList.stream()
.map(map -> {
TsMssageVO tsMssageVO = new TsMssageVO();
tsMssageVO.setSopmalCd(StringUtil.isNullToString(map.get("mainSopmalCd")));
tsMssageVO.setRegusrDv("03");//시스템
tsMssageVO.setStrInnb(BigInteger.ZERO);
tsMssageVO.setStrNm("");
tsMssageVO.setStrDv("99");
tsMssageVO.setChrSttus("REG");
tsMssageVO.setHead("");
String cn = StringUtil.isNullToString("AT".equals(dv) ? map.get("msg") : map.get("smsCn"));
tsMssageVO.setCn(fixStr(cn));
tsMssageVO.setTail("");
//dv가 AT면 AT설정, 아니면 길이 계산 dv (sms, lms)
tsMssageVO.setDv("AT".equals(dv) ? dv : msgType(cn));
tsMssageVO.setSmsNm("surem");
tsMssageVO.setSndngNb(StringUtil.isNullToString(map.get("sndngNb")));
//FM_SMS_TO 등록 정보
tsMssageVO.setRecptnNb(StringUtil.isNullToString(map.get("mbtlnb")));
String mbrInnbStr = StringUtil.isNullToString(map.get("mbrInnb"));
log.debug("map {}", map);
tsMssageVO.setCstmrIdnb(new BigInteger(mbrInnbStr));
tsMssageVO.setCstmrNm(StringUtil.isNullToString(map.get("mbrNm")));
tsMssageVO.setSubstWrd1("0");
tsMssageVO.setSubstWrd2("0");
tsMssageVO.setSubstWrd3("0");
tsMssageVO.setSubstWrd4("0");
tsMssageVO.setSubstWrd5("0");
return tsMssageVO;
})
.collect(Collectors.groupingBy(TsMssageVO::getSopmalCd));
}
/**
* 쇼핑몰별 그룹화된 데이터 메시지 처리
*
* @param map
* @return
*/
public List<BigInteger> processGroupedMssageData(Map<String, List<TsMssageVO>> groupedData) {
//그룹 처리 목록 FM_SMS 입력, FM_SMS에는 쇼핑몰코드별 입력
List<BigInteger> smsInnbList = new ArrayList<>();
for (Map.Entry<String, List<TsMssageVO>> entry : groupedData.entrySet()) {
if (!entry.getValue().isEmpty()) {
List<TsMssageVO> list = entry.getValue();
TsMssageVO tsMsgVO = list.get(0);
//FM_SMS 등록
mapper.insertMssageRegist(tsMsgVO);
smsInnbList.add(tsMsgVO.getSmsInnb());
//SMS_INNB 입력
list.forEach(tsMssageToVO ->
tsMssageToVO.setSmsInnb(tsMsgVO.getSmsInnb())
);
mapper.insertMssageToListRegist(list);
}
}
//대상수 설정 -> cnt 항목 수정
log.debug("smsInnbList {}", smsInnbList);
mapper.updateMssageCntUpdt(smsInnbList);
return smsInnbList;
}
/**
* 발송 대상 그룹 처리 - 이메일
* 발송 대상 목록을 쇼핑몰 별로 그룹화하여 새로운 리스트로 분리 생성
*
* @param groupedData
*/
public Map<String, List<TsEmailVO>> makeGroupedEmailData(List<DataMap> selectedList) {
return selectedList.stream()
.map(map -> {
TsEmailVO tsEmailVo = new TsEmailVO();
tsEmailVo.setSopmalCd(StringUtil.isNullToString(map.get("mainSopmalCd")));
tsEmailVo.setSndngLc("");
tsEmailVo.setRegusrDv("03");//시스템
tsEmailVo.setSj(StringUtil.isNullToString(map.get("emailSj")));
tsEmailVo.setCn(StringUtil.isNullToString(map.get("emailCn")));
tsEmailVo.setSndrEmail(StringUtil.isNullToString(map.get("email")));
return tsEmailVo;
})
.collect(Collectors.groupingBy(TsEmailVO::getSopmalCd));
}
/**
* 쇼핑몰별 그룹화된 데이터 메시지 처리
*
* @param map
* @return
*/
public List<BigInteger> processGroupedEmailData(Map<String, List<TsEmailVO>> groupedData) {
//그룹 처리 목록 FM_SMS 입력, FM_SMS에는 쇼핑몰코드별 입력
List<BigInteger> emailSndngInnbList = new ArrayList<>();
for (Map.Entry<String, List<TsEmailVO>> entry : groupedData.entrySet()) {
if (!entry.getValue().isEmpty()) {
List<TsEmailVO> list = entry.getValue();
TsEmailVO tsEmailVO = list.get(0);
mapper.insertBOEmailSndngDtls(tsEmailVO);
emailSndngInnbList.add(tsEmailVO.getEmailSndngInnb());
//SMS_INNB 입력
list.forEach(tsEmailToVO ->
tsEmailToVO.setEmailSndngInnb(tsEmailVO.getEmailSndngInnb())
);
log.debug("list {}", list);
}
}
return emailSndngInnbList;
}
//문자열 오류 처리
public String fixStr(String convertCn) {
Map<String, String> replacementMap = new HashMap<>();
replacementMap.put("&#x20a9;", "₩");
replacementMap.put("&yen;", "¥");
replacementMap.put("&euro;", "€");
replacementMap.put("&#x24;", "$");
replacementMap.put("US&dollar;", "US$");
replacementMap.put("&amp;", "&");
replacementMap.put("&lt;", "<");
replacementMap.put("&gt;", ">");
//문자열 오류 수정
return replacementMap.entrySet().stream()
.map(entry -> convertCn.replaceAll(entry.getKey(), entry.getValue()))
.reduce((str1, str2) -> str2)
.orElse(convertCn);
}
//메시지 타입 설정
public String msgType(String msg) {
//바이트 타입 변환
byte[] bytes = null;
int length = 0;
try {
bytes = msg.getBytes("UTF-8");
byte[] convertedBytes = new byte[bytes.length];
int convertedLength = 0;
for (byte b : bytes) {
if (b >= 0) {
convertedBytes[convertedLength++] = b;
}
}
length = new String(convertedBytes, 0, convertedLength, "EUC-KR").length();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
String sendType = length <= 90 ? "SMS" : "LMS";
return sendType;
}
}

View File

@@ -0,0 +1,39 @@
package com.wb.domainserver.atmcrcpmny.tasklet;
import java.util.Map;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.wb.domainserver.response.WnbtWebClientResponseHandler;
import com.wb.domainserver.util.communicate.RESRC;
import com.wb.domainserver.util.communicate.SendToResrc;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class InsertTsRcpmnyDtlsColctTasklet implements Tasklet {
@Autowired
WnbtWebClientResponseHandler responseHandler;
@Autowired
private SendToResrc sendToResrc;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
log.debug("execute()");
Map<String, Object> result = responseHandler.handleResponseAsMap(
sendToResrc.ofPost(RESRC.GCONEBO, "/gcone/ordr/atmcrcpmny/insertBORcpmnyDtlsColctBatch", "")
);
log.debug("result = {}", result);
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,51 @@
package com.wb.domainserver.atmcrcpmny.tasklet;
import java.util.List;
import java.util.Map;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.wb.domainserver.mapper.gcone.AtmcrcpmnyMapper;
import com.wb.domainserver.response.WnbtWebClientResponseHandler;
import com.wb.domainserver.util.communicate.RESRC;
import com.wb.domainserver.util.communicate.SendToResrc;
import com.wb.domainserver.util.dataaccess.DataMap;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class SelectTsOrderCancelTasklet implements Tasklet {
@Autowired
private AtmcrcpmnyMapper mapper;
@Autowired
WnbtWebClientResponseHandler responseHandler;
@Autowired
private SendToResrc sendToResrc;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
log.debug("execute()");
List<DataMap> list = mapper.selectOrderCancel();
if(!list.isEmpty()) {
Map<String, Object> result = responseHandler.handleResponseAsMap(
sendToResrc.ofPost(RESRC.GCONEBO, "/gcone/ordr/atmcrcpmny/selectBOOrderCancel", list)
);
log.debug("result = {}", result);
}
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,133 @@
package com.wb.domainserver.atmcrcpmny.tasklet;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.wb.domainserver.atmcrcpmny.vo.TsUpdateClearPersonalInfoShopVO;
import com.wb.domainserver.mapper.gcone.AtmcrcpmnyMapper;
import com.wb.domainserver.util.dataaccess.DataMap;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class UpdateClearPersonalInfoShopTasklet implements Tasklet {
@Autowired
private AtmcrcpmnyMapper mapper;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
log.debug("execute()");
// 날짜 포맷
// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
// 현재 날짜
// LocalDate currentDate = LocalDate.now();
// LocalDate oneYearsAgoDate = currentDate.minusMonths(12); // 현재 날짜에서 12개월 전 날짜
// LocalDate fiveYearsAgoDate = currentDate.minusMonths(60); // 현재 날짜에서 60개월 전 날짜
// String oneYearsAgo = oneYearsAgoDate.format(formatter) + " 00:00:00"; // 1년 전
// String fiveYearsAgo = fiveYearsAgoDate.format(formatter) + " 00:00:00"; // 5년 전
// 파라미터용 객체
TsUpdateClearPersonalInfoShopVO paramVO = new TsUpdateClearPersonalInfoShopVO();
// paramVO.setDeleteDate(oneYearsAgo); // 1년 전
// paramVO.setUpdateDate(fiveYearsAgo); // 5년 전
paramVO.setDeleteMonths(-12); // 현재 날짜에서 12개월 전 날짜(1년 전+일주일전 ~ 1년전)
paramVO.setUpdateMonths(-24); // 현재 날짜에서 24개월 전 날짜(2년 전+일주일전 ~ 2년전)
paramVO.setBufferDays(-7); // 현재 날짜에서 DeleteMonths or UpdateMonths 개월 전 날짜에서 일주일전을 세팅
// log.debug("paramVO = {}", paramVO);
// List<DataMap> list = mapper.selectGcSms(paramVO);
// log.debug("list = {}", list);
// String[] smsToInnb = new String[list.size()];
// for(int i = 0; i < list.size(); i++) {
// smsToInnb[i] = list.get(i).get("smsToInnb").toString();
// }
// paramVO.setSmsToInnb(smsToInnb);
// 문자/메일 관련 개인정보 삭제 쿼리
mapper.deleteGcSmsTo(paramVO);
// 이메일 발송로그
mapper.deleteGcEmailLog(paramVO);
// 이메일 대상관리
mapper.deleteGcEmailTo(paramVO);
// 주문결제
mapper.updateGcOrderSetle(paramVO);
// 배송
mapper.updateGcOrderShipping(paramVO);
// 반품
mapper.updateGcOrderRefund(paramVO);
// 매출증빙
mapper.updateGcSales(paramVO);
// 주문(마지막에 실행)
mapper.updateGcOrder(paramVO);
// // 대상 주문 선정 (개인정보 보유기한 5년, 매일 최대 100000개 까지만 처리)
// List<TsUpdateClearPersonalInfoShopVO> resultListVO = mapper.selectUpdateTrget(paramVO);
// log.debug("resultListVO = {}", resultListVO);
//
// // 주문 업데이트를할 대상이 있으면
// if(resultListVO.size() != 0) {
// String[] ordrInnbs = new String[resultListVO.size()];
//
// // select 결과 데이터 배열에 담음.
// for(int i = 0; i < resultListVO.size(); i++) {
// ordrInnbs[i] = resultListVO.get(i).getOrdrInnb();
// log.debug("ordrInnbs {} = {}", i, ordrInnbs[i]);
// }
//
// int limitCnt = 1000; // 한번에 1000개씩
// int arrCnt = (int) Math.ceil((double) resultListVO.size() / limitCnt);
//
// String[][] temp = new String[arrCnt][];
//
// // 2차원 배열에 1000개씩 나눠서 담음.
// for(int i = 0; i < arrCnt; i++) {
// int start = i * limitCnt;
// int end = Math.min(start + limitCnt, resultListVO.size());
// temp[i] = new String[end - start];
//
// System.arraycopy(ordrInnbs, start, temp[i], 0, end - start);
// }
//
// for(int i = 0; i < temp.length; i++) {
// paramVO.setOrdrInnbs(temp[i]);
//
// // 배송
// mapper.updateGcOrderShipping(paramVO);
// // 반품
// mapper.updateGcOrderRefund(paramVO);
// // 매출증빙
// mapper.updateGcSales(paramVO);
// // 주문
// mapper.updateGcOrder(paramVO);
// // 주문결제
// mapper.updateGcOrderSetle(paramVO);
// }
// }
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,49 @@
package com.wb.domainserver.atmcrcpmny.tasklet;
import java.util.List;
import java.util.Map;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.wb.domainserver.mapper.gcone.AtmcrcpmnyMapper;
import com.wb.domainserver.response.WnbtWebClientResponseHandler;
import com.wb.domainserver.util.communicate.RESRC;
import com.wb.domainserver.util.communicate.SendToResrc;
import com.wb.domainserver.util.dataaccess.DataMap;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class UpdateTsCshRciptRegistTasklet implements Tasklet {
@Autowired
private AtmcrcpmnyMapper mapper;
@Autowired
WnbtWebClientResponseHandler responseHandler;
@Autowired
private SendToResrc sendToResrc;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
log.debug("execute()");
// 현금영수증 신청 할 데이터 조회
List<DataMap> resultList = mapper.selectCshRciptRegist();
Map<String, Object> result = responseHandler.handleResponseAsMap(
sendToResrc.ofPost(RESRC.GCONEBO, "/gcone/ordr/selngpruf/insertBOCshRciptRegistBatch", resultList)
);
log.debug("result = {}", result);
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,45 @@
package com.wb.domainserver.atmcrcpmny.tasklet;
import java.util.Map;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.wb.domainserver.mapper.gcone.AtmcrcpmnyMapper;
import com.wb.domainserver.response.WnbtWebClientResponseHandler;
import com.wb.domainserver.util.communicate.RESRC;
import com.wb.domainserver.util.communicate.SendToResrc;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class UpdateTsRcpmnyCnfirmAtmcMtchgTasklet implements Tasklet {
@Autowired
private AtmcrcpmnyMapper mapper;
@Autowired
WnbtWebClientResponseHandler responseHandler;
@Autowired
private SendToResrc sendToResrc;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
log.debug("execute()");
Map<String, Object> result = responseHandler.handleResponseAsMap(
sendToResrc.ofPost(RESRC.GCONEBO, "/gcone/ordr/atmcrcpmny/updateBORcpmnyCnfirmExecutBatch", "")
);
log.debug("result = {}", result);
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,57 @@
package com.wb.domainserver.atmcrcpmny.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
*
* 해당 클래스에 대한 설명을 입력하세요.
* @author 임수영.
* @since 2024-07-08
* @version 1.0
* @see
*
* <pre>
* == (Modification Information) == 개정이력
*
* 수정일 수정자 수정내용
* ------- -------- ---------------------------
* 2024-07-08 임수영 최초 생성
*
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class TsCshRciptRegistVO {
private static final long serialVersionUID = 1L;
/** 쇼핑몰코드 */
private String sopmalCd;
/** 매출증빙고유번호 */
private String selngPrufInnb;
/** 주문결제번호 */
private String ordrSetleInnb;
/** 주문고유번호 */
private String ordrInnb;
/** 주문자명 */
private String ordrrNm;
/** 주문자email */
private String ordrrEmail;
/** 인증번호 */
private String crtnb;
/** 상품명 */
private String goodsNm;
/** 발급대상구분코드 */
private String issuTrgetDvCd;
/** 금액 */
private String amt;
/** 공급가액 */
private String splpric;
/** 부가세액 */
private String vatAmt;
}

View File

@@ -0,0 +1,25 @@
package com.wb.domainserver.atmcrcpmny.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class TsDepositRequestVO {
private static final long serialVersionUID = 1L;
// 주문(fm_order)
/** 쇼핑몰코드*/
private String sopmalCd;
/** 주문고유번호 */
private String ordrInnb;
/** 주문자 휴대전화 */
private String ordrrMbtlnb;
/** 회원고유번호 */
private String mbrInnb;
/** 주문자명 */
private String ordrrNm;
}

View File

@@ -0,0 +1,19 @@
package com.wb.domainserver.atmcrcpmny.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class TsOrderCancelVO {
private static final long serialVersionUID = 1L;
/** 쇼핑몰코드*/
private String sopmalCd;
/** 주문고유번호 */
private String ordrInnb;
//
}

View File

@@ -0,0 +1,53 @@
package com.wb.domainserver.atmcrcpmny.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
*
* 해당 클래스에 대한 설명을 입력하세요.
* @author 임수영.
* @since 2024-07-30
* @version 1.0
* @see
*
* <pre>
* == (Modification Information) == 개정이력
*
* 수정일 수정자 수정내용
* ------- -------- ---------------------------
* 2024-07-30 임수영 최초 생성
*
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class TsUpdateClearPersonalInfoShopVO {
private static final long serialVersionUID = 1L;
/** 쇼핑몰코드 */
private String sopmalCd;
/** 주문고유번호 */
private String ordrInnb;
/** 주문고유번호 */
private String ordrInnbs[];
/** 수정일 */
private String updateDate;
/** 삭제일 */
private String deleteDate;
/** SMS 대상고유번호 */
private String smsToInnb[];
/** 삭제월수 */
private Integer deleteMonths;
/** 수정월수 */
private Integer updateMonths;
/** 수정 버퍼수 */
private Integer bufferDays;
}

View File

@@ -0,0 +1,69 @@
package com.wb.domainserver.common;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class ApiSvc {
public String getConnect(String Url) throws Exception {
HttpURLConnection con = connect(Url);
try {
con.setRequestMethod("GET");
con.setRequestProperty("Content-Type", "application/json");
int responseCode = con.getResponseCode();
log.debug("responseCode : " + responseCode);
if(responseCode == HttpURLConnection.HTTP_OK) {
return readBody(con.getInputStream());
} else {
return readBody(con.getErrorStream());
}
}catch (IOException e) {
throw new Exception("API 요청과 응답 실패",e);
}finally {
con.disconnect();
}
}
public HttpURLConnection connect(String apiUrl) throws Exception {
try {
URL url = new URL(apiUrl);
return (HttpURLConnection)url.openConnection();
}catch (MalformedURLException e) {
throw new Exception("API URL이 잘못되었습니다. : "+apiUrl,e);
}catch (IOException e) {
throw new Exception("연결이 실패했습니다. : "+apiUrl,e);
}
}
public String readBody(InputStream body) throws Exception {
InputStreamReader streamReader = new InputStreamReader(body, "UTF-8");
try (BufferedReader lineReader = new BufferedReader(streamReader)){
StringBuilder responseBody = new StringBuilder();
String line;
while((line = lineReader.readLine()) != null) {
responseBody.append(line);
}
return responseBody.toString();
} catch (IOException e) {
throw new Exception("API 응답을 읽는데 실패했습니다.",e);
}
}
}

View File

@@ -0,0 +1,19 @@
package com.wb.domainserver.common;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class CommonService {
@Value("${secret.key}")
private String secretKey;
/**
* 암호화키 조회
* @return String
*/
public String selectSecretkey() {
return secretKey;
}
}

View File

@@ -0,0 +1,51 @@
package com.wb.domainserver.common.config;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@EnableTransactionManagement
@MapperScan(
basePackages = "com.wb.domainserver.mapper.crm",
sqlSessionFactoryRef = "crmSqlSessionFactory"
)
public class CrmDataSourceConfig {
@Bean(name = "crmDataSource")
@ConfigurationProperties(prefix = "spring.datasource.crmdatasource")
public DataSource crmDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "crmSqlSessionFactory")
public SqlSessionFactory crmSqlSessionFactory(@Qualifier("crmDataSource") DataSource crmDataSource) throws Exception {
// SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
SqlSessionFactoryBean sessionFactory = new RefreshableSqlSessionFactoryBean();
sessionFactory.setDataSource(crmDataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mybatis/xml/mapper/crm/**/*.xml"));
sessionFactory.setConfigLocation(new PathMatchingResourcePatternResolver().getResource("classpath:mybatis/xml/config/mapper-config.xml"));
return sessionFactory.getObject();
}
@Bean(name = "crmTransactionManager")
public PlatformTransactionManager crmTransactionManager(@Qualifier("crmDataSource") DataSource crmDataSource) {
return new DataSourceTransactionManager(crmDataSource);
}
}

View File

@@ -0,0 +1,74 @@
package com.wb.domainserver.common.config;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration
@EnableTransactionManagement
@MapperScan(
basePackages = "com.wb.domainserver.mapper.gcone",
sqlSessionFactoryRef = "gconeSqlSessionFactory"
)
public class GconeSourceConfig {
@Bean(name = "dataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.defaultdatasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "gconeDataSource")
@ConfigurationProperties(prefix = "spring.datasource.gconedatasource")
public DataSource gconeDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "gconeSqlSessionFactory")
@Primary
public SqlSessionFactory gconeSqlSessionFactory(@Qualifier("gconeDataSource") DataSource gconeDataSource) throws Exception {
// SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
SqlSessionFactoryBean sessionFactory = new RefreshableSqlSessionFactoryBean();
sessionFactory.setDataSource(gconeDataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mybatis/xml/mapper/gcone/**/*.xml"));
sessionFactory.setConfigLocation(new PathMatchingResourcePatternResolver().getResource("classpath:mybatis/xml/config/mapper-config.xml"));
return sessionFactory.getObject();
}
@Bean(name = "transactionManager")
@Primary
public PlatformTransactionManager transactionManager(@Qualifier("gconeDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "gconeTransactionManager")
public PlatformTransactionManager gconeTransactionManager(@Qualifier("gconeDataSource") DataSource gconeDataSource) {
return new DataSourceTransactionManager(gconeDataSource);
}
@Bean
public JobRepository jobRepository( @Qualifier("gconeTransactionManager") PlatformTransactionManager transactionManager, @Qualifier("gconeDataSource") DataSource gconeDataSource) throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(gconeDataSource);
factory.setTransactionManager(transactionManager);
factory.afterPropertiesSet();
return factory.getObject();
}
}

View File

@@ -0,0 +1,51 @@
package com.wb.domainserver.common.config;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@EnableTransactionManagement
@MapperScan(
basePackages = "com.wb.domainserver.mapper.mq",
sqlSessionFactoryRef = "mqSqlSessionFactory"
)
public class MqDataSourceConfig {
@Bean(name = "mqDataSource")
@ConfigurationProperties(prefix = "spring.datasource.mqdatasource")
public DataSource mqDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "mqSqlSessionFactory")
public SqlSessionFactory mqSqlSessionFactory(@Qualifier("mqDataSource") DataSource mqDataSource) throws Exception {
// SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
SqlSessionFactoryBean sessionFactory = new RefreshableSqlSessionFactoryBean();
sessionFactory.setDataSource(mqDataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mybatis/xml/mapper/mq/**/*.xml"));
sessionFactory.setConfigLocation(new PathMatchingResourcePatternResolver().getResource("classpath:mybatis/xml/config/mapper-config.xml"));
return sessionFactory.getObject();
}
@Bean(name = "mqTransactionManager")
public PlatformTransactionManager mqTransactionManager(@Qualifier("mqDataSource") DataSource mqDataSource) {
return new DataSourceTransactionManager(mqDataSource);
}
}

View File

@@ -0,0 +1,156 @@
package com.wb.domainserver.common.config;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class RefreshableSqlSessionFactoryBean extends SqlSessionFactoryBean implements DisposableBean {
private static final Logger LOG = LoggerFactory.getLogger(RefreshableSqlSessionFactoryBean.class);
private SqlSessionFactory proxy;
private int interval = 1000;
private Timer timer;
private TimerTask task;
private Resource[] mapperLocations;
private boolean running = false;
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
public void setMapperLocations(Resource[] mapperLocations) {
super.setMapperLocations(mapperLocations);
this.mapperLocations = mapperLocations;
}
public void setInterval(int interval) {
this.interval = interval;
}
public void refresh() throws Exception {
w.lock();
try {
super.afterPropertiesSet();
} finally {
w.unlock();
}
LOG.info("sqlMapClient refreshed.");
}
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
}
private void setRefreshable() {
proxy = (SqlSessionFactory) Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSessionFactory.class}, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(getParentObject(), args);
}
});
task = new TimerTask() {
private Map<Resource, Long> map = new HashMap<Resource, Long>();
public void run() {
if (isModified()) {
try {
refresh();
} catch (Exception e) {
LOG.error("caught exception", e);
}
}
}
private boolean isModified() {
boolean retVal = false;
if (mapperLocations != null) {
for (int i = 0; i < mapperLocations.length; i++) {
Resource mappingLocation = mapperLocations[i];
retVal |= findModifiedResource(mappingLocation);
}
}
return retVal;
}
private boolean findModifiedResource(Resource resource) {
boolean retVal = false;
List<String> modifiedResources = new ArrayList<String>();
try {
long modified = resource.lastModified();
if (map.containsKey(resource)) {
long lastModified = map.get(resource).longValue();
if (lastModified != modified) {
map.put(resource, modified);
modifiedResources.add(resource.getDescription());
retVal = true;
}
} else {
map.put(resource, modified);
}
} catch (IOException e) {
LOG.error("caught exception", e);
}
if (retVal) {
LOG.info("modified files : " + modifiedResources);
}
return retVal;
}
};
timer = new Timer(true);
resetInterval();
}
private Object getParentObject() throws Exception {
r.lock();
try {
return super.getObject();
} finally {
r.unlock();
}
}
public SqlSessionFactory getObject() throws Exception {
if (this.proxy == null) {
setRefreshable();
}
return this.proxy;
}
public Class<? extends SqlSessionFactory> getObjectType() {
return (this.proxy != null ? this.proxy.getClass() : SqlSessionFactory.class);
}
public boolean isSingleton() {
return true;
}
public void setCheckInterval(int ms) {
interval = ms;
if (timer != null) {
resetInterval();
}
}
private void resetInterval() {
if (running) {
timer.cancel();
running = false;
}
if (interval > 0) {
timer.schedule(task, 0, interval);
running = true;
}
}
public void destroy() throws Exception {
timer.cancel();
}
}

View File

@@ -0,0 +1,49 @@
package com.wb.domainserver.common.config;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration
@EnableTransactionManagement
@MapperScan(
basePackages = "com.wb.domainserver.mapper.sure",
sqlSessionFactoryRef = "sureSqlSessionFactory"
)
public class SureDataSourceConfig {
@Bean(name = "sureDataSource")
@ConfigurationProperties(prefix = "spring.datasource.suredatasource")
public DataSource sureDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "sureSqlSessionFactory")
public SqlSessionFactory sureSqlSessionFactory(@Qualifier("sureDataSource") DataSource sureDataSource) throws Exception {
// SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
SqlSessionFactoryBean sessionFactory = new RefreshableSqlSessionFactoryBean();
sessionFactory.setDataSource(sureDataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mybatis/xml/mapper/sure/**/*.xml"));
sessionFactory.setConfigLocation(new PathMatchingResourcePatternResolver().getResource("classpath:mybatis/xml/config/mapper-config.xml"));
return sessionFactory.getObject();
}
@Bean(name = "sureTransactionManager")
public PlatformTransactionManager mqTransactionManager(@Qualifier("sureDataSource") DataSource sureDataSource) {
return new DataSourceTransactionManager(sureDataSource);
}
}

View File

@@ -0,0 +1,41 @@
package com.wb.domainserver.common.vo;
import lombok.Data;
import java.io.Serializable;
import java.sql.Date;
@Data
public abstract class AbstractVO implements Serializable {
private static final long serialVersionUID = 1L;
/** 사용여부 */
private String useAt;
/** 등록자 */
private int regusr;
/** 등록일시 */
private Date registDt;
/** 등록일자 */
private String registDe;
/** 수정자 */
private int updusr;
/** 수정일시 */
private Date updtDt;
/** 수정일자 */
private String updtDe;
/** 현재페이지 */
private int pageIndex = 1;
/** 페이지갯수 */
private int pageUnit = 10;
/** 페이지사이즈 */
private int pageSize = 10;
/** 첫페이지 인덱스 */
private int firstIndex = 1;
/** 마지막페이지 인덱스 */
private int lastIndex = 1;
/** 페이지당 레코드 개수 */
private int recordCountPerPage = 10;
/** pagination객체 */
// private PaginationInfo paginationInfo;
}

View File

@@ -0,0 +1,15 @@
package com.wb.domainserver.common.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommVO {
private String sopmalCd;
}

View File

@@ -0,0 +1,149 @@
package com.wb.domainserver.controller;
import com.wb.domainserver.common.vo.CommVO;
import com.wb.domainserver.pos.vo.PosReqVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.*;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.wb.domainserver.response.ApiResponse;
import com.wb.domainserver.util.dataaccess.DataMap;
import java.util.UUID;
@RestController
@RequestMapping("/batch")
@Slf4j
public class BatchJobController {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private ApplicationContext applicationContext;
@PostMapping("/run/{jobName}")
public ResponseEntity<?> runBatchJob(@PathVariable String jobName) {
log.debug(" 파라미터 받은 jobName 확인 : " + jobName);
JobParameters params = new JobParametersBuilder()
.addLong("currTime", System.currentTimeMillis()) // 고유값 추가
.toJobParameters();
log.debug(" jobParameters : " + params);
DataMap message = new DataMap();
try {
// JobExecution 객체로 실행 결과 받기
Job job = (Job) applicationContext.getBean(jobName);
JobExecution jobExecution = jobLauncher.run(job, params);
// Job의 실행 상태 확인
if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
message.put("result", "Job executed successfully");
return ApiResponse.of(message).ifPresentOrElse(HttpStatus.OK, HttpStatus.NOT_FOUND);
} else {
message.put("result", "Job failed or is still running: " + jobExecution.getStatus());
return ApiResponse.of(message).ifPresentOrElse(HttpStatus.INTERNAL_SERVER_ERROR, HttpStatus.NOT_FOUND);
}
} catch (Exception e) {
message.put("result", "Job execution failed: " + e.getMessage());
return ApiResponse.of(message).ifPresentOrElse(HttpStatus.INTERNAL_SERVER_ERROR, HttpStatus.NOT_FOUND);
}
};
@PostMapping("/run/mq/{jobName}")
public ResponseEntity<?> runBatchJob(@PathVariable String jobName, @RequestBody CommVO vo) {
System.out.println(" 파라미터 받은 jobName 확인 : " + jobName);
System.out.println(" 파라미터 받은 VO 확인33 : " + vo);
JobParameters params = new JobParametersBuilder()
.addString("currTime", vo.getSopmalCd()+":"+System.currentTimeMillis()) // 고유값 추가
.toJobParameters();
System.out.println(" jobParameters : " + params);
DataMap message = new DataMap();
try {
// JobExecution 객체로 실행 결과 받기
Job job = (Job) applicationContext.getBean(jobName);
JobExecution jobExecution = jobLauncher.run(job, params);
String resultMsg = "";
for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
ExecutionContext stepContext = stepExecution.getExecutionContext();
if (stepContext.containsKey("resultMsg")) {
resultMsg = stepContext.getString("resultMsg");
break;
}
}
log.debug(" stepExecution : resultMsg " + resultMsg);
// Job의 실행 상태 확인
if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
message.put("result", "Job executed successfully");
message.put("resultMsg", resultMsg); // 추가된 resultMsg 반환
log.debug(" 배치 컨트롤러에서 성공하고 결과값 확인 : {} " + message);
return ApiResponse.of(message).ifPresentOrElse(HttpStatus.OK, HttpStatus.NOT_FOUND);
} else {
message.put("result", "Job failed or is still running: " + jobExecution.getStatus());
return ApiResponse.of(message).ifPresentOrElse(HttpStatus.INTERNAL_SERVER_ERROR, HttpStatus.NOT_FOUND);
}
} catch (Exception e) {
message.put("result", "Job execution failed: " + e.getMessage());
return ApiResponse.of(message).ifPresentOrElse(HttpStatus.INTERNAL_SERVER_ERROR, HttpStatus.NOT_FOUND);
}
};
/**
* 포스 수동 조회
* @return
*/
@RequestMapping("/run/pos/{jobName}")
public ResponseEntity<?> runPosBatchJob(@PathVariable String jobName, @RequestBody PosReqVO vo) {
log.debug(" 파라미터 받은 jobName 확인 : {} ", jobName);
log.debug(" 받은 파라미터 확인 : {}", vo);
String paramSet = System.currentTimeMillis() + ":" + vo.toString() ;
JobParameters params = new JobParametersBuilder()
.addString("currTime", paramSet) // 고유값 추가
.toJobParameters();
log.debug(" jobParameters : {}",params);
DataMap message = new DataMap();
try {
// JobExecution 객체로 실행 결과 받기
Job job = (Job) applicationContext.getBean(jobName);
JobExecution jobExecution = jobLauncher.run(job, params);
// Job의 실행 상태 확인
if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
message.put("result", "Job executed successfully");
return ApiResponse.of(message).ifPresentOrElse(HttpStatus.OK, HttpStatus.NOT_FOUND);
} else {
message.put("result", "Job failed or is still running: " + jobExecution.getStatus());
return ApiResponse.of(message).ifPresentOrElse(HttpStatus.INTERNAL_SERVER_ERROR, HttpStatus.NOT_FOUND);
}
} catch (Exception e) {
message.put("result", "Job execution failed: " + e.getMessage());
return ApiResponse.of(message).ifPresentOrElse(HttpStatus.INTERNAL_SERVER_ERROR, HttpStatus.NOT_FOUND);
}
};
}

View File

@@ -0,0 +1,86 @@
package com.wb.domainserver.controller;
import com.wb.domainserver.response.ApiResponse;
import com.wb.domainserver.service.MssageJobService;
import com.wb.domainserver.util.dataaccess.DataMap;
import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/batch/mssage")
@RequiredArgsConstructor
public class MssageJobController {
private final MssageJobService service;
/**
* 회원 등급 변경 메시지
*/
/**
* 광고 동의 안내 메시지
* @return
*/
@GetMapping(value = "/marktAgreMbr")
public ResponseEntity<?> runMssageMarktAgreMbrJob() {
DataMap message = new DataMap();
message.put("result", service.runMssageMarktAgreJob("force"));
return ApiResponse.of(message).ifPresentOrElse(HttpStatus.OK, HttpStatus.NOT_FOUND);
}
/**
* 만료 마일리지 안내
* @return
*/
@GetMapping(value = "/mlgExp")
public ResponseEntity<?> runMessageMlgExpJob() {
DataMap message = new DataMap();
service.runMssageMlgExpJob("force");
return ApiResponse.of(message).ifPresentOrElse(HttpStatus.OK, HttpStatus.NOT_FOUND);
}
/**
* 입금 요청 안내
* @return
*/
@GetMapping(value = "/depositRequest")
public ResponseEntity<?> runMssageDepositRequestJob() {
DataMap message = new DataMap();
service.runMssageDepositRequestJob("force");
return ApiResponse.of(message).ifPresentOrElse(HttpStatus.OK, HttpStatus.NOT_FOUND);
}
/**
* 문자 상태 갱신
* @return
*/
@GetMapping(value = "/updtSttus")
public ResponseEntity<?> runMssageUpdtSttusJob() {
DataMap message = new DataMap();
message.put("result", service.runMssageUpdtSttusJob("force"));
return ApiResponse.of(message).ifPresentOrElse(HttpStatus.OK, HttpStatus.NOT_FOUND);
}
}

View File

@@ -0,0 +1,119 @@
package com.wb.domainserver.coupon.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
*
* 쿠폰 VO
* @author 추지훈
* @since 2023-12-27
* @version 1.0
* @see
*
* <pre>
* == (Modification Information) == 개정이력
*
* 수정일 수정자 수정내용
* ------- -------- ---------------------------
* 2023-12-27 추지훈 최초 생성
*
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class TsCouponPkSndngVO {
private static final long serialVersionUID = 1L;
// 쿠폰(팩) 발송 정보
/** 쇼핑몰코드 */
private String sopmalCd;
/** 쿠폰발송 고유번호 */
private Integer couponSndngInnb;
/** 이메일 발송양식 고유번호 */
private String emailSndngFormInnb;
/** SMS발송양식 고유번호 */
private String smsSndngFormInnb;
/** 알림톡 발송양식 고유번호 */
private String ntcntalkSndngFormInnb;
/** 발송구분 */
private String sndngDv;
/** 쿠폰발송유형 */
private String couponSndngTy;
/** 쿠폰발송명 */
private String couponSndngNm;
/** 쿠폰발송설명 */
private String couponSndngDc;
/** 쿠폰발송 사용여부 */
private String couponSndngUseAt;
/** 다운로드 기간 제한 여부 */
private String dwldPdLmttAt;
/** 다운시작일시 */
private String dwldBgnDt;
/** 다운종료일시 */
private String dwldEndDt;
/** 발송일시구분 */
private String sndngDtDvCd;
/** 발송일시 */
private String sndngDt;
/** 발송주기 */
private String sndngCycle;
/** 월발송주기일자 */
private String mtSndngCycleDe;
/** 발송대상 구분 */
private String sndngTrgetDv;
/** 사용 여부 */
private String useAt;
// 검색
/** 검색_쿠폰발송명 */
private String searchCouponPkSndngNm;
/** 검색_발송구분 */
private String searchSndngDv;
/** 검색_쿠폰발송 사용여부 */
private String searchCouponSndngUseAt;
/** 검색_쿠폰발송유형 */
private String[] searchCouponSndngTy;
/** 검색_사용여부 */
private String searchUseAt;
/**
* 쿠폰(팩) 등급대상
*/
/** 쿠폰등급제한 고유번호 */
private Integer couponGradLmttInnb;
/** 회원등급 고유번호 등급 대상을 받을 문자열 */
private String trgetMbrGradeInnbs;
/** 회원등급 고유번호 등급 대상 배열 */
private int[] trgetMbrGradeArray;
/** 회원등급 고유번호 등급 대상 */
private Integer mbrGradInnb;
/**
* 쿠폰(팩) 발송대상쿠폰
*/
/** 발송대상 고유번호 */
private Integer sndngTrgetInnb;
/** 쿠폰 고유번호 */
private Integer couponInnb;
/** 쿠폰팩에 매칭된 쿠폰들을 받을 문자열 */
private String packedCouponInnbs;
/** packedCouponInnbs 문자열을 배열로 전환 */
private int[] packedCouponArray;
/** 쿠폰팩 고유번호 */
private Integer cupnpkInnb;
}

View File

@@ -0,0 +1,237 @@
package com.wb.domainserver.coupon.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
*
* 쿠폰 VO
* @author 추지훈
* @since 2023-12-11
* @version 1.0
* @see
*
* <pre>
* == (Modification Information) == 개정이력
*
* 수정일 수정자 수정내용
* ------- -------- ---------------------------
* 2023-12-11 추지훈 최초 생성
*
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class TsCouponVO {
private static final long serialVersionUID = 1L;
/**
* 쿠폰정보
*/
/** 인증번호 개수 */
private Integer offlineCnt;
// 발송 대상 쿠폰 조회
/** 쿠폰팩 고유번호 */
private Integer cupnpkInnb;
/** 쿠폰 발송 대상 고유번호 */
private String sndngTrgetInnb;
/** 쿠폰발송 고유번호 */
private String couponSndngInnb;
/** 쿠폰 고유번호 */
private Integer couponInnb;
/** 쇼핑몰 코드 */
private String sopmalCd;
/** 쿠폰명 */
private String coupNm;
/** 쿠폰 설명 */
private String couponDc;
/** 사용환경코드 */
private String useEnvrnCd;
/** 단독사용, 공동사용 */
private String otrCouponSmtmUseAt;
/** 중복다운로드여부 */
private String dplctDwldAt;
/** 중복할인여부 */
private String dplctDscntAt;
/** 사용가능금액 */
private String usePosblAmt;
/** 상품카테고리 제한구분( 전체상품(all), 상품/카테고리(issue) ) */
private String goodsCtgryLmttDv;
/** 수량 제한여부 */
private String qyLmttAt;
/** 제한수량 */
private String lmttQy;
/** 기간설정, 발금(다운로드)일 기준 */
private String validpdKnd;
/** 유효기간시작일시 */
private String validpdBgnDt;
/** 유효기간시작일시 포맷 yyyy-mm-dd */
private String validpdBgnDe;
/** 유효기간종료일시 */
private String validpdEndDt;
/** 유효기간종료일시 포맷 yyyy-mm-dd */
private String validpdEndDe;
/** 유효기간일수 */
private String validpdDeCnt;
/** 유효기간일수 */
private String validpdCntDe;
/** 쿠폰팩 등록가능여부 */
private String cupnpkRegistPosblAt;
/** 타브랜드 쿠폰팩 등록가능여부 */
private String otrBrndCpnpkRgstPsblAt;
/** 쿠폰 사용여부 */
private String couponUseAt;
// 쿠폰 혜택
/** 쿠폰 혜택 고유번호 */
private Integer couponBnefInnb;
/** 혜택구분 */
private String bnefDv;
/** 상품할인구분 */
private String goodsDscntDv;
/** */
// private String selectAditDscnt;
/** 추가할인금액 */
private String aditDscntAmt;
/** 추가할인비율 */
private String aditDscntRt;
/** 할인최대금액 */
private String dscntMxmmAmt;
/** 무료, 금액 */
private String dlvyAmtDscntDv;
/** 배송비할인금액 */
private String dlvyAmtDscntAmt;
/** 배송비최대할인금액 */
private String dlvyAmtMxmmDscntAmt;
// 쿠폰 적용 상품
/** 상품 적용 구분 코드 */
private String goodsApplcDvCd;
/** 선택한 카테고리 */
private String[] reprsntCtgryId;
/** 선택한 상품 */
private String[] relatedGoodsId;
/** 상품 고유번호 */
private String goodsInnb;
/** 상위 카테고리 */
private String upperCtgryId;
/** 쿠폰 적용상품 고유번호 */
private Integer couponApplcGoodsInnb;
/** 상품적용구분 */
private String goodsApplcDv;
/** 판매상품 고유번호 */
private Integer sleGoodsInnb;
/** 혜택 적용 판매상품 고유번호 리스트 */
private List<Integer> sleGoodsInnbList;
/** 혜택 제외 판매상품 고유번호 리스트 */
private List<Integer> ExclSleGoodsInnbList;
/** 카테고리 ID */
private Integer ctgryId;
/** 혜택 적용 카테고리 ID 리스트 */
private List<Integer> ctgryIdList;
/** 혜택 제외 카테고리 ID 리스트 */
private List<Integer> ExclCtgryIdList;
// 쿠폰매장연동
/** POS 본부코드 */
private String posHdqrtrsCd;
private List<String> posHdqrtrsCdList;
/** POS 등록년도 */
private String posCouponRegistYear;
private List<String> posCouponRegistYearList;
/** POS 쿠폰코드 */
private String posCouponCd;
private List<String> posCouponCdList;
// 쇼핑몰
/** 쇼핑몰 명 */
private String sopmalNm;
// 검색조건
/** 검색_쿠폰명 */
private String searchCoupNm;
/** 검색_혜택구분 */
private String[] searchBnefDv;
/** 검색_타 쿠폰동시사용여부 */
private String searchOtrCouponSmtmUseAt;
/** 검색_사용여부 */
private String searchUseAt;
/** 검색_사용환경코드 */
private String[] searchUseEnvrnCd;
/** 검색_중복할인 */
private String searchDplctDscntAt;
/** 검색_쇼핑몰 코드 */
private String searchSopmalCd;
/** 검색_인증번호 */
private String srchCrtnb;
/** 그룹 코드 */
private String groupCd;
/** 쿠폰 발송 유형 코드 */
private String couponSndngTy;
/** 쿠폰발송 대상 고유번호 */
private Integer couponSndngTrgetInnb;
/***************************************************
* 인증번호
***************************************************/
/** 인증번호 생성 개수 */
private String createQy;
/** 오프라인쿠폰 고유번호 */
private Integer oflneCouponInnb;
/** 오프라인쿠폰 생성번호 */
private String oflneCouponCreateNb;
/** 오프라인쿠폰 인증번호 */
private String oflneCouponCrtnb;
/** 사용 건수 */
private String useCnt;
/** 발송대상자명 */
private String sndngTrgetrNm;
/** 발송대상전화번호 */
private String sndngTrgetTelnb;
}

View File

@@ -0,0 +1,230 @@
package com.wb.domainserver.coupon.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigInteger;
import java.util.List;
/**
*
* 쿠폰 VO
* @author 추지훈
* @since 2023-12-11
* @version 1.0
* @see
*
* <pre>
* == (Modification Information) == 개정이력
*
* 수정일 수정자 수정내용
* ------- -------- ---------------------------
* 2023-12-11 추지훈 최초 생성
*
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class TsDwldCouponVO {
private static final long serialVersionUID = 1L;
/**
* 쿠폰정보
*/
/** 다운로드 쿠폰 고유번호 */
private Integer dwldCouponInnb;
/** 쿠폰 고유번호 */
private Integer couponInnb;
/** 회원 고유번호 */
private BigInteger mbrInnb;
/** 회원 구분 코드 */
private String mbrDvCd;
/** 회원 명 */
private String mbrNm;
/** 회원 휴대폰번호 */
private String mbtlnb;
/** 쿠폰팩 고유번호 */
private Integer cupnpkInnb;
/** 오프라인쿠폰 고유번호 */
private Integer oflneCouponInnb;
/** 쿠폰 발송 고유번호 */
private Integer couponSndngInnb;
/** 쿠폰 발송 유형코드 */
private String couponSndngTy;
/** 발송구분 */
private String sndngDv;
/** 발송대상 구분 */
private String sndngTrgetDv;
/** 쇼핑몰 코드 */
private String sopmalCd;
/** 다운로드 쿠폰팩명 */
private String cupnpkNm;
/** 다운로드 쿠폰팩 설명 */
private String cupnpkDc;
/** 다운로드 쿠폰명 */
private String coupNm;
/** 다운로드 쿠폰 설명 */
private String couponDc;
/** 사용환경코드 */
private String useEnvrnCd;
/** 단독사용, 공동사용 */
private String otrCouponSmtmUseAt;
/** 중복다운로드여부 */
private String dplctDwldAt;
/** 중복할인여부 */
private String dplctDscntAt;
/** 사용가능금액 */
private String usePosblAmt;
/** 상품카테고리 제한구분( 전체상품(all), 상품/카테고리(issue) ) */
private String goodsCtgryLmttDv;
/** 유효기간 종류 구분 코드 */
private String validpdKndCd;
/** 유효기간시작일시 */
private String validpdBgnDt;
/** 유효기간시작일시 포맷 yyyy-mm-dd */
private String validpdBgnDe;
/** 유효기간종료일시 */
private String validpdEndDt;
/** 유효기간종료일시 포맷 yyyy-mm-dd */
private String validpdEndDe;
/** 유효기간 남은 일수 */
private String validpdDay;
/** 쿠폰 사용여부 */
private String couponUseAt;
/** 쿠폰 사용 일시 */
private String couponUseDt;
/** 오프라인쿠폰 인증번호 */
private String oflneCouponCrtnb;
/** 사용처구분 */
private String useplcDvCd;
/** 복원 원본쿠폰 */
private String recovryOrginlCoupon;
/** 쿠폰상태코드 */
private String couponSttusCd;
/** 사용자 다운로드할 쿠폰 목록 */
private List<TsUserDwldVO> downloadCouponList;
// 쿠폰 혜택
/** 다운로드 쿠폰 혜택 고유번호 */
private Integer dwldCouponBnefInnb;
/** 혜택구분 */
private String bnefDv;
/** 상품할인구분 */
private String goodsDscntDv;
/** 추가할인금액 */
private String aditDscntAmt;
/** 추가할인비율 */
private String aditDscntRt;
/** 할인최대금액 */
private String dscntMxmmAmt;
/** 무료, 금액 */
private String dlvyAmtDscntDv;
/** 배송비할인금액 */
private String dlvyAmtDscntAmt;
/** 배송비최대할인금액 */
private String dlvyAmtMxmmDscntAmt;
// 쿠폰 적용 상품
/** 쿠폰 적용상품 고유번호 */
private Integer dwldCouponApplcGoodsInnb;
/** 상품적용구분 */
private String goodsApplcDv;
/** 판매상품 고유번호 */
private Integer sleGoodsInnb;
/** 혜택 적용 판매상품 고유번호 리스트 */
private List<Integer> sleGoodsInnbList;
/** 혜택 제외 판매상품 고유번호 리스트 */
private List<Integer> ExclSleGoodsInnbList;
/** 카테고리 ID */
private String ctgryId;
/** 대상 상품 고유번호 */
private String goodsInnb;
/** 혜택 적용 카테고리 ID 리스트 */
private List<Integer> ctgryIdList;
/** 혜택 제외 카테고리 ID 리스트 */
private List<Integer> ExclCtgryIdList;
// 검색조건
/** 검색_회원아이디, 회원명 */
private String searchKeyword;
/** 검색_발급일 시작 */
private String srchStartDate;
/** 검색_발급일 종료 */
private String srchEndDate;
/** 검색_다운로드쿠폰사용여부 */
private String srchUseAt;
/** 쿠폰 발급 혹은 쿠폰 등록 시 */
private String[] couponArray;
/** 그룹 코드 */
private String groupCd;
/** 주문 고유번호 ( 주문 쿠폰 사용 내역 조회 ) */
private String ordrInnb;
private String ordrRefundInnb;
/** JSON 형태의 회원 리스트 ( 발급하기 ) */
private String jsonMbrList;
/** 발송 대상 구분 ( 사람, 업체 ) */
private String targetDv;
/** 발송대상자명 */
private String sndngTrgetNm;
/** 발송대상전화번호 */
private String sndngTrgetTelnb;
/** 발송 수량 _ 발송 대상 구분이 업체일 경우에만 해당됨. */
private String sndngQy;
//메시지 관련
/** 발송 일시 구분 */
private String sndngDtDvCd;
// 쿠폰 사용처리
/** 포스본부코드 */
private String posHdqrtrsCd;
private String couponUseDtlsInnb;
private String manageMemo;
/**
* 서버 구분
*/
private String serverDv;
private String regusr;
private String registDt;
private String updusr;
private String updDt;
}

View File

@@ -0,0 +1,46 @@
package com.wb.domainserver.coupon.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
*
* 발송 대상 VO
* @author 추지훈
* @since 2023-12-11
* @version 1.0
* @see
*
* <pre>
* == (Modification Information) == 개정이력
*
* 수정일 수정자 수정내용
* ------- -------- ---------------------------
* 2023-12-11 추지훈 최초 생성
*
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class TsSndngMbrJsonVO {
private static final long serialVersionUID = 1L;
/** 쇼핑몰 코드 */
private String sopmalCd;
/** 회원 고유번호 */
private String mbrInnb;
/** 회원 구분 코드 */
private String mbrDvCd;
/** 대상자명 */
private String recpntNm;
/** 대상자 휴대폰번호 */
private String sndngMbtlnb;
/** 대상자 이메일 */
private String sndngEmail;
}

View File

@@ -0,0 +1,65 @@
package com.wb.domainserver.coupon.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
*
* 쿠폰 VO
* @author 추지훈
* @since 2023-12-11
* @version 1.0
* @see
*
* <pre>
* == (Modification Information) == 개정이력
*
* 수정일 수정자 수정내용
* ------- -------- ---------------------------
* 2023-12-11 추지훈 최초 생성
*
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class TsUserDwldVO {
private static final long serialVersionUID = 1L;
/** 다운로드쿠폰 고유번호 */
private Integer dwldCouponInnb;
/** 쿠폰 고유번호 */
private Integer couponInnb;
/** 쿠폰명 */
private String coupNm;
/** 쿠폰설명 */
private String couponDc;
/** 쇼핑몰 코드 */
private String sopmalCd;
/** 회원고유번호 */
private Integer mbrInnb;
/** 회원구분코드 */
private String mbrDvCd;
/** 쿠폰팩고유번호 */
private Integer cupnpkInnb;
/** 오프라인쿠폰 고유번호 */
private Integer oflneCouponInnb;
/** 쿠폰발송 고유번호 */
private Integer couponSndngInnb;
/** 쿠폰팩 명 */
private String cupnpkNm;
/** 쿠폰팩 설명 */
private String cupnpkDc;
/** 회원 명 */
private String mbrNm;
/** 휴대폰번호 */
private String mbtlnb;
/** 오프라인쿠폰 인증번호 */
private String oflneCouponCrtnb;
/** 사용처 구분 */
private String useplcDvCd;
}

View File

@@ -0,0 +1,73 @@
package com.wb.domainserver.crm.jobs;
import com.wb.domainserver.crm.tasklet.InsertExtOrdrTasklet;
import lombok.RequiredArgsConstructor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.listener.ExecutionContextPromotionListener;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
/**
* CRM(ERP) 관련 배치
*
* @author 추지훈
* @since 2024.06.10
* @version 1.0
*/
@RequiredArgsConstructor
@Configuration
@EnableBatchProcessing
public class CrmExtOrdrConfig extends DefaultBatchConfiguration{
private static final Logger logger = LoggerFactory.getLogger(CrmExtOrdrConfig.class);
private final SqlSessionFactory sqlSessionFactory;
private final InsertExtOrdrTasklet insertExtOrdrTasklet;
@Bean
public ExecutionContextPromotionListener promotionListener() {
ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener();
listener.setKeys(new String[]{"message"});
return listener;
}
/* ##############################################################################################
외부 주문 등록
################################################################################################# */
/* @param jobRepository
* @param transactionManager
* @return
*/
@Bean
public Job crmGetExtOrdrJob(JobRepository jobRepository, PlatformTransactionManager transactionManager, ExecutionContextPromotionListener promotionListener) {
return new JobBuilder("crmGetExtOrdrJob", jobRepository)
.start(insertExtOrdrStep(jobRepository, transactionManager, promotionListener))
.incrementer(new RunIdIncrementer())
.build();
}
/**
* 1. GCONE 외부 주문 MAX값 조회
* 2.erp GC_ERP_PURCHSR_INFO에서 외부주문 조회
* 3. GCONE GC_ERP_ORDER 등록
*/
@Bean
public Step insertExtOrdrStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, ExecutionContextPromotionListener promotionListener) {
return new StepBuilder("insertExtOrdrStep", jobRepository)
.tasklet(insertExtOrdrTasklet, transactionManager)
.listener(promotionListener)
.build();
}
}

View File

@@ -0,0 +1,103 @@
package com.wb.domainserver.crm.jobs;
import com.wb.domainserver.crm.tasklet.InsertTsDelMbrAppnRegistTasklet;
import com.wb.domainserver.crm.tasklet.InsertTsMbrAppnRegistTasklet;
import com.wb.domainserver.crm.tasklet.InsertTsRegMbrAppnRegistTasklet;
import lombok.RequiredArgsConstructor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.listener.ExecutionContextPromotionListener;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
/**
* CRM(ERP) 관련 배치
*
* @author 추지훈
* @since 2024.06.10
* @version 1.0
*/
@RequiredArgsConstructor
@Configuration
@EnableBatchProcessing
public class CrmMemberAppnConfig extends DefaultBatchConfiguration{
private static final Logger logger = LoggerFactory.getLogger(CrmMemberAppnConfig.class);
private final SqlSessionFactory sqlSessionFactory;
private final InsertTsDelMbrAppnRegistTasklet insertTsDelMbrAppnRegistTasklet;
private final InsertTsMbrAppnRegistTasklet insertTsMbrAppnRegistTasklet;
private final InsertTsRegMbrAppnRegistTasklet insertTsRegMbrAppnRegistTasklet;
@Bean
public ExecutionContextPromotionListener promotionListener() {
ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener();
listener.setKeys(new String[]{"message"});
return listener;
}
/* ##############################################################################################
블랙리스트
################################################################################################# */
/* @param jobRepository
* @param transactionManager
* @return
*/
@Bean
public Job mqGetMbrAppnJob(JobRepository jobRepository, PlatformTransactionManager transactionManager, ExecutionContextPromotionListener promotionListener) {
return new JobBuilder("mqGetMbrAppnJob", jobRepository)
.start(insertDelAppnLogRegistStep(jobRepository, transactionManager, promotionListener))
.next(insertDelRslrlistRegistStep(jobRepository, transactionManager, promotionListener))
.next(insertRegAppnLogRegistStep(jobRepository, transactionManager, promotionListener))
.incrementer(new RunIdIncrementer())
.build();
}
/**
* 1.삭제 로그 등록
*/
@Bean
public Step insertDelAppnLogRegistStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, ExecutionContextPromotionListener promotionListener) {
return new StepBuilder("insertDelAppnLogRegistStep", jobRepository)
.tasklet(insertTsDelMbrAppnRegistTasklet, transactionManager)
.listener(promotionListener)
.build();
}
/**
* 2. erp 조회, appn 테이블 삭제후 등록하고
*/
@Bean
public Step insertDelRslrlistRegistStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, ExecutionContextPromotionListener promotionListener) {
return new StepBuilder("insertDelRslrlistRegistStep", jobRepository)
.tasklet(insertTsMbrAppnRegistTasklet, transactionManager)
.listener(promotionListener)
.build();
}
/**
* 3. 등록 로그 등록
*/
@Bean
public Step insertRegAppnLogRegistStep(JobRepository jobRepository, PlatformTransactionManager transactionManager, ExecutionContextPromotionListener promotionListener) {
return new StepBuilder("insertRegAppnLogRegistStep", jobRepository)
.tasklet(insertTsRegMbrAppnRegistTasklet, transactionManager)
.listener(promotionListener)
.build();
}
}

View File

@@ -0,0 +1,73 @@
package com.wb.domainserver.crm.tasklet;
import com.wb.domainserver.crm.vo.TsExtOrdrVO;
import com.wb.domainserver.mapper.gcone.ExtOrdrMapper;
import com.wb.domainserver.mapper.mq.CrmExtOrdrMapper;
import com.wb.domainserver.util.dataaccess.DataMap;
import com.wb.domainserver.util.ntcn.DataShareBean;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.scope.context.StepContext;
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@Component
@JobScope
@Slf4j
public class InsertExtOrdrTasklet implements Tasklet {
private static final Logger logger = LoggerFactory.getLogger(InsertExtOrdrTasklet.class);
private StepExecution stepExecution;
@Autowired
private ExtOrdrMapper mapper;
@Autowired
private CrmExtOrdrMapper crmExtOrdrMapper;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
StepContext stepContext = StepSynchronizationManager.getContext();
Map<String, Object> message = (Map<String, Object>) stepContext.getStepExecution().getJobExecution().getExecutionContext().get("message");
log.debug("message {}", message);
try {
//gcone max값 가져오기
DataMap map = mapper.selectExtOrdrMaxInnb();
//mq에서 select 하기
TsExtOrdrVO vo = new TsExtOrdrVO();
BigDecimal maxInnb = (BigDecimal) map.get("maxErpOrderInnb");
vo.setMaxExtOrdrInnb(maxInnb);
List<TsExtOrdrVO> extOrdrInfo = crmExtOrdrMapper.selectCrmExtOrdrInfo(vo);
//gcone 등록
if (extOrdrInfo != null) {
if (extOrdrInfo != null) {
for (TsExtOrdrVO extVO : extOrdrInfo) {
int result = mapper.insertExtOrdr(extVO);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,63 @@
package com.wb.domainserver.crm.tasklet;
import com.wb.domainserver.crm.vo.TsMemberAppnVO;
import com.wb.domainserver.mapper.gcone.MemberAppnMapper;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.scope.context.StepContext;
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
@JobScope
@Slf4j
public class InsertTsDelMbrAppnRegistTasklet implements Tasklet {
private static final Logger logger = LoggerFactory.getLogger(InsertTsRegMbrAppnRegistTasklet.class);
@Autowired
private MemberAppnMapper memberAppnMapper;
private StepExecution stepExecution;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
StepContext stepContext = StepSynchronizationManager.getContext();
System.out.println("==========================================");
System.out.println("MemberAppnLogDelTasklet 실행");
Map<String,Object> message = new HashMap<>();
try {
TsMemberAppnVO vo = new TsMemberAppnVO();
//삭제 로그 등록
memberAppnMapper.insertAppnLog(vo);
message.put("status", "1");
message.put("log_message", "GC_ERP_MEMBER_APPN_LOG 테이블에 insert 성공!!");
} catch (Exception e) {
e.printStackTrace();
message.put("status", "0");
message.put("message", "GC_ERP_MEMBER_APPN_LOG 테이블에 insert 실패!!");
}
stepContext = StepSynchronizationManager.getContext();
stepContext.getStepExecution().getExecutionContext().put("message", message);
System.out.println("MemberAppnLogDelTasklet 종료");
System.out.println("==========================================");
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,89 @@
package com.wb.domainserver.crm.tasklet;
import com.wb.domainserver.crm.vo.TsMemberAppnVO;
import com.wb.domainserver.mapper.gcone.MemberAppnMapper;
import com.wb.domainserver.mapper.mq.CrmMemberAppnMapper;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.scope.context.StepContext;
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
@JobScope
@Slf4j
public class InsertTsMbrAppnRegistTasklet implements Tasklet {
private static final Logger logger = LoggerFactory.getLogger(InsertTsMbrAppnRegistTasklet.class);
@Autowired
private MemberAppnMapper memberAppnMapper;
@Autowired
private CrmMemberAppnMapper crmMemberAppnMapper;
private StepExecution stepExecution;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
StepContext stepContext = StepSynchronizationManager.getContext();
System.out.println("==========================================");
System.out.println("MemberAppnLogTasklet 실행");
Map<String,Object> message = new HashMap<>();
try {
//1.erp 테이블 블랙리스트 조회
List<TsMemberAppnVO> rslrList = crmMemberAppnMapper.selectCrmRslrlistInqire();
//2. gcone 테이블에 구분자가 '03'인 데이터 삭제
memberAppnMapper.deleteRslrAppn();
//3. gc_member_appn 등록
List<String> appnInnbList = new ArrayList<>();
//2.gcone 테이블에 블랙리스트 등록
if(rslrList != null){
for (TsMemberAppnVO vo : rslrList) {
memberAppnMapper.insertRslrAppn(vo);
/*고유번호 get*/
appnInnbList.add(vo.getAppnInnb());
}
}
/*로그에 등록할 고유번호*/
message.put("appnInnbList",appnInnbList);
message.put("status", "1");
message.put("log_message", "GC_ERP_MEMBER_APPN 테이블에 insert 성공!!");
} catch (Exception e) {
e.printStackTrace();
message.put("status", "0");
message.put("message", "GC_ERP_MEMBER_APPN 실패!!");
}
stepContext = StepSynchronizationManager.getContext();
stepContext.getStepExecution().getExecutionContext().put("message", message);
System.out.println("MemberAppnLogTasklet 종료");
System.out.println("==========================================");
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,77 @@
package com.wb.domainserver.crm.tasklet;
import com.wb.domainserver.crm.vo.TsMemberAppnVO;
import com.wb.domainserver.mapper.gcone.MemberAppnMapper;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.scope.context.StepContext;
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
@JobScope
@Slf4j
public class InsertTsRegMbrAppnRegistTasklet implements Tasklet {
private static final Logger logger = LoggerFactory.getLogger(InsertTsRegMbrAppnRegistTasklet.class);
@Autowired
private MemberAppnMapper memberAppnMapper;
private StepExecution stepExecution;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
StepContext stepContext = StepSynchronizationManager.getContext();
Map<String, Object> message = (Map<String, Object>) stepContext.getStepExecution().getJobExecution().getExecutionContext().get("message");
System.out.println("로그 찍기 전 Step 결과: " + message);
System.out.println("==========================================");
System.out.println("InsertTsRegMbrAppnRegistTasklet 실행");
Map<String, Object> result = new HashMap<>();
try {
if(message != null){
List<String> appnInnbList = (List<String>) message.get("appnInnbList");
TsMemberAppnVO vo = new TsMemberAppnVO();
vo.setAppnInnbArr(appnInnbList);
memberAppnMapper.insertAppnLog(vo);
}
result.put("status", "1");
result.put("log_message", "GC_ERP_MEMBER_APPN_LOG 테이블에 등록 로그 insert 성공!!");
} catch (Exception e) {
e.printStackTrace();
result.put("status", "0");
result.put("message", "GC_ERP_MEMBER_APPN_LOG 등록 로그 insert 실패!!");
}
stepContext = StepSynchronizationManager.getContext();
stepContext.getStepExecution().getExecutionContext().put("message", result);
System.out.println("MemberAppnLogTasklet 종료");
System.out.println("==========================================");
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,52 @@
package com.wb.domainserver.crm.tasklet;
import com.wb.domainserver.crm.vo.TsExtOrdrVO;
import com.wb.domainserver.mapper.mq.CrmExtOrdrMapper;
import com.wb.domainserver.util.dataaccess.DataMap;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.scope.context.StepContext;
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
@JobScope
@Slf4j
public class SelectCrmExtOrdrInfoTasklet implements Tasklet {
private static final Logger logger = LoggerFactory.getLogger(InsertTsMbrAppnRegistTasklet.class);
private StepExecution stepExecution;
@Autowired
private CrmExtOrdrMapper crmExtOrdrMapper;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
StepContext stepContext = StepSynchronizationManager.getContext();
log.debug("상태확인 {}",stepContext.getStepExecution().getJobExecution().getExecutionContext());
DataMap map = (DataMap) stepContext.getStepExecution().getJobExecution().getExecutionContext().get("message");
Map<String, Object> message = new HashMap<>();
TsExtOrdrVO vo = new TsExtOrdrVO();
String maxInnb = (String) map.get("maxErpOrderInnb");
List<TsExtOrdrVO> extOrdrInfo = crmExtOrdrMapper.selectCrmExtOrdrInfo(vo);
message.put("extOrdrInfo",extOrdrInfo);
log.debug("extOrdrInfo 결과{}", extOrdrInfo);
log.debug("message 내용 {}", message);
stepContext.getStepExecution().getExecutionContext().put("message", message);
return RepeatStatus.FINISHED;
}
}

View File

@@ -0,0 +1,51 @@
package com.wb.domainserver.crm.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = false)
public class TsExtOrdrVO implements Serializable {
private static final long serialVersionUID = 1L;
/**외부주문고유번호(PK)*/
private String erpOrderInnb;
/**법인코드*/
private String cprCd;
/**브랜드코드*/
private String brandCd;
/**쇼핑몰구분*/
private String sopmalDv;
/**쇼핑몰*/
private String sopmal;
/**주문코드(번호)*/
private String ordrNb;
/**주문일시*/
private String ordrDt;
/**출고일시*/
private String dlivyDt;
/**휴대전화(숫자만)*/
private String mbtlnb;
/**이름*/
private String nm;
/**주소(상세주소제외)*/
private String adres;
/**전자우편(재확인용)*/
private String email;
/**메모*/
private String memo;
/**업로드작업그룹*/
private String uploadGroup;
/**등록일시*/
private String registDt;
/**수정일시*/
private String updtDt;
/*max 고유번호*/
private BigDecimal maxExtOrdrInnb;
}

View File

@@ -0,0 +1,46 @@
package com.wb.domainserver.crm.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = false)
public class TsMemberAppnVO implements Serializable {
private static final long serialVersionUID = 1L;
/**지정로그고유번호*/
private String appnLogInnb;
/**지정고유번호(PK)*/
private String appnInnb;
/**지정고유번호 배열*/
private List<String> appnInnbArr;
/**쇼핑몰코드(PK)*/
private String sopmalCd;
/**지정구분코드*/
private String appnDvCd;
/**식별기준코드*/
private String idntfcStdrCd;
/**식별정보(FK)*/
private String idntfcInfo;
/**메모*/
private String appnMemo;
/**등록자*/
private String regusr;
/**수정자*/
private String updusr;
/*등록일자*/
private String registDt;
}

View File

@@ -0,0 +1,44 @@
package com.wb.domainserver.ep.form;
public class GoogleEpForm {
public static String googleEpForm(){
return """
<rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">
<script/>
<script/>
<script/>
<channel>
<title>#TITLE#</title>
<link>#LINK#</link>
<description>#DESCRIPTION#</description>
""";
}
public static String googleEpItemForm(){
return """
<item>
<g:id>#GOODS_INNB#</g:id>
<g:title>#GOODS_NM#</g:title>
<g:description>#REPRSNT_DC#</g:description>
<g:link>#PC_GOODS_LINK#</g:link>
<g:image_link>#IMG#</g:image_link>
<g:price>#PRICE#</g:price>
<g:sale_price>#SALE_PRICE#</g:sale_price>
<g:product_type>#PRODUCT_TYPE#</g:product_type>
<g:brand>#BRAND#</g:brand>
<g:condition>new</g:condition>
<g:availability>#IN_STOCK#</g:availability>
</item>
""";
}
public static String googleEpEndForm(){
return """
</channel>
</rss>
""";
}
}

View File

@@ -0,0 +1,43 @@
package com.wb.domainserver.ep.form;
public class MetaEpForm {
public static String metaEpForm(){
return """
<rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">
<script/>
<script/>
<script/>
<channel>
<title>#TITLE#</title>
<link>#LINK#</link>
<description>#DESCRIPTION#</description>
""";
}
public static String metaEpItemForm(){
return """
<item>
<g:id>#GOODS_INNB#</g:id>
<g:title>#GOODS_NM#</g:title>
<g:description>#REPRSNT_DC#</g:description>
<g:link>#PC_GOODS_LINK#</g:link>
<g:image_link>#IMG#</g:image_link>
<g:price>#PRICE#</g:price>
<g:sale_price>#SALE_PRICE#</g:sale_price>
<g:brand>#BRAND#</g:brand>
<g:condition>new</g:condition>
<g:availability>#IN_STOCK#</g:availability>
</item>
""";
}
public static String metaEpEndForm(){
return """
</channel>
</rss>
""";
}
}

View File

@@ -0,0 +1,70 @@
package com.wb.domainserver.ep.form;
public class MobionEpForm {
public static String mobionEpForm(){
return """
<products>
<script/>
<script/>
<script/>
""";
}
public static String mobionEpItemForm(){
return """
<product id="#GOODS_INNB#">
<title>
<![CDATA[ #GOODS_NM# ]]>
</title>
<price_pc>
<![CDATA[ #PRICE_PC# ]]>
</price_pc>
<price_mobile>
<![CDATA[ #PRICE_MOBILE# ]]>
</price_mobile>
<normal_price>
<![CDATA[ #NORMAL_PRICE# ]]>
</normal_price>
<link>
<![CDATA[ #LINK# ]]>
</link>
<mobile_link>
<![CDATA[ #MOBILE_LINK# ]]>
</mobile_link>
<image_link1>
<![CDATA[ #IMAGE_LINK1# ]]>
</image_link1>
<image_link2>
<![CDATA[ #IMAGE_LINK2# ]]>
</image_link2>
<image_link3>
<![CDATA[ #IMAGE_LINK3# ]]>
</image_link3>
<image_link4>
<![CDATA[ #IMAGE_LINK4# ]]>
</image_link4>
<category_name1>
<![CDATA[ #CATEGORY_NAME1# ]]>
</category_name1>
<category_name2>
<![CDATA[ #CATEGORY_NAME2# ]]>
</category_name2>
<category_name3>
<![CDATA[ #CATEGORY_NAME3# ]]>
</category_name3>
<category_name4>
<![CDATA[ #CATEGORY_NAME4# ]]>
</category_name4>
</product>
""";
}
public static String mobionEpEndForm(){
return """
</products>
""";
}
}

View File

@@ -0,0 +1,15 @@
package com.wb.domainserver.ep.form;
import lombok.Data;
@Data
public class NaverEpForm {
public String naverEpFormHeader(){
return """
id title price_pc price_mobile normal_price link mobile_link image_link add_image_link category_name1 category_name2 category_name3 category_name4 naver_category naver_product_id condition import_flag parallel_import order_made product_flag adult goods_type barcode manufacture_define_number model_number brand maker origin card_event event_words coupon partner_coupon_download interest_free_event point installation_costs pre_match_code search_tag group_id vendor_id coordi_id minimum_purchase_quantity review_count shipping delivery_grade delivery_detail attribute option_detail seller_id age_group gender
""";
}
}

View File

@@ -0,0 +1,80 @@
package com.wb.domainserver.ep.jobs;
import com.wb.domainserver.ep.tasklet.GoogleEpTasklet;
import com.wb.domainserver.ep.tasklet.MetaEpTasklet;
import com.wb.domainserver.ep.tasklet.MobionEpTasklet;
import com.wb.domainserver.ep.tasklet.NaverEpTasklet;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration
@RequiredArgsConstructor
@Slf4j
public class EpConfig extends DefaultBatchConfiguration{
private final GoogleEpTasklet googleEpTasklet;
private final MetaEpTasklet metaEpTasklet;
private final NaverEpTasklet naverEpTasklet;
private final MobionEpTasklet mobionEpTasklet;
@Bean
public Job epJob(JobRepository jobRepository
, Step googleEpStep
, Step metaEpStep
, Step naverEpStep
, Step mobionEpStep
) {
return new JobBuilder("epJob", jobRepository)
.incrementer(new RunIdIncrementer())
.start(googleEpStep)
.next(metaEpStep)
.next(naverEpStep)
.next(mobionEpStep)
.build();
}
@Bean
@JobScope
public Step googleEpStep(JobRepository jobRepository, PlatformTransactionManager platformTransactionManager) {
return new StepBuilder("googleEpStep", jobRepository)
.tasklet(googleEpTasklet, platformTransactionManager)
.build();
}
@Bean
@JobScope
public Step metaEpStep(JobRepository jobRepository, PlatformTransactionManager platformTransactionManager) {
return new StepBuilder("metaEpStep", jobRepository)
.tasklet(metaEpTasklet, platformTransactionManager)
.build();
}
@Bean
@JobScope
public Step naverEpStep(JobRepository jobRepository, PlatformTransactionManager platformTransactionManager) {
return new StepBuilder("naverEpStep", jobRepository)
.tasklet(naverEpTasklet, platformTransactionManager)
.build();
}
@Bean
@JobScope
public Step mobionEpStep(JobRepository jobRepository, PlatformTransactionManager platformTransactionManager) {
return new StepBuilder("mobionEpStep", jobRepository)
.tasklet(mobionEpTasklet, platformTransactionManager)
.build();
}
}

View File

@@ -0,0 +1,97 @@
package com.wb.domainserver.ep.tasklet;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.util.HashSet;
import java.util.Set;
@Slf4j
public abstract class AbstractEpTasklet {
/**
* EP 데이터 생성 후 파일 쓰기
* @param epData EP 데이터
* @param sopmalCd EP 대상 쇼핑몰
* @return
*/
protected void createEpFile(String epData, String sopmalCd, String epPath, String fileNm, String ext){
// 루트 경로에서 시작하는 디렉토리 경로 (OS에 따라 경로 분리)
// String uploaddirsPath = FileSystems.getDefault().getSeparator(); // root에서 시작
Path directory = Paths.get(epPath, sopmalCd, "ep").toAbsolutePath().normalize();
// 생성할 파일의 경로
Path filePath = directory.resolve(fileNm+ext);
log.debug("directory :::: {}", directory);
log.debug("filePath :: {}", filePath);
//디렉토리 생성
try {
Files.createDirectories(directory);
} catch (IOException ioe) {
log.error("create ep directory err {}", ioe.getMessage());
}
//파일생성
File epfile = new File(filePath.toString());
//파일 생성 기존에 있을경우 삭제후 빈파일 생성
try( FileOutputStream fos = new FileOutputStream(epfile, false)){
//파일 쓰기
String epFileData ="";
//xml 파일 일경우 xml 태그 추가하고 &를 &amp;로 치환
if(".xml".equals(ext)){
epFileData = "<?xml version='1.0'?> \n"+epData.replace("&", "&amp;");
}else{
epFileData = epData;
}
fos.write(epFileData.getBytes(StandardCharsets.UTF_8));
log.debug("파일 작성 완료: {}" , epfile.getAbsolutePath());
// 리눅스/유닉스 계열 OS일 경우 파일 읽기/쓰기 권한 부여
if (System.getProperty("os.name").toLowerCase().contains("nix") ||
System.getProperty("os.name").toLowerCase().contains("nux")) {
// 읽기/쓰기 권한을 설정
Set<PosixFilePermission> perms = new HashSet<>();
perms.add(PosixFilePermission.OWNER_READ);
perms.add(PosixFilePermission.OWNER_WRITE);
perms.add(PosixFilePermission.GROUP_READ);
perms.add(PosixFilePermission.GROUP_WRITE);
// 파일에 권한 적용
Files.setPosixFilePermissions(filePath, perms);
log.error("리눅스/유닉스 계열 OS에서 파일 권한 설정 완료.");
}
} catch (UnsupportedOperationException e) {
// 만약 OS가 Posix 파일 권한을 지원하지 않는다면
log.error("POSIX 파일 시스템이 아닌 OS입니다: " + e.getMessage());
}catch (FileNotFoundException fne){
log.error("create ep file directory notFound error {}", fne.getMessage());
}
catch (IOException ie){
log.error("create ep file error {}", ie.getMessage());
}catch (Exception e){
log.error("create ep file error", e);
}
}
}

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