first Commit!!!
This commit is contained in:
21
.vscode/launch.json
vendored
Normal file
21
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "java",
|
||||||
|
"name": "BatchQuartzApplication",
|
||||||
|
"request": "launch",
|
||||||
|
"mainClass": "com.spring.BatchQuartzApplication",
|
||||||
|
"projectName": "batch-quartz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "java",
|
||||||
|
"name": "Spring Boot-BatchQuartzApplication<batch-quartz>",
|
||||||
|
"request": "launch",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"mainClass": "com.spring.batch_quartz.BatchQuartzApplication",
|
||||||
|
"projectName": "batch-quartz",
|
||||||
|
"args": "",
|
||||||
|
"envFile": "${workspaceFolder}/.env"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
51
.vscode/settings.json
vendored
Normal file
51
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"java.compile.nullAnalysis.mode": "automatic",
|
||||||
|
"cSpell.words": [
|
||||||
|
"attachfile",
|
||||||
|
"Autowire",
|
||||||
|
"cdate",
|
||||||
|
"checkin",
|
||||||
|
"classpath",
|
||||||
|
"Configurer",
|
||||||
|
"CTNOPS",
|
||||||
|
"dbcode",
|
||||||
|
"Embeddable",
|
||||||
|
"Grps",
|
||||||
|
"Hikari",
|
||||||
|
"ibatis",
|
||||||
|
"insertable",
|
||||||
|
"issecure",
|
||||||
|
"JDBC",
|
||||||
|
"jdbcjobstore",
|
||||||
|
"jsonwebtoken",
|
||||||
|
"Jwts",
|
||||||
|
"lastflg",
|
||||||
|
"Mailque",
|
||||||
|
"Mailrst",
|
||||||
|
"mailtypename",
|
||||||
|
"mindol",
|
||||||
|
"Mybatis",
|
||||||
|
"Mybtis",
|
||||||
|
"nxcus",
|
||||||
|
"Qrtz",
|
||||||
|
"RCODE",
|
||||||
|
"rmail",
|
||||||
|
"RMSG",
|
||||||
|
"RNAME",
|
||||||
|
"RPOS",
|
||||||
|
"rscode",
|
||||||
|
"rsdetmsg",
|
||||||
|
"rsmsg",
|
||||||
|
"rstime",
|
||||||
|
"sched",
|
||||||
|
"sdate",
|
||||||
|
"securetemplate",
|
||||||
|
"Servlet",
|
||||||
|
"Simprop",
|
||||||
|
"smail",
|
||||||
|
"sname",
|
||||||
|
"stime",
|
||||||
|
"subid"
|
||||||
|
],
|
||||||
|
"java.debug.settings.onBuildFailureProceed": true
|
||||||
|
}
|
||||||
33
batch-quartz/.gitignore
vendored
Normal file
33
batch-quartz/.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
HELP.md
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
19
batch-quartz/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
19
batch-quartz/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you 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.
|
||||||
|
wrapperVersion=3.3.2
|
||||||
|
distributionType=only-script
|
||||||
|
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.7/apache-maven-3.9.7-bin.zip
|
||||||
259
batch-quartz/mvnw
vendored
Normal file
259
batch-quartz/mvnw
vendored
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you 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.
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Apache Maven Wrapper startup batch script, version 3.3.2
|
||||||
|
#
|
||||||
|
# Optional ENV vars
|
||||||
|
# -----------------
|
||||||
|
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
|
||||||
|
# MVNW_REPOURL - repo url base for downloading maven distribution
|
||||||
|
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||||
|
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
set -euf
|
||||||
|
[ "${MVNW_VERBOSE-}" != debug ] || set -x
|
||||||
|
|
||||||
|
# OS specific support.
|
||||||
|
native_path() { printf %s\\n "$1"; }
|
||||||
|
case "$(uname)" in
|
||||||
|
CYGWIN* | MINGW*)
|
||||||
|
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
|
||||||
|
native_path() { cygpath --path --windows "$1"; }
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# set JAVACMD and JAVACCMD
|
||||||
|
set_java_home() {
|
||||||
|
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
|
||||||
|
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"
|
||||||
|
JAVACCMD="$JAVA_HOME/jre/sh/javac"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
JAVACCMD="$JAVA_HOME/bin/javac"
|
||||||
|
|
||||||
|
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
|
||||||
|
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
|
||||||
|
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="$(
|
||||||
|
'set' +e
|
||||||
|
'unset' -f command 2>/dev/null
|
||||||
|
'command' -v java
|
||||||
|
)" || :
|
||||||
|
JAVACCMD="$(
|
||||||
|
'set' +e
|
||||||
|
'unset' -f command 2>/dev/null
|
||||||
|
'command' -v javac
|
||||||
|
)" || :
|
||||||
|
|
||||||
|
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
|
||||||
|
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# hash string like Java String::hashCode
|
||||||
|
hash_string() {
|
||||||
|
str="${1:-}" h=0
|
||||||
|
while [ -n "$str" ]; do
|
||||||
|
char="${str%"${str#?}"}"
|
||||||
|
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
|
||||||
|
str="${str#?}"
|
||||||
|
done
|
||||||
|
printf %x\\n $h
|
||||||
|
}
|
||||||
|
|
||||||
|
verbose() { :; }
|
||||||
|
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
|
||||||
|
|
||||||
|
die() {
|
||||||
|
printf %s\\n "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
trim() {
|
||||||
|
# MWRAPPER-139:
|
||||||
|
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
|
||||||
|
# Needed for removing poorly interpreted newline sequences when running in more
|
||||||
|
# exotic environments such as mingw bash on Windows.
|
||||||
|
printf "%s" "${1}" | tr -d '[:space:]'
|
||||||
|
}
|
||||||
|
|
||||||
|
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
|
||||||
|
while IFS="=" read -r key value; do
|
||||||
|
case "${key-}" in
|
||||||
|
distributionUrl) distributionUrl=$(trim "${value-}") ;;
|
||||||
|
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
|
||||||
|
esac
|
||||||
|
done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
|
||||||
|
case "${distributionUrl##*/}" in
|
||||||
|
maven-mvnd-*bin.*)
|
||||||
|
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
|
||||||
|
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
|
||||||
|
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
|
||||||
|
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
|
||||||
|
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
|
||||||
|
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
|
||||||
|
*)
|
||||||
|
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
|
||||||
|
distributionPlatform=linux-amd64
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
|
||||||
|
;;
|
||||||
|
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
|
||||||
|
*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||||
|
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||||
|
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
|
||||||
|
distributionUrlName="${distributionUrl##*/}"
|
||||||
|
distributionUrlNameMain="${distributionUrlName%.*}"
|
||||||
|
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
|
||||||
|
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
|
||||||
|
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
|
||||||
|
|
||||||
|
exec_maven() {
|
||||||
|
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
|
||||||
|
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -d "$MAVEN_HOME" ]; then
|
||||||
|
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||||
|
exec_maven "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${distributionUrl-}" in
|
||||||
|
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
|
||||||
|
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# prepare tmp dir
|
||||||
|
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
|
||||||
|
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
|
||||||
|
trap clean HUP INT TERM EXIT
|
||||||
|
else
|
||||||
|
die "cannot create temp dir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p -- "${MAVEN_HOME%/*}"
|
||||||
|
|
||||||
|
# Download and Install Apache Maven
|
||||||
|
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||||
|
verbose "Downloading from: $distributionUrl"
|
||||||
|
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
|
||||||
|
# select .zip or .tar.gz
|
||||||
|
if ! command -v unzip >/dev/null; then
|
||||||
|
distributionUrl="${distributionUrl%.zip}.tar.gz"
|
||||||
|
distributionUrlName="${distributionUrl##*/}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# verbose opt
|
||||||
|
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
|
||||||
|
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
|
||||||
|
|
||||||
|
# normalize http auth
|
||||||
|
case "${MVNW_PASSWORD:+has-password}" in
|
||||||
|
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||||
|
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
|
||||||
|
verbose "Found wget ... using wget"
|
||||||
|
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
|
||||||
|
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
|
||||||
|
verbose "Found curl ... using curl"
|
||||||
|
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
|
||||||
|
elif set_java_home; then
|
||||||
|
verbose "Falling back to use Java to download"
|
||||||
|
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
|
||||||
|
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
cat >"$javaSource" <<-END
|
||||||
|
public class Downloader extends java.net.Authenticator
|
||||||
|
{
|
||||||
|
protected java.net.PasswordAuthentication getPasswordAuthentication()
|
||||||
|
{
|
||||||
|
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
|
||||||
|
}
|
||||||
|
public static void main( String[] args ) throws Exception
|
||||||
|
{
|
||||||
|
setDefault( new Downloader() );
|
||||||
|
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END
|
||||||
|
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
|
||||||
|
verbose " - Compiling Downloader.java ..."
|
||||||
|
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
|
||||||
|
verbose " - Running Downloader.java ..."
|
||||||
|
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||||
|
if [ -n "${distributionSha256Sum-}" ]; then
|
||||||
|
distributionSha256Result=false
|
||||||
|
if [ "$MVN_CMD" = mvnd.sh ]; then
|
||||||
|
echo "Checksum validation is not supported for maven-mvnd." >&2
|
||||||
|
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||||
|
exit 1
|
||||||
|
elif command -v sha256sum >/dev/null; then
|
||||||
|
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
|
||||||
|
distributionSha256Result=true
|
||||||
|
fi
|
||||||
|
elif command -v shasum >/dev/null; then
|
||||||
|
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
|
||||||
|
distributionSha256Result=true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
|
||||||
|
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ $distributionSha256Result = false ]; then
|
||||||
|
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
|
||||||
|
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# unzip and move
|
||||||
|
if command -v unzip >/dev/null; then
|
||||||
|
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
|
||||||
|
else
|
||||||
|
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
|
||||||
|
fi
|
||||||
|
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
|
||||||
|
mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
|
||||||
|
|
||||||
|
clean || :
|
||||||
|
exec_maven "$@"
|
||||||
149
batch-quartz/mvnw.cmd
vendored
Normal file
149
batch-quartz/mvnw.cmd
vendored
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
<# : batch portion
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
@REM or more contributor license agreements. See the NOTICE file
|
||||||
|
@REM distributed with this work for additional information
|
||||||
|
@REM regarding copyright ownership. The ASF licenses this file
|
||||||
|
@REM to you under the Apache License, Version 2.0 (the
|
||||||
|
@REM "License"); you may not use this file except in compliance
|
||||||
|
@REM with the License. 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,
|
||||||
|
@REM software distributed under the License is distributed on an
|
||||||
|
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
@REM KIND, either express or implied. See the License for the
|
||||||
|
@REM specific language governing permissions and limitations
|
||||||
|
@REM under the License.
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Apache Maven Wrapper startup batch script, version 3.3.2
|
||||||
|
@REM
|
||||||
|
@REM Optional ENV vars
|
||||||
|
@REM MVNW_REPOURL - repo url base for downloading maven distribution
|
||||||
|
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||||
|
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
|
||||||
|
@SET __MVNW_CMD__=
|
||||||
|
@SET __MVNW_ERROR__=
|
||||||
|
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
|
||||||
|
@SET PSModulePath=
|
||||||
|
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
|
||||||
|
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
|
||||||
|
)
|
||||||
|
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
|
||||||
|
@SET __MVNW_PSMODULEP_SAVE=
|
||||||
|
@SET __MVNW_ARG0_NAME__=
|
||||||
|
@SET MVNW_USERNAME=
|
||||||
|
@SET MVNW_PASSWORD=
|
||||||
|
@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
|
||||||
|
@echo Cannot start maven from wrapper >&2 && exit /b 1
|
||||||
|
@GOTO :EOF
|
||||||
|
: end batch / begin powershell #>
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
if ($env:MVNW_VERBOSE -eq "true") {
|
||||||
|
$VerbosePreference = "Continue"
|
||||||
|
}
|
||||||
|
|
||||||
|
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
|
||||||
|
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
|
||||||
|
if (!$distributionUrl) {
|
||||||
|
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
|
||||||
|
"maven-mvnd-*" {
|
||||||
|
$USE_MVND = $true
|
||||||
|
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
|
||||||
|
$MVN_CMD = "mvnd.cmd"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
$USE_MVND = $false
|
||||||
|
$MVN_CMD = $script -replace '^mvnw','mvn'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||||
|
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||||
|
if ($env:MVNW_REPOURL) {
|
||||||
|
$MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
|
||||||
|
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
|
||||||
|
}
|
||||||
|
$distributionUrlName = $distributionUrl -replace '^.*/',''
|
||||||
|
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
|
||||||
|
$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
|
||||||
|
if ($env:MAVEN_USER_HOME) {
|
||||||
|
$MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
|
||||||
|
}
|
||||||
|
$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
|
||||||
|
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
|
||||||
|
|
||||||
|
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
|
||||||
|
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||||
|
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||||
|
exit $?
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
|
||||||
|
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
|
||||||
|
}
|
||||||
|
|
||||||
|
# prepare tmp dir
|
||||||
|
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
|
||||||
|
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
|
||||||
|
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
|
||||||
|
trap {
|
||||||
|
if ($TMP_DOWNLOAD_DIR.Exists) {
|
||||||
|
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||||
|
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
|
||||||
|
|
||||||
|
# Download and Install Apache Maven
|
||||||
|
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||||
|
Write-Verbose "Downloading from: $distributionUrl"
|
||||||
|
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
|
||||||
|
$webclient = New-Object System.Net.WebClient
|
||||||
|
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
|
||||||
|
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
|
||||||
|
}
|
||||||
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
|
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
|
||||||
|
|
||||||
|
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||||
|
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
|
||||||
|
if ($distributionSha256Sum) {
|
||||||
|
if ($USE_MVND) {
|
||||||
|
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
|
||||||
|
}
|
||||||
|
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
|
||||||
|
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
|
||||||
|
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# unzip and move
|
||||||
|
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
|
||||||
|
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
|
||||||
|
try {
|
||||||
|
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
|
||||||
|
} catch {
|
||||||
|
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
|
||||||
|
Write-Error "fail to move MAVEN_HOME"
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||||
|
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||||
132
batch-quartz/pom.xml
Normal file
132
batch-quartz/pom.xml
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>3.3.2</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>com.spring</groupId>
|
||||||
|
<artifactId>batch-quartz</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>batch-quartz</name>
|
||||||
|
<description>Demo project for Spring Boot</description>
|
||||||
|
<url/>
|
||||||
|
<licenses>
|
||||||
|
<license/>
|
||||||
|
</licenses>
|
||||||
|
<developers>
|
||||||
|
<developer/>
|
||||||
|
</developers>
|
||||||
|
<scm>
|
||||||
|
<connection/>
|
||||||
|
<developerConnection/>
|
||||||
|
<tag/>
|
||||||
|
<url/>
|
||||||
|
</scm>
|
||||||
|
<properties>
|
||||||
|
<java.version>17</java.version>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-batch</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mybatis.spring.boot</groupId>
|
||||||
|
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||||
|
<version>3.0.3</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-quartz</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-api</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-impl</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-jackson</artifactId>
|
||||||
|
<version>0.11.5</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.batch</groupId>
|
||||||
|
<artifactId>spring-batch-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<excludes>
|
||||||
|
<exclude>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</exclude>
|
||||||
|
</excludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.spring;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@ConfigurationPropertiesScan
|
||||||
|
public class BatchQuartzApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(BatchQuartzApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.spring.common.error;
|
||||||
|
|
||||||
|
public class BizException extends RuntimeException {
|
||||||
|
|
||||||
|
public BizException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package com.spring.domain.batch.entity;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.ForeignKey;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "BATCH_JOB_EXECUTION")
|
||||||
|
@Getter
|
||||||
|
public class BatchJobExecution {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "JOB_EXECUTION_ID")
|
||||||
|
private Long jobExecutionId;
|
||||||
|
|
||||||
|
@Column(name = "VERSION")
|
||||||
|
private Long version;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "JOB_INSTANCE_ID", nullable = false, foreignKey = @ForeignKey(name = "JOB_INST_EXEC_FK"))
|
||||||
|
private BatchJobInstance batchJobInstance;
|
||||||
|
|
||||||
|
@Column(name = "CREATE_TIME", nullable = false)
|
||||||
|
private Timestamp createTime;
|
||||||
|
|
||||||
|
@Column(name = "START_TIME")
|
||||||
|
private Timestamp startTime;
|
||||||
|
|
||||||
|
@Column(name = "END_TIME")
|
||||||
|
private Timestamp endTime;
|
||||||
|
|
||||||
|
@Column(name = "STATUS", length = 10)
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
@Column(name = "EXIT_CODE", length = 2500)
|
||||||
|
private String exitCode;
|
||||||
|
|
||||||
|
@Column(name = "EXIT_MESSAGE", length = 2500)
|
||||||
|
private String exitMessage;
|
||||||
|
|
||||||
|
@Column(name = "LAST_UPDATED")
|
||||||
|
private Timestamp lastUpdated;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.spring.domain.batch.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.ForeignKey;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.OneToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "BATCH_JOB_EXECUTION_CONTEXT")
|
||||||
|
@Getter
|
||||||
|
public class BatchJobExecutionContext {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "JOB_EXECUTION_ID")
|
||||||
|
private Long jobExecutionId;
|
||||||
|
|
||||||
|
@Column(name = "SHORT_CONTEXT", length = 2500, nullable = false)
|
||||||
|
private String shortContext;
|
||||||
|
|
||||||
|
@Column(name = "SERIALIZED_CONTEXT")
|
||||||
|
private String serializedContext;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "JOB_EXECUTION_ID", insertable = false, updatable = false, foreignKey = @ForeignKey(name = "JOB_EXEC_CTX_FK"))
|
||||||
|
private BatchJobExecution batchJobExecution;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.spring.domain.batch.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.EmbeddedId;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.ForeignKey;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "BATCH_JOB_EXECUTION_PARAMS")
|
||||||
|
@Getter
|
||||||
|
public class BatchJobExecutionParams {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private BatchJobExecutionParamsId id;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "JOB_EXECUTION_ID", insertable = false, updatable = false, foreignKey = @ForeignKey(name = "JOB_EXEC_PARAMS_FK"))
|
||||||
|
private BatchJobExecution jobExecution;
|
||||||
|
|
||||||
|
@Column(name = "PARAMETER_TYPE", nullable = false)
|
||||||
|
private String parameterType;
|
||||||
|
|
||||||
|
@Column(name = "PARAMETER_VALUE", length = 2500)
|
||||||
|
private String parameterValue;
|
||||||
|
|
||||||
|
@Column(name = "IDENTIFYING", nullable = false)
|
||||||
|
private Character identifying;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public class BatchJobExecutionParamsId implements Serializable {
|
||||||
|
@Column(name = "JOB_EXECUTION_ID")
|
||||||
|
private Long jobExecutionId;
|
||||||
|
|
||||||
|
@Column(name = "PARAMETER_NAME")
|
||||||
|
private String parameterName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.spring.domain.batch.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import jakarta.persistence.UniqueConstraint;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "BATCH_JOB_INSTANCE",
|
||||||
|
uniqueConstraints = @UniqueConstraint(name = "JOB_INST_UN", columnNames = {"JOB_NAME", "JOB_KEY"}))
|
||||||
|
@Getter
|
||||||
|
public class BatchJobInstance {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "JOB_INSTANCE_ID")
|
||||||
|
private Long jobInstanceId;
|
||||||
|
|
||||||
|
@Column(name = "VERSION")
|
||||||
|
private Long version;
|
||||||
|
|
||||||
|
@Column(name = "JOB_NAME", length = 100, nullable = false)
|
||||||
|
private String jobName;
|
||||||
|
|
||||||
|
@Column(name = "JOB_KEY", length = 32, nullable = false)
|
||||||
|
private String jobKey;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package com.spring.domain.batch.entity;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.ForeignKey;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "BATCH_STEP_EXECUTION")
|
||||||
|
@Getter
|
||||||
|
public class BatchStepExecution {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "STEP_EXECUTION_ID")
|
||||||
|
private Long stepExecutionId;
|
||||||
|
|
||||||
|
@Column(name = "VERSION", nullable = false)
|
||||||
|
private Long version;
|
||||||
|
|
||||||
|
@Column(name = "STEP_NAME", length = 100, nullable = false)
|
||||||
|
private String stepName;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "JOB_EXECUTION_ID", nullable = false, foreignKey = @ForeignKey(name = "JOB_EXEC_STEP_FK"))
|
||||||
|
private BatchJobExecution batchJobExecution;
|
||||||
|
|
||||||
|
@Column(name = "CREATE_TIME", nullable = false)
|
||||||
|
private Timestamp createTime;
|
||||||
|
|
||||||
|
@Column(name = "START_TIME")
|
||||||
|
private Timestamp startTime;
|
||||||
|
|
||||||
|
@Column(name = "END_TIME")
|
||||||
|
private Timestamp endTime;
|
||||||
|
|
||||||
|
@Column(name = "STATUS", length = 10)
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
@Column(name = "COMMIT_COUNT")
|
||||||
|
private Long commitCount;
|
||||||
|
|
||||||
|
@Column(name = "READ_COUNT")
|
||||||
|
private Long readCount;
|
||||||
|
|
||||||
|
@Column(name = "FILTER_COUNT")
|
||||||
|
private Long filterCount;
|
||||||
|
|
||||||
|
@Column(name = "WRITE_COUNT")
|
||||||
|
private Long writeCount;
|
||||||
|
|
||||||
|
@Column(name = "READ_SKIP_COUNT")
|
||||||
|
private Long readSkipCount;
|
||||||
|
|
||||||
|
@Column(name = "WRITE_SKIP_COUNT")
|
||||||
|
private Long writeSkipCount;
|
||||||
|
|
||||||
|
@Column(name = "PROCESS_SKIP_COUNT")
|
||||||
|
private Long processSkipCount;
|
||||||
|
|
||||||
|
@Column(name = "ROLLBACK_COUNT")
|
||||||
|
private Long rollbackCount;
|
||||||
|
|
||||||
|
@Column(name = "EXIT_CODE", length = 2500)
|
||||||
|
private String exitCode;
|
||||||
|
|
||||||
|
@Column(name = "EXIT_MESSAGE", length = 2500)
|
||||||
|
private String exitMessage;
|
||||||
|
|
||||||
|
@Column(name = "LAST_UPDATED")
|
||||||
|
private Timestamp lastUpdated;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.spring.domain.batch.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.ForeignKey;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.OneToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "BATCH_STEP_EXECUTION_CONTEXT")
|
||||||
|
@Getter
|
||||||
|
public class BatchStepExecutionContext {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "STEP_EXECUTION_ID")
|
||||||
|
private Long stepExecutionId;
|
||||||
|
|
||||||
|
@Column(name = "SHORT_CONTEXT", length = 2500, nullable = false)
|
||||||
|
private String shortContext;
|
||||||
|
|
||||||
|
@Column(name = "SERIALIZED_CONTEXT")
|
||||||
|
private String serializedContext;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "STEP_EXECUTION_ID", insertable = false, updatable = false, foreignKey = @ForeignKey(name = "STEP_EXEC_CTX_FK"))
|
||||||
|
private BatchStepExecution batchStepExecution;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package com.spring.domain.email.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.IdClass;
|
||||||
|
import jakarta.persistence.Lob;
|
||||||
|
import jakarta.persistence.SequenceGenerator;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@SequenceGenerator(
|
||||||
|
name = "COM_MAILQUE_MST_SEQ",
|
||||||
|
sequenceName = "COM_MAILQUE_MST_SEQ",
|
||||||
|
initialValue = 1,
|
||||||
|
allocationSize = 1
|
||||||
|
)
|
||||||
|
@Entity
|
||||||
|
@Table(name = "COM_MAILQUE_MST")
|
||||||
|
@IdClass(com.spring.domain.email.entity.ComMailqueMst.ComMailqueMstId.class)
|
||||||
|
public class ComMailqueMst {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "COM_MAILQUE_MST_SEQ")
|
||||||
|
@Column(name = "MID", nullable = false)
|
||||||
|
private Long mid;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "SUBID", nullable = false)
|
||||||
|
private Long subid;
|
||||||
|
|
||||||
|
@Column(name = "TID", nullable = false, length = 10)
|
||||||
|
private String tid;
|
||||||
|
|
||||||
|
@Column(name = "MAILTYPENAME", length = 25)
|
||||||
|
private String mailtypename;
|
||||||
|
|
||||||
|
@Column(name = "SNAME", nullable = false, length = 50)
|
||||||
|
private String sname;
|
||||||
|
|
||||||
|
@Column(name = "SMAIL", nullable = false, length = 100)
|
||||||
|
private String smail;
|
||||||
|
|
||||||
|
@Column(name = "SID", length = 50)
|
||||||
|
private String sid;
|
||||||
|
|
||||||
|
@Column(name = "RPOS", nullable = false, length = 1)
|
||||||
|
private Character rpos;
|
||||||
|
|
||||||
|
@Column(name = "QUERY", length = 2000)
|
||||||
|
private String query;
|
||||||
|
|
||||||
|
@Column(name = "CTNOPS", length = 1)
|
||||||
|
private String ctnops;
|
||||||
|
|
||||||
|
@Column(name = "SUBJECT", length = 100)
|
||||||
|
private String subject;
|
||||||
|
|
||||||
|
@Lob
|
||||||
|
@Column(name = "CONTENTS")
|
||||||
|
private String contents;
|
||||||
|
|
||||||
|
@Column(name = "CDATE")
|
||||||
|
private LocalDate cdate;
|
||||||
|
|
||||||
|
@Column(name = "SDATE")
|
||||||
|
private LocalDate sdate;
|
||||||
|
|
||||||
|
@Column(name = "STATUS", length = 1)
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
@Column(name = "DBCODE", length = 10)
|
||||||
|
private String dbcode;
|
||||||
|
|
||||||
|
@Column(name = "CHARSET")
|
||||||
|
private Integer charset;
|
||||||
|
|
||||||
|
@Column(name = "ISSECURE", length = 1)
|
||||||
|
private String issecure;
|
||||||
|
|
||||||
|
@Column(name = "SECURETEMPLATE", length = 50)
|
||||||
|
private String securetemplate;
|
||||||
|
|
||||||
|
@Column(name = "ATTACHFILE01", length = 255)
|
||||||
|
private String attachfile01;
|
||||||
|
|
||||||
|
@Column(name = "ATTACHFILE02", length = 255)
|
||||||
|
private String attachfile02;
|
||||||
|
|
||||||
|
@Column(name = "ATTACHFILE03", length = 255)
|
||||||
|
private String attachfile03;
|
||||||
|
|
||||||
|
@Column(name = "ATTACHFILE04", length = 255)
|
||||||
|
private String attachfile04;
|
||||||
|
|
||||||
|
@Column(name = "ATTACHFILE05", length = 255)
|
||||||
|
private String attachfile05;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public static class ComMailqueMstId implements Serializable {
|
||||||
|
private Long mid;
|
||||||
|
private Long subid;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package com.spring.domain.email.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.EmbeddedId;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Entity
|
||||||
|
@Table(name = "COM_MAILRST_LOG")
|
||||||
|
public class ComMailrstLog {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private ComMailrstLogId id;
|
||||||
|
|
||||||
|
@Column(name = "TID", nullable = false, length = 20)
|
||||||
|
private String tid;
|
||||||
|
|
||||||
|
@Column(name = "RNAME", length = 50)
|
||||||
|
private String rname;
|
||||||
|
|
||||||
|
@Column(name = "SID", length = 50)
|
||||||
|
private String sid;
|
||||||
|
|
||||||
|
@Column(name = "SNAME", nullable = false, length = 50)
|
||||||
|
private String sname;
|
||||||
|
|
||||||
|
@Column(name = "SMAIL", nullable = false, length = 100)
|
||||||
|
private String smail;
|
||||||
|
|
||||||
|
@Column(name = "RCODE", nullable = false, length = 2)
|
||||||
|
private Character rcode;
|
||||||
|
|
||||||
|
@Column(name = "RMSG", length = 100)
|
||||||
|
private String rmsg;
|
||||||
|
|
||||||
|
@Column(name = "STIME", nullable = false)
|
||||||
|
private LocalDate stime;
|
||||||
|
|
||||||
|
@Column(name = "LASTFLG", length = 2)
|
||||||
|
private Character lastflg;
|
||||||
|
|
||||||
|
@Column(name = "RSTIME")
|
||||||
|
private LocalDate rstime;
|
||||||
|
|
||||||
|
@Column(name = "RSCODE", length = 2)
|
||||||
|
private Character rscode;
|
||||||
|
|
||||||
|
@Column(name = "RSMSG", length = 100)
|
||||||
|
private String rsmsg;
|
||||||
|
|
||||||
|
@Column(name = "RSDETMSG", length = 2000)
|
||||||
|
private String rsdetmsg;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
public static class ComMailrstLogId implements Serializable {
|
||||||
|
@Column(name = "MID", nullable = false)
|
||||||
|
private Long mid;
|
||||||
|
|
||||||
|
@Column(name = "SUBID", nullable = false)
|
||||||
|
private Long subid;
|
||||||
|
|
||||||
|
@Column(name = "RMAIL", nullable = false, length = 100)
|
||||||
|
private String rmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.spring.domain.post.entity;
|
||||||
|
|
||||||
|
import com.spring.infra.db.SecondaryDataSourceConfig;
|
||||||
|
import com.spring.infra.db.annotation.DatabaseSelector;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@DatabaseSelector(SecondaryDataSourceConfig.DATABASE)
|
||||||
|
@Entity
|
||||||
|
@Table(name = "APP_POST")
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class Post {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "POST_ID", nullable = false)
|
||||||
|
private final Long postId;
|
||||||
|
|
||||||
|
@Column(name = "TITLE", nullable = false, length = 100)
|
||||||
|
private final String title;
|
||||||
|
|
||||||
|
@Column(name = "CONTENT", nullable = false, length = 2000)
|
||||||
|
private final String content;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.spring.domain.post.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import com.spring.domain.post.entity.Post;
|
||||||
|
import com.spring.infra.db.SecondaryDataSourceConfig;
|
||||||
|
import com.spring.infra.db.annotation.DatabaseSelector;
|
||||||
|
|
||||||
|
@DatabaseSelector(SecondaryDataSourceConfig.DATABASE)
|
||||||
|
public interface PostRepository extends JpaRepository<Post, Long> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.spring.domain.quartz.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.EmbeddedId;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.JoinColumns;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "QRTZ_BLOB_TRIGGERS")
|
||||||
|
@Getter
|
||||||
|
public class QrtzBlobTriggers {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private QrtzBlobTriggersId id;
|
||||||
|
|
||||||
|
@Column(name = "BLOB_DATA")
|
||||||
|
private byte[] blobData;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumns({
|
||||||
|
@JoinColumn(name = "SCHED_NAME", referencedColumnName = "SCHED_NAME", insertable = false, updatable = false),
|
||||||
|
@JoinColumn(name = "TRIGGER_NAME", referencedColumnName = "TRIGGER_NAME", insertable = false, updatable = false),
|
||||||
|
@JoinColumn(name = "TRIGGER_GROUP", referencedColumnName = "TRIGGER_GROUP", insertable = false, updatable = false)
|
||||||
|
})
|
||||||
|
private QrtzTriggers qrtzTriggers;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public static class QrtzBlobTriggersId implements Serializable {
|
||||||
|
@Column(name = "SCHED_NAME", length = 120, nullable = false)
|
||||||
|
private String schedName;
|
||||||
|
|
||||||
|
@Column(name = "TRIGGER_NAME", length = 200, nullable = false)
|
||||||
|
private String triggerName;
|
||||||
|
|
||||||
|
@Column(name = "TRIGGER_GROUP", length = 200, nullable = false)
|
||||||
|
private String triggerGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.spring.domain.quartz.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.EmbeddedId;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "QRTZ_CALENDARS")
|
||||||
|
@Getter
|
||||||
|
public class QrtzCalendars {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private QrtzCalendarsId id;
|
||||||
|
|
||||||
|
@Column(name = "CALENDAR", nullable = false)
|
||||||
|
private byte[] calendar;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public static class QrtzCalendarsId implements Serializable {
|
||||||
|
@Column(name = "SCHED_NAME", length = 120, nullable = false)
|
||||||
|
private String schedName;
|
||||||
|
|
||||||
|
@Column(name = "CALENDAR_NAME", length = 200, nullable = false)
|
||||||
|
private String calendarName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.spring.domain.quartz.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.EmbeddedId;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.ForeignKey;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.JoinColumns;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "QRTZ_CRON_TRIGGERS")
|
||||||
|
@Getter
|
||||||
|
public class QrtzCronTriggers {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private QrtzCronTriggersId id;
|
||||||
|
|
||||||
|
@Column(name = "CRON_EXPRESSION", length = 120, nullable = false)
|
||||||
|
private String cronExpression;
|
||||||
|
|
||||||
|
@Column(name = "TIME_ZONE_ID", length = 80)
|
||||||
|
private String timeZoneId;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumns(value = {
|
||||||
|
@JoinColumn(name = "SCHED_NAME", referencedColumnName = "SCHED_NAME", insertable = false, updatable = false),
|
||||||
|
@JoinColumn(name = "TRIGGER_NAME", referencedColumnName = "TRIGGER_NAME", insertable = false, updatable = false),
|
||||||
|
@JoinColumn(name = "TRIGGER_GROUP", referencedColumnName = "TRIGGER_GROUP", insertable = false, updatable = false)
|
||||||
|
}, foreignKey = @ForeignKey(name = "FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS"))
|
||||||
|
private QrtzTriggers qrtzTriggers;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public static class QrtzCronTriggersId implements Serializable {
|
||||||
|
@Column(name = "SCHED_NAME", length = 120, nullable = false)
|
||||||
|
private String schedName;
|
||||||
|
|
||||||
|
@Column(name = "TRIGGER_NAME", length = 200, nullable = false)
|
||||||
|
private String triggerName;
|
||||||
|
|
||||||
|
@Column(name = "TRIGGER_GROUP", length = 200, nullable = false)
|
||||||
|
private String triggerGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package com.spring.domain.quartz.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.EmbeddedId;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "QRTZ_FIRED_TRIGGERS")
|
||||||
|
@Getter
|
||||||
|
public class QrtzFiredTriggers {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private QrtzFiredTriggersId id;
|
||||||
|
|
||||||
|
@Column(name = "TRIGGER_NAME", length = 200, nullable = false)
|
||||||
|
private String triggerName;
|
||||||
|
|
||||||
|
@Column(name = "TRIGGER_GROUP", length = 200, nullable = false)
|
||||||
|
private String triggerGroup;
|
||||||
|
|
||||||
|
@Column(name = "INSTANCE_NAME", length = 200, nullable = false)
|
||||||
|
private String instanceName;
|
||||||
|
|
||||||
|
@Column(name = "FIRED_TIME", nullable = false)
|
||||||
|
private long firedTime;
|
||||||
|
|
||||||
|
@Column(name = "SCHED_TIME", nullable = false)
|
||||||
|
private long schedTime;
|
||||||
|
|
||||||
|
@Column(name = "PRIORITY", nullable = false)
|
||||||
|
private int priority;
|
||||||
|
|
||||||
|
@Column(name = "STATE", length = 16, nullable = false)
|
||||||
|
private String state;
|
||||||
|
|
||||||
|
@Column(name = "JOB_NAME", length = 200)
|
||||||
|
private String jobName;
|
||||||
|
|
||||||
|
@Column(name = "JOB_GROUP", length = 200)
|
||||||
|
private String jobGroup;
|
||||||
|
|
||||||
|
@Column(name = "IS_NONCONCURRENT")
|
||||||
|
private Boolean isNonConcurrent;
|
||||||
|
|
||||||
|
@Column(name = "REQUESTS_RECOVERY")
|
||||||
|
private Boolean requestsRecovery;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public static class QrtzFiredTriggersId implements Serializable {
|
||||||
|
@Column(name = "SCHED_NAME", length = 120, nullable = false)
|
||||||
|
private String schedName;
|
||||||
|
|
||||||
|
@Column(name = "ENTRY_ID", length = 95, nullable = false)
|
||||||
|
private String entryId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.spring.domain.quartz.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.EmbeddedId;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "QRTZ_JOB_DETAILS")
|
||||||
|
@Getter
|
||||||
|
public class QrtzJobDetails {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private QrtzJobDetailsId id;
|
||||||
|
|
||||||
|
@Column(name = "DESCRIPTION", length = 250)
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@Column(name = "JOB_CLASS_NAME", length = 250, nullable = false)
|
||||||
|
private String jobClassName;
|
||||||
|
|
||||||
|
@Column(name = "IS_DURABLE", nullable = false)
|
||||||
|
private boolean isDurable;
|
||||||
|
|
||||||
|
@Column(name = "IS_NONCONCURRENT", nullable = false)
|
||||||
|
private boolean isNonConcurrent;
|
||||||
|
|
||||||
|
@Column(name = "IS_UPDATE_DATA", nullable = false)
|
||||||
|
private boolean isUpdateData;
|
||||||
|
|
||||||
|
@Column(name = "REQUESTS_RECOVERY", nullable = false)
|
||||||
|
private boolean requestsRecovery;
|
||||||
|
|
||||||
|
@Column(name = "JOB_DATA")
|
||||||
|
private byte[] jobData;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public static class QrtzJobDetailsId implements Serializable {
|
||||||
|
@Column(name = "SCHED_NAME", length = 120, nullable = false)
|
||||||
|
private String schedName;
|
||||||
|
|
||||||
|
@Column(name = "JOB_NAME", length = 200, nullable = false)
|
||||||
|
private String jobName;
|
||||||
|
|
||||||
|
@Column(name = "JOB_GROUP", length = 200, nullable = false)
|
||||||
|
private String jobGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.spring.domain.quartz.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.EmbeddedId;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "QRTZ_LOCKS")
|
||||||
|
@Getter
|
||||||
|
public class QrtzLocks {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private QrtzLocksId id;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public static class QrtzLocksId implements Serializable {
|
||||||
|
@Column(name = "SCHED_NAME", length = 120, nullable = false)
|
||||||
|
private String schedName;
|
||||||
|
|
||||||
|
@Column(name = "LOCK_NAME", length = 40, nullable = false)
|
||||||
|
private String lockName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.spring.domain.quartz.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.EmbeddedId;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "QRTZ_PAUSED_TRIGGER_GRPS")
|
||||||
|
@Getter
|
||||||
|
public class QrtzPausedTriggerGrps {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private QrtzPausedTriggerGrpsId id;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public static class QrtzPausedTriggerGrpsId implements Serializable {
|
||||||
|
@Column(name = "SCHED_NAME", length = 120, nullable = false)
|
||||||
|
private String schedName;
|
||||||
|
|
||||||
|
@Column(name = "TRIGGER_GROUP", length = 200, nullable = false)
|
||||||
|
private String triggerGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.spring.domain.quartz.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.EmbeddedId;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "QRTZ_SCHEDULER_STATE")
|
||||||
|
@Getter
|
||||||
|
public class QrtzSchedulerState {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private QrtzSchedulerStateId id;
|
||||||
|
|
||||||
|
@Column(name = "LAST_CHECKIN_TIME", nullable = false)
|
||||||
|
private long lastCheckinTime;
|
||||||
|
|
||||||
|
@Column(name = "CHECKIN_INTERVAL", nullable = false)
|
||||||
|
private long checkinInterval;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public static class QrtzSchedulerStateId implements Serializable {
|
||||||
|
@Column(name = "SCHED_NAME", length = 120, nullable = false)
|
||||||
|
private String schedName;
|
||||||
|
|
||||||
|
@Column(name = "INSTANCE_NAME", length = 200, nullable = false)
|
||||||
|
private String instanceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.spring.domain.quartz.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.EmbeddedId;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.ForeignKey;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.JoinColumns;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "QRTZ_SIMPLE_TRIGGERS")
|
||||||
|
@Getter
|
||||||
|
public class QrtzSimpleTriggers {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private QrtzSimpleTriggersId id;
|
||||||
|
|
||||||
|
@Column(name = "REPEAT_COUNT", nullable = false)
|
||||||
|
private long repeatCount;
|
||||||
|
|
||||||
|
@Column(name = "REPEAT_INTERVAL", nullable = false)
|
||||||
|
private long repeatInterval;
|
||||||
|
|
||||||
|
@Column(name = "TIMES_TRIGGERED", nullable = false)
|
||||||
|
private long timesTriggered;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumns(value = {
|
||||||
|
@JoinColumn(name = "SCHED_NAME", referencedColumnName = "SCHED_NAME", insertable = false, updatable = false),
|
||||||
|
@JoinColumn(name = "TRIGGER_NAME", referencedColumnName = "TRIGGER_NAME", insertable = false, updatable = false),
|
||||||
|
@JoinColumn(name = "TRIGGER_GROUP", referencedColumnName = "TRIGGER_GROUP", insertable = false, updatable = false)
|
||||||
|
}, foreignKey = @ForeignKey(name = "FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS"))
|
||||||
|
private QrtzTriggers qrtzTriggers;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public static class QrtzSimpleTriggersId implements Serializable {
|
||||||
|
@Column(name = "SCHED_NAME", length = 120, nullable = false)
|
||||||
|
private String schedName;
|
||||||
|
|
||||||
|
@Column(name = "TRIGGER_NAME", length = 200, nullable = false)
|
||||||
|
private String triggerName;
|
||||||
|
|
||||||
|
@Column(name = "TRIGGER_GROUP", length = 200, nullable = false)
|
||||||
|
private String triggerGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package com.spring.domain.quartz.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.EmbeddedId;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.ForeignKey;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.JoinColumns;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "QRTZ_SIMPROP_TRIGGERS")
|
||||||
|
@Getter
|
||||||
|
public class QrtzSimpropTriggers {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private QrtzSimpropTriggersId id;
|
||||||
|
|
||||||
|
@Column(name = "STR_PROP_1", length = 512)
|
||||||
|
private String strProp1;
|
||||||
|
|
||||||
|
@Column(name = "STR_PROP_2", length = 512)
|
||||||
|
private String strProp2;
|
||||||
|
|
||||||
|
@Column(name = "STR_PROP_3", length = 512)
|
||||||
|
private String strProp3;
|
||||||
|
|
||||||
|
@Column(name = "INT_PROP_1")
|
||||||
|
private Integer intProp1;
|
||||||
|
|
||||||
|
@Column(name = "INT_PROP_2")
|
||||||
|
private Integer intProp2;
|
||||||
|
|
||||||
|
@Column(name = "LONG_PROP_1")
|
||||||
|
private Long longProp1;
|
||||||
|
|
||||||
|
@Column(name = "LONG_PROP_2")
|
||||||
|
private Long longProp2;
|
||||||
|
|
||||||
|
@Column(name = "DEC_PROP_1", precision = 13, scale = 4)
|
||||||
|
private BigDecimal decProp1;
|
||||||
|
|
||||||
|
@Column(name = "DEC_PROP_2", precision = 13, scale = 4)
|
||||||
|
private BigDecimal decProp2;
|
||||||
|
|
||||||
|
@Column(name = "BOOL_PROP_1")
|
||||||
|
private Boolean boolProp1;
|
||||||
|
|
||||||
|
@Column(name = "BOOL_PROP_2")
|
||||||
|
private Boolean boolProp2;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumns(value = {
|
||||||
|
@JoinColumn(name = "SCHED_NAME", referencedColumnName = "SCHED_NAME", insertable = false, updatable = false),
|
||||||
|
@JoinColumn(name = "TRIGGER_NAME", referencedColumnName = "TRIGGER_NAME", insertable = false, updatable = false),
|
||||||
|
@JoinColumn(name = "TRIGGER_GROUP", referencedColumnName = "TRIGGER_GROUP", insertable = false, updatable = false)
|
||||||
|
}, foreignKey = @ForeignKey(name = "FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS"))
|
||||||
|
private QrtzTriggers qrtzTriggers;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public static class QrtzSimpropTriggersId implements Serializable {
|
||||||
|
@Column(name = "SCHED_NAME", length = 120, nullable = false)
|
||||||
|
private String schedName;
|
||||||
|
|
||||||
|
@Column(name = "TRIGGER_NAME", length = 200, nullable = false)
|
||||||
|
private String triggerName;
|
||||||
|
|
||||||
|
@Column(name = "TRIGGER_GROUP", length = 200, nullable = false)
|
||||||
|
private String triggerGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package com.spring.domain.quartz.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.EmbeddedId;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.ForeignKey;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.JoinColumns;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "QRTZ_TRIGGERS")
|
||||||
|
@Getter
|
||||||
|
public class QrtzTriggers {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private QrtzTriggersId id;
|
||||||
|
|
||||||
|
@Column(name = "DESCRIPTION", length = 250)
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@Column(name = "NEXT_FIRE_TIME")
|
||||||
|
private Long nextFireTime;
|
||||||
|
|
||||||
|
@Column(name = "PREV_FIRE_TIME")
|
||||||
|
private Long prevFireTime;
|
||||||
|
|
||||||
|
@Column(name = "PRIORITY")
|
||||||
|
private Integer priority;
|
||||||
|
|
||||||
|
@Column(name = "TRIGGER_STATE", length = 16, nullable = false)
|
||||||
|
private String triggerState;
|
||||||
|
|
||||||
|
@Column(name = "TRIGGER_TYPE", length = 8, nullable = false)
|
||||||
|
private String triggerType;
|
||||||
|
|
||||||
|
@Column(name = "START_TIME", nullable = false)
|
||||||
|
private Long startTime;
|
||||||
|
|
||||||
|
@Column(name = "END_TIME")
|
||||||
|
private Long endTime;
|
||||||
|
|
||||||
|
@Column(name = "CALENDAR_NAME", length = 200)
|
||||||
|
private String calendarName;
|
||||||
|
|
||||||
|
@Column(name = "MISFIRE_INSTR")
|
||||||
|
private Short misfireInstr;
|
||||||
|
|
||||||
|
@Column(name = "JOB_DATA")
|
||||||
|
private byte[] jobData;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumns(value = {
|
||||||
|
@JoinColumn(name = "SCHED_NAME", referencedColumnName = "SCHED_NAME", insertable = false, updatable = false),
|
||||||
|
@JoinColumn(name = "JOB_NAME", referencedColumnName = "JOB_NAME", insertable = false, updatable = false),
|
||||||
|
@JoinColumn(name = "JOB_GROUP", referencedColumnName = "JOB_GROUP", insertable = false, updatable = false)
|
||||||
|
}, foreignKey = @ForeignKey(name = "FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS"))
|
||||||
|
private QrtzJobDetails qrtzJobDetails;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public static class QrtzTriggersId implements Serializable {
|
||||||
|
@Column(name = "SCHED_NAME", length = 120, nullable = false)
|
||||||
|
private String schedName;
|
||||||
|
|
||||||
|
@Column(name = "TRIGGER_NAME", length = 200, nullable = false)
|
||||||
|
private String triggerName;
|
||||||
|
|
||||||
|
@Column(name = "TRIGGER_GROUP", length = 200, nullable = false)
|
||||||
|
private String triggerGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.spring.domain.user.api;
|
||||||
|
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import com.spring.domain.user.dto.SignInRequest;
|
||||||
|
import com.spring.domain.user.service.AuthService;
|
||||||
|
import com.spring.infra.security.jwt.JwtTokenService;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("/api")
|
||||||
|
public class AuthController {
|
||||||
|
|
||||||
|
private final AuthService authService;
|
||||||
|
private final JwtTokenService jwtTokenService;
|
||||||
|
|
||||||
|
@PostMapping("/auth")
|
||||||
|
public ResponseEntity<?> generateToken(HttpServletResponse response, @RequestBody SignInRequest request) {
|
||||||
|
Authentication auth = authService.getAuthentication(request.getUsername(), request.getPassword());
|
||||||
|
jwtTokenService.generateAccessToken(response, auth);
|
||||||
|
jwtTokenService.generateRefreshToken(response, auth);
|
||||||
|
return ResponseEntity.ok().body(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.spring.domain.user.dto;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SignInRequest {
|
||||||
|
|
||||||
|
private final String username;
|
||||||
|
private final String password;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.spring.domain.user.entity;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import jakarta.persistence.CascadeType;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "APP_USER")
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public final class AppUser {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "USER_ID", nullable = false)
|
||||||
|
private final Long userId;
|
||||||
|
|
||||||
|
@Column(name = "LOGIN_ID", nullable = false, length = 50)
|
||||||
|
private final String loginId;
|
||||||
|
|
||||||
|
@Column(name = "PASSWORD", nullable = false, length = 128)
|
||||||
|
private final String password;
|
||||||
|
|
||||||
|
@Column(name = "USER_NAME", nullable = false, length = 50)
|
||||||
|
private final String userName;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "appUser", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||||
|
private final Set<AppUserRoleMap> appUserRoleMap;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.spring.domain.user.entity;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import jakarta.persistence.CascadeType;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "APP_USER_ROLE")
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public final class AppUserRole {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "ROLE_ID", nullable = false)
|
||||||
|
private final Long roleId;
|
||||||
|
|
||||||
|
@Column(name = "ROLE_TYPE", nullable = false, length = 10)
|
||||||
|
private final String roleType;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "appUserRole", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||||
|
private final Set<AppUserRoleMap> appUserRoleMap;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.spring.domain.user.entity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.EmbeddedId;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.MapsId;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "APP_USER_ROLE_MAP")
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public final class AppUserRoleMap {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private final AppUserRoleMapId id;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@MapsId("roleId")
|
||||||
|
@JoinColumn(name = "ROLE_ID")
|
||||||
|
private final AppUserRole appUserRole;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@MapsId("userId")
|
||||||
|
@JoinColumn(name = "USER_ID")
|
||||||
|
private final AppUser appUser;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static final class AppUserRoleMapId implements Serializable {
|
||||||
|
@Column(name = "ROLE_ID", nullable = false)
|
||||||
|
private final Long roleId;
|
||||||
|
|
||||||
|
@Column(name = "USER_ID", nullable = false)
|
||||||
|
private final Long userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.spring.domain.user.repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import com.spring.domain.user.entity.AppUser;
|
||||||
|
|
||||||
|
public interface AppUserRepository extends JpaRepository<AppUser, Long> {
|
||||||
|
|
||||||
|
Optional<AppUser> findByLoginId(String loginId);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.spring.domain.user.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import com.spring.domain.user.entity.AppUserRoleMap;
|
||||||
|
import com.spring.domain.user.entity.AppUserRoleMap.AppUserRoleMapId;
|
||||||
|
|
||||||
|
public interface AppUserRoleMapRepository extends JpaRepository<AppUserRoleMap, AppUserRoleMapId> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.spring.domain.user.service;
|
||||||
|
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AuthService {
|
||||||
|
|
||||||
|
private final AuthenticationManagerBuilder authenticationManagerBuilder;
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public Authentication getAuthentication(String username, String password) {
|
||||||
|
var authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
|
||||||
|
return authenticationManagerBuilder.getObject().authenticate(authenticationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.spring.infra.batch;
|
||||||
|
|
||||||
|
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
|
||||||
|
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
|
||||||
|
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableBatchProcessing
|
||||||
|
public abstract class AbstractBatchConfig {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected JobBuilderFactory jobBuilderFactory;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected StepBuilderFactory stepBuilderFactory;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.spring.infra.db;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class PrimaryDataSourceConfig {
|
||||||
|
|
||||||
|
public static final String DATABASE = "primary";
|
||||||
|
public static final String DATASOURCE = "primaryDataSource";
|
||||||
|
private static final String DATASOURCE_PROPERTIES = "primaryDataSourceProperties";
|
||||||
|
private static final String DATASOURCE_PROPERTIES_PREFIX = "spring.datasource.primary";
|
||||||
|
|
||||||
|
@Primary
|
||||||
|
@Bean(name = DATASOURCE_PROPERTIES)
|
||||||
|
@ConfigurationProperties(prefix = DATASOURCE_PROPERTIES_PREFIX)
|
||||||
|
DataSourceProperties dataSourceProperties() {
|
||||||
|
return new DataSourceProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Primary
|
||||||
|
@Bean(name = DATASOURCE)
|
||||||
|
DataSource dataSource(@Qualifier(DATASOURCE_PROPERTIES) DataSourceProperties properties) {
|
||||||
|
return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.spring.infra.db;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class SecondaryDataSourceConfig {
|
||||||
|
|
||||||
|
public static final String DATABASE = "secondary";
|
||||||
|
public static final String DATASOURCE = "secondaryDataSource";
|
||||||
|
private static final String DATASOURCE_PROPERTIES = "secondaryDataSourceProperties";
|
||||||
|
private static final String DATASOURCE_PROPERTIES_PREFIX = "spring.datasource.secondary";
|
||||||
|
|
||||||
|
@Bean(name = DATASOURCE_PROPERTIES)
|
||||||
|
@ConfigurationProperties(prefix = DATASOURCE_PROPERTIES_PREFIX)
|
||||||
|
DataSourceProperties dataSourceProperties() {
|
||||||
|
return new DataSourceProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name = DATASOURCE)
|
||||||
|
DataSource dataSource(@Qualifier(DATASOURCE_PROPERTIES) DataSourceProperties properties) {
|
||||||
|
return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.spring.infra.db.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface DatabaseSelector {
|
||||||
|
String value();
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package com.spring.infra.db.orm.jpa;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.FilterType;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||||
|
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||||
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
|
||||||
|
import com.spring.infra.db.PrimaryDataSourceConfig;
|
||||||
|
import com.spring.infra.db.orm.jpa.util.DatabaseSelectorFilter;
|
||||||
|
import com.spring.infra.db.orm.jpa.util.EntityScannerConfigurer;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManagerFactory;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableJpaRepositories(
|
||||||
|
basePackages = {PrimaryJpaConfig.BASE_PACKAGE},
|
||||||
|
entityManagerFactoryRef = PrimaryJpaConfig.ENTITY_MANAGER_FACTORY,
|
||||||
|
transactionManagerRef = PrimaryJpaConfig.TRANSACTION_MANAGER,
|
||||||
|
includeFilters = @Filter(type = FilterType.CUSTOM, classes = DatabaseSelectorFilter.class)
|
||||||
|
)
|
||||||
|
public class PrimaryJpaConfig {
|
||||||
|
|
||||||
|
public static final String TRANSACTION_MANAGER = "primaryTransactionManager";
|
||||||
|
private static final String DATABASE_FILTER = "primaryDatabaseFilter";
|
||||||
|
private static final String BASE_PACKAGE = "com.spring.domain";
|
||||||
|
private static final String ENTITY_MANAGER_FACTORY = "primaryEntityManagerFactory";
|
||||||
|
private static final String PERSISTENCE_UNIT = "primaryPersistenceUnit";
|
||||||
|
|
||||||
|
@Primary
|
||||||
|
@Bean(name = DATABASE_FILTER)
|
||||||
|
DatabaseSelectorFilter databaseSelectorFilter() {
|
||||||
|
var filter = new DatabaseSelectorFilter();
|
||||||
|
filter.setDbName(PrimaryDataSourceConfig.DATABASE);
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Primary
|
||||||
|
@Bean(name = ENTITY_MANAGER_FACTORY)
|
||||||
|
LocalContainerEntityManagerFactoryBean entityManagerFactory(
|
||||||
|
EntityManagerFactoryBuilder builder,
|
||||||
|
@Qualifier(PrimaryDataSourceConfig.DATASOURCE) DataSource dataSource
|
||||||
|
) {
|
||||||
|
var entities = EntityScannerConfigurer.scanEntities(BASE_PACKAGE, PrimaryDataSourceConfig.DATABASE);
|
||||||
|
return builder
|
||||||
|
.dataSource(dataSource)
|
||||||
|
.packages(entities.stream().map(BeanDefinition::getBeanClassName).toArray(String[]::new))
|
||||||
|
.persistenceUnit(PERSISTENCE_UNIT)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Primary
|
||||||
|
@Bean(TRANSACTION_MANAGER)
|
||||||
|
PlatformTransactionManager transactionManager(
|
||||||
|
@Qualifier(ENTITY_MANAGER_FACTORY) EntityManagerFactory entityManagerFactory
|
||||||
|
) {
|
||||||
|
return new JpaTransactionManager(entityManagerFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package com.spring.infra.db.orm.jpa;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.FilterType;
|
||||||
|
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||||
|
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||||
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
|
||||||
|
import com.spring.infra.db.SecondaryDataSourceConfig;
|
||||||
|
import com.spring.infra.db.orm.jpa.util.DatabaseSelectorFilter;
|
||||||
|
import com.spring.infra.db.orm.jpa.util.EntityScannerConfigurer;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManagerFactory;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableJpaRepositories(
|
||||||
|
basePackages = {SecondaryJpaConfig.BASE_PACKAGE},
|
||||||
|
entityManagerFactoryRef = SecondaryJpaConfig.ENTITY_MANAGER_FACTORY,
|
||||||
|
transactionManagerRef = SecondaryJpaConfig.TRANSACTION_MANAGER,
|
||||||
|
includeFilters = @Filter(type = FilterType.CUSTOM, classes = DatabaseSelectorFilter.class)
|
||||||
|
)
|
||||||
|
public class SecondaryJpaConfig {
|
||||||
|
|
||||||
|
public static final String TRANSACTION_MANAGER = "secondaryTransactionManager";
|
||||||
|
private static final String DATABASE_FILTER = "secondaryDatabaseFilter";
|
||||||
|
private static final String BASE_PACKAGE = "com.spring.domain";
|
||||||
|
private static final String ENTITY_MANAGER_FACTORY = "secondaryEntityManagerFactory";
|
||||||
|
private static final String PERSISTENCE_UNIT = "secondaryPersistenceUnit";
|
||||||
|
|
||||||
|
@Bean(name = DATABASE_FILTER)
|
||||||
|
DatabaseSelectorFilter databaseSelectorFilter() {
|
||||||
|
var filter = new DatabaseSelectorFilter();
|
||||||
|
filter.setDbName(SecondaryDataSourceConfig.DATABASE);
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name = ENTITY_MANAGER_FACTORY)
|
||||||
|
LocalContainerEntityManagerFactoryBean entityManagerFactory(
|
||||||
|
EntityManagerFactoryBuilder builder,
|
||||||
|
@Qualifier(SecondaryDataSourceConfig.DATASOURCE) DataSource dataSource
|
||||||
|
) {
|
||||||
|
var entities = EntityScannerConfigurer.scanEntities(BASE_PACKAGE, SecondaryDataSourceConfig.DATABASE);
|
||||||
|
return builder
|
||||||
|
.dataSource(dataSource)
|
||||||
|
.packages(entities.stream().map(BeanDefinition::getBeanClassName).toArray(String[]::new))
|
||||||
|
.persistenceUnit(PERSISTENCE_UNIT)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(TRANSACTION_MANAGER)
|
||||||
|
PlatformTransactionManager transactionManager(
|
||||||
|
@Qualifier(ENTITY_MANAGER_FACTORY) EntityManagerFactory entityManagerFactory
|
||||||
|
) {
|
||||||
|
return new JpaTransactionManager(entityManagerFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.spring.infra.db.orm.jpa.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.springframework.core.type.classreading.MetadataReader;
|
||||||
|
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||||
|
import org.springframework.core.type.filter.TypeFilter;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
|
||||||
|
import com.spring.infra.db.annotation.DatabaseSelector;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
public class DatabaseSelectorFilter implements TypeFilter {
|
||||||
|
|
||||||
|
@Setter private String dbName;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean match(@NonNull MetadataReader metadataReader, @NonNull MetadataReaderFactory metadataReaderFactory)
|
||||||
|
throws IOException {
|
||||||
|
boolean hasAnnotation = metadataReader.getAnnotationMetadata().hasAnnotation(DatabaseSelector.class.getName());
|
||||||
|
if (!hasAnnotation) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return Optional.ofNullable(metadataReader.getAnnotationMetadata()
|
||||||
|
.getAnnotationAttributes(DatabaseSelector.class.getName()))
|
||||||
|
.map(attributes -> dbName.equals(attributes.get("value")))
|
||||||
|
.orElse(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.spring.infra.db.orm.jpa.util;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||||
|
import org.springframework.core.type.classreading.MetadataReader;
|
||||||
|
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||||
|
import org.springframework.core.type.filter.TypeFilter;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
|
||||||
|
import com.spring.infra.db.annotation.DatabaseSelector;
|
||||||
|
|
||||||
|
public class EntityScannerConfigurer {
|
||||||
|
|
||||||
|
public static Set<BeanDefinition> scanEntities(String basePackage, String dbName) {
|
||||||
|
var scanner = new ClassPathScanningCandidateComponentProvider(false);
|
||||||
|
scanner.addIncludeFilter(new TypeFilter() {
|
||||||
|
@Override
|
||||||
|
public boolean match(@NonNull MetadataReader metadataReader, @NonNull MetadataReaderFactory metadataReaderFactory) {
|
||||||
|
boolean hasAnnotation = metadataReader.getAnnotationMetadata().hasAnnotation(DatabaseSelector.class.getName());
|
||||||
|
if (!hasAnnotation) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return Optional.ofNullable(metadataReader.getAnnotationMetadata()
|
||||||
|
.getAnnotationAttributes(DatabaseSelector.class.getName()))
|
||||||
|
.map(attributes -> dbName.equals(attributes.get("value")))
|
||||||
|
.orElse(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return scanner.findCandidateComponents(basePackage);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package com.spring.infra.db.orm.mybatis;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
|
import org.apache.ibatis.type.JdbcType;
|
||||||
|
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||||
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
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 com.spring.infra.db.PrimaryDataSourceConfig;
|
||||||
|
import com.spring.infra.db.orm.mybatis.util.MybatisBeanNameGenerator;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@MapperScan(
|
||||||
|
basePackages = PrimaryMybatisConfig.BASE_PACKAGE,
|
||||||
|
sqlSessionFactoryRef = PrimaryMybatisConfig.SESSION_FACTORY,
|
||||||
|
nameGenerator = MybatisBeanNameGenerator.class
|
||||||
|
)
|
||||||
|
public class PrimaryMybatisConfig {
|
||||||
|
|
||||||
|
private static final String BEAN_NAME_GENERATOR = "primaryNameGenerator";
|
||||||
|
private static final String BASE_PACKAGE = "com.spring.domain";
|
||||||
|
private static final String ALIASES_PACKAGE = "com.spring.domain.*.*.dto";
|
||||||
|
private static final String MAPPER_RESOURCES = "classpath:mapper/**/*.xml";
|
||||||
|
private static final String MYBATIS_CONFIG = "primaryMybatisConfig";
|
||||||
|
private static final String SESSION_FACTORY = "primarySqlSessionFactory";
|
||||||
|
|
||||||
|
@Primary
|
||||||
|
@Bean(name = BEAN_NAME_GENERATOR)
|
||||||
|
MybatisBeanNameGenerator mybatisBeanNameGenerator() {
|
||||||
|
return new MybatisBeanNameGenerator(PrimaryDataSourceConfig.DATABASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Primary
|
||||||
|
@Bean(name = MYBATIS_CONFIG)
|
||||||
|
org.apache.ibatis.session.Configuration mybatisConfiguration() {
|
||||||
|
var configuration = new org.apache.ibatis.session.Configuration();
|
||||||
|
configuration.setMapUnderscoreToCamelCase(true);
|
||||||
|
configuration.setCallSettersOnNulls(true);
|
||||||
|
configuration.setReturnInstanceForEmptyRow(true);
|
||||||
|
configuration.setJdbcTypeForNull(JdbcType.NULL);
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Primary
|
||||||
|
@Bean(name = SESSION_FACTORY)
|
||||||
|
SqlSessionFactory sqlSessionFactory(@Qualifier(PrimaryDataSourceConfig.DATASOURCE) DataSource dataSource) throws Exception {
|
||||||
|
var sessionFactory = new SqlSessionFactoryBean();
|
||||||
|
sessionFactory.setConfiguration(mybatisConfiguration());
|
||||||
|
sessionFactory.setDataSource(dataSource);
|
||||||
|
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_RESOURCES));
|
||||||
|
sessionFactory.setTypeAliasesPackage(ALIASES_PACKAGE);
|
||||||
|
sessionFactory.setVfs(SpringBootVFS.class);
|
||||||
|
return sessionFactory.getObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package com.spring.infra.db.orm.mybatis;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
|
import org.apache.ibatis.type.JdbcType;
|
||||||
|
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||||
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||||
|
|
||||||
|
import com.spring.infra.db.SecondaryDataSourceConfig;
|
||||||
|
import com.spring.infra.db.orm.mybatis.util.MybatisBeanNameGenerator;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@MapperScan(
|
||||||
|
basePackages = SecondaryMybatisConfig.BASE_PACKAGE,
|
||||||
|
sqlSessionFactoryRef = SecondaryMybatisConfig.SESSION_FACTORY,
|
||||||
|
nameGenerator = MybatisBeanNameGenerator.class
|
||||||
|
)
|
||||||
|
public class SecondaryMybatisConfig {
|
||||||
|
|
||||||
|
private static final String BEAN_NAME_GENERATOR = "secondaryNameGenerator";
|
||||||
|
private static final String BASE_PACKAGE = "com.spring.domain";
|
||||||
|
private static final String ALIASES_PACKAGE = "com.spring.domain.*.*.dto";
|
||||||
|
private static final String MAPPER_RESOURCES = "classpath:mapper/**/*.xml";
|
||||||
|
private static final String MYBATIS_CONFIG = "secondaryMybatisConfig";
|
||||||
|
private static final String SESSION_FACTORY = "secondarySqlSessionFactory";
|
||||||
|
|
||||||
|
@Bean(name = BEAN_NAME_GENERATOR)
|
||||||
|
MybatisBeanNameGenerator mybatisBeanNameGenerator() {
|
||||||
|
return new MybatisBeanNameGenerator(SecondaryDataSourceConfig.DATABASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name = MYBATIS_CONFIG)
|
||||||
|
org.apache.ibatis.session.Configuration mybatisConfiguration() {
|
||||||
|
var configuration = new org.apache.ibatis.session.Configuration();
|
||||||
|
configuration.setMapUnderscoreToCamelCase(true);
|
||||||
|
configuration.setCallSettersOnNulls(true);
|
||||||
|
configuration.setReturnInstanceForEmptyRow(true);
|
||||||
|
configuration.setJdbcTypeForNull(JdbcType.NULL);
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name = SESSION_FACTORY)
|
||||||
|
SqlSessionFactory sqlSessionFactory(@Qualifier(SecondaryDataSourceConfig.DATASOURCE) DataSource dataSource) throws Exception {
|
||||||
|
var sessionFactory = new SqlSessionFactoryBean();
|
||||||
|
sessionFactory.setConfiguration(mybatisConfiguration());
|
||||||
|
sessionFactory.setDataSource(dataSource);
|
||||||
|
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_RESOURCES));
|
||||||
|
sessionFactory.setTypeAliasesPackage(ALIASES_PACKAGE);
|
||||||
|
sessionFactory.setVfs(SpringBootVFS.class);
|
||||||
|
return sessionFactory.getObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package com.spring.infra.db.orm.mybatis.util;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
|
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
|
||||||
|
import com.spring.infra.db.annotation.DatabaseSelector;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MybatisBeanNameGenerator extends AnnotationBeanNameGenerator {
|
||||||
|
|
||||||
|
private final String dbName;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public String generateBeanName(@NonNull BeanDefinition definition, @NonNull BeanDefinitionRegistry registry) {
|
||||||
|
return Optional.ofNullable(definition.getBeanClassName())
|
||||||
|
.flatMap(className -> {
|
||||||
|
try {
|
||||||
|
var beanClass = Class.forName(className);
|
||||||
|
var annotation = beanClass.getAnnotation(DatabaseSelector.class);
|
||||||
|
if (annotation == null) {
|
||||||
|
return Optional.of(super.generateBeanName(definition, registry));
|
||||||
|
}
|
||||||
|
if (dbName.equals(annotation.value())) {
|
||||||
|
return Optional.of(super.generateBeanName(definition, registry));
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.orElse("");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package com.spring.infra.quartz;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.quartz.spi.JobFactory;
|
||||||
|
import org.quartz.spi.TriggerFiredBundle;
|
||||||
|
import org.springframework.batch.core.configuration.JobRegistry;
|
||||||
|
import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
|
||||||
|
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
|
||||||
|
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class QuartzConfig {
|
||||||
|
|
||||||
|
private final QuartzProperties quartzProperties;
|
||||||
|
private final DataSource dataSource;
|
||||||
|
private final PlatformTransactionManager transactionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JobRegistry 에 Job 을 자동으로 등록하기 위한 설정.
|
||||||
|
*
|
||||||
|
* @param jobRegistry ths Spring Batch Job Registry
|
||||||
|
* @return JobRegistry BeanPostProcessor
|
||||||
|
*/
|
||||||
|
// @Bean
|
||||||
|
// JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry) {
|
||||||
|
// var jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
|
||||||
|
// jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry);
|
||||||
|
// return jobRegistryBeanPostProcessor;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quartz Schedule Job 에 의존성 주입
|
||||||
|
*
|
||||||
|
* @param beanFactory application context beanFactory
|
||||||
|
* @return the job factory
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
JobFactory jobFactory(AutowireCapableBeanFactory beanFactory) {
|
||||||
|
return new SpringBeanJobFactory(){
|
||||||
|
@Override
|
||||||
|
protected @NonNull Object createJobInstance(@NonNull final TriggerFiredBundle bundle) throws Exception {
|
||||||
|
var job = super.createJobInstance(bundle);
|
||||||
|
beanFactory.autowireBean(job);
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scheduler 전체를 관리하는 Manager.
|
||||||
|
*
|
||||||
|
* @param datasource Spring datasource
|
||||||
|
* @param quartzProperties quartz config
|
||||||
|
* @return the scheduler factory bean
|
||||||
|
* @throws Exception the exception
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) throws Exception {
|
||||||
|
var factory = new SchedulerFactoryBean();
|
||||||
|
factory.setSchedulerName("SampleProject-0.0.1");
|
||||||
|
factory.setQuartzProperties(quartzProperties.toProperties());
|
||||||
|
factory.setOverwriteExistingJobs(true); //Job Detail 데이터 Overwrite 유무
|
||||||
|
factory.setDataSource(dataSource); //Schedule 관리를 Spring Datasource 에 위임
|
||||||
|
factory.setTransactionManager(transactionManager);
|
||||||
|
factory.setJobFactory(jobFactory);
|
||||||
|
factory.setAutoStartup(true);
|
||||||
|
factory.setWaitForJobsToCompleteOnShutdown(true);
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.spring.infra.quartz;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
public @interface QuartzJob {
|
||||||
|
String name();
|
||||||
|
String cronExpression();
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package com.spring.infra.quartz;
|
||||||
|
|
||||||
|
import org.quartz.JobExecutionContext;
|
||||||
|
import org.quartz.JobExecutionException;
|
||||||
|
import org.springframework.batch.core.Job;
|
||||||
|
import org.springframework.batch.core.JobParameters;
|
||||||
|
import org.springframework.batch.core.JobParametersBuilder;
|
||||||
|
import org.springframework.batch.core.configuration.JobLocator;
|
||||||
|
import org.springframework.batch.core.launch.JobLauncher;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||||
|
|
||||||
|
public class QuartzJobLauncher extends QuartzJobBean {
|
||||||
|
|
||||||
|
private String jobName;
|
||||||
|
private JobLauncher jobLauncher;
|
||||||
|
private JobLocator jobLocator;
|
||||||
|
|
||||||
|
public void setJobName(String jobName) {
|
||||||
|
this.jobName = jobName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJobLauncher(JobLauncher jobLauncher) {
|
||||||
|
this.jobLauncher = jobLauncher;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJobLocator(JobLocator jobLocator) {
|
||||||
|
this.jobLocator = jobLocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void executeInternal(@NonNull JobExecutionContext context) throws JobExecutionException {
|
||||||
|
try {
|
||||||
|
Job job = jobLocator.getJob(jobName);
|
||||||
|
JobParameters params = new JobParametersBuilder()
|
||||||
|
.addString("JobID", String.valueOf(System.currentTimeMillis()))
|
||||||
|
.toJobParameters();
|
||||||
|
jobLauncher.run(job, params);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new JobExecutionException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package com.spring.infra.quartz;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.quartz.CronScheduleBuilder;
|
||||||
|
import org.quartz.JobBuilder;
|
||||||
|
import org.quartz.JobDataMap;
|
||||||
|
import org.quartz.JobDetail;
|
||||||
|
import org.quartz.Scheduler;
|
||||||
|
import org.quartz.SchedulerException;
|
||||||
|
import org.quartz.Trigger;
|
||||||
|
import org.quartz.TriggerBuilder;
|
||||||
|
import org.springframework.batch.core.configuration.JobLocator;
|
||||||
|
import org.springframework.batch.core.launch.JobLauncher;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class QuartzJobRegistrar implements BeanPostProcessor, ApplicationContextAware {
|
||||||
|
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
private Scheduler scheduler;
|
||||||
|
|
||||||
|
public QuartzJobRegistrar(Scheduler scheduler) {
|
||||||
|
this.scheduler = scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object postProcessAfterInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException {
|
||||||
|
Class<?> beanClass = bean.getClass();
|
||||||
|
for (Method method : beanClass.getMethods()) {
|
||||||
|
QuartzJob quartzJobAnnotation = method.getAnnotation(QuartzJob.class);
|
||||||
|
if (quartzJobAnnotation != null) {
|
||||||
|
registerQuartzJob(quartzJobAnnotation, method.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerQuartzJob(QuartzJob quartzJobAnnotation, String jobName) {
|
||||||
|
try {
|
||||||
|
JobDetail jobDetail = createJobDetail(quartzJobAnnotation, jobName);
|
||||||
|
Trigger trigger = createTrigger(quartzJobAnnotation, jobDetail);
|
||||||
|
scheduler.scheduleJob(jobDetail, trigger);
|
||||||
|
} catch (SchedulerException e) {
|
||||||
|
throw new RuntimeException("Error scheduling Quartz job", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JobDetail createJobDetail(QuartzJob quartzJobAnnotation, String jobName) {
|
||||||
|
JobDataMap jobDataMap = new JobDataMap();
|
||||||
|
jobDataMap.put("jobName", jobName);
|
||||||
|
jobDataMap.put("jobLauncher", applicationContext.getBean(JobLauncher.class));
|
||||||
|
jobDataMap.put("jobLocator", applicationContext.getBean(JobLocator.class));
|
||||||
|
|
||||||
|
return JobBuilder.newJob(QuartzJobLauncher.class)
|
||||||
|
.withIdentity(quartzJobAnnotation.name())
|
||||||
|
.setJobData(jobDataMap)
|
||||||
|
.storeDurably()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Trigger createTrigger(QuartzJob quartzJobAnnotation, JobDetail jobDetail) {
|
||||||
|
return TriggerBuilder.newTrigger()
|
||||||
|
.forJob(jobDetail)
|
||||||
|
.withIdentity(quartzJobAnnotation.name() + "Trigger")
|
||||||
|
.withSchedule(CronScheduleBuilder.cronSchedule(quartzJobAnnotation.cronExpression()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package com.spring.infra.quartz;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@ConfigurationProperties(prefix = "spring.quartz.properties.org.quartz")
|
||||||
|
public class QuartzProperties {
|
||||||
|
|
||||||
|
private static final String PREFIX = "org.quartz";
|
||||||
|
|
||||||
|
private final JobStore jobStore;
|
||||||
|
private final Scheduler scheduler;
|
||||||
|
private final ThreadPool threadPool;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class JobStore {
|
||||||
|
private final String tablePrefix;
|
||||||
|
private final String isClustered;
|
||||||
|
private final int clusterCheckinInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class Scheduler {
|
||||||
|
private final String instanceId;
|
||||||
|
private final String instanceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class ThreadPool {
|
||||||
|
private final int threadCount;
|
||||||
|
private final int threadPriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Properties toProperties() {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
addProperties(PREFIX, this, properties);
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addProperties(String prefix, Object object, Properties properties) {
|
||||||
|
Arrays.stream(object.getClass().getDeclaredFields())
|
||||||
|
.filter(field -> !Modifier.isStatic(field.getModifiers()))
|
||||||
|
.forEach(field -> {
|
||||||
|
setProperties(prefix, object, properties, field);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setProperties(String prefix, Object object, Properties properties, Field field) {
|
||||||
|
try {
|
||||||
|
Object value = field.get(object);
|
||||||
|
if (value != null) {
|
||||||
|
String fieldName = field.getName();
|
||||||
|
String key = prefix + "." + fieldName;
|
||||||
|
if (isSimpleType(field.getType())) {
|
||||||
|
properties.setProperty(key, String.valueOf(value));
|
||||||
|
} else {
|
||||||
|
addProperties(key, value, properties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
log.error("Error getting property value for {}", field.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSimpleType(Class<?> type) {
|
||||||
|
return type.isPrimitive()
|
||||||
|
|| String.class == type
|
||||||
|
|| Number.class.isAssignableFrom(type)
|
||||||
|
|| Boolean.class == type
|
||||||
|
|| Character.class == type;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package com.spring.infra.security.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer.FrameOptionsConfig;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.HttpBasicConfigurer;
|
||||||
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
|
||||||
|
import com.spring.infra.security.filter.JwtAuthenticationFilter;
|
||||||
|
import com.spring.infra.security.handler.JwtAccessDeniedHandler;
|
||||||
|
import com.spring.infra.security.handler.JwtAuthenticationEntryPoint;
|
||||||
|
import com.spring.infra.security.jwt.JwtTokenService;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
@EnableMethodSecurity
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SecurityConfig {
|
||||||
|
|
||||||
|
public static final String PERMITTED_URI[] = {"/api/auth/**", "/signIn"};
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SecurityFilterChain securityFilterChain(
|
||||||
|
HttpSecurity http,
|
||||||
|
JwtTokenService tokenService,
|
||||||
|
JwtAuthenticationEntryPoint authenticationEntryPoint,
|
||||||
|
JwtAccessDeniedHandler accessDeniedHandler) throws Exception
|
||||||
|
{
|
||||||
|
http
|
||||||
|
.headers(headers -> headers.frameOptions(FrameOptionsConfig::sameOrigin))
|
||||||
|
.csrf(CsrfConfigurer::disable)
|
||||||
|
.httpBasic(HttpBasicConfigurer::disable)
|
||||||
|
.formLogin(FormLoginConfigurer::disable)
|
||||||
|
.authorizeHttpRequests(auth -> auth
|
||||||
|
.requestMatchers(PERMITTED_URI).permitAll()
|
||||||
|
.anyRequest().authenticated()
|
||||||
|
)
|
||||||
|
.logout((logout) -> logout
|
||||||
|
.logoutSuccessUrl("/signIn")
|
||||||
|
.invalidateHttpSession(true))
|
||||||
|
.sessionManagement(session -> session
|
||||||
|
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||||
|
)
|
||||||
|
.addFilterBefore(new JwtAuthenticationFilter(tokenService), UsernamePasswordAuthenticationFilter.class)
|
||||||
|
.exceptionHandling(ex -> ex.authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler));
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
WebSecurityCustomizer ignoringCustomizer() {
|
||||||
|
return (web) -> web.ignoring().requestMatchers("/h2-console/**");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
PasswordEncoder passwordEncoder() {
|
||||||
|
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package com.spring.infra.security.domain;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
|
import com.spring.domain.user.entity.AppUser;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public final class UserPrincipal implements UserDetails {
|
||||||
|
|
||||||
|
private final AppUser appUser;
|
||||||
|
|
||||||
|
public static UserPrincipal valueOf(AppUser appUser) {
|
||||||
|
return new UserPrincipal(appUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||||
|
return appUser.getAppUserRoleMap().stream()
|
||||||
|
.map(role -> role.getAppUserRole().getRoleType())
|
||||||
|
.map(SimpleGrantedAuthority::new)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAccountNonExpired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAccountNonLocked() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCredentialsNonExpired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPassword() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsername() {
|
||||||
|
return appUser.getLoginId();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package com.spring.infra.security.filter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import com.spring.infra.security.jwt.JwtTokenRule;
|
||||||
|
import com.spring.infra.security.jwt.JwtTokenService;
|
||||||
|
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public final class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
private final JwtTokenService jwtTokenService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain)
|
||||||
|
throws ServletException, IOException {
|
||||||
|
|
||||||
|
String accessToken = jwtTokenService.resolveTokenFromCookie(request, JwtTokenRule.ACCESS_PREFIX);
|
||||||
|
if (jwtTokenService.validateAccessToken(accessToken)) {
|
||||||
|
setAuthenticationToContext(accessToken);
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String refreshToken = jwtTokenService.resolveTokenFromCookie(request, JwtTokenRule.REFRESH_PREFIX);
|
||||||
|
if (jwtTokenService.validateRefreshToken(refreshToken)) {
|
||||||
|
Authentication authentication = jwtTokenService.getAuthentication(refreshToken);
|
||||||
|
String reissuedAccessToken = jwtTokenService.generateAccessToken(response, authentication);
|
||||||
|
jwtTokenService.generateRefreshToken(response, authentication);
|
||||||
|
setAuthenticationToContext(reissuedAccessToken);
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jwtTokenService.deleteCookie(response);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setAuthenticationToContext(String accessToken) {
|
||||||
|
Authentication authentication = jwtTokenService.getAuthentication(accessToken);
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.spring.infra.security.handler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 유저 정보는 있으나 자원에 접근할 수 있는 권한이 없는 경우 : SC_FORBIDDEN (403) 응답
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(HttpServletRequest request, HttpServletResponse response,
|
||||||
|
AccessDeniedException accessDeniedException) throws IOException, ServletException {
|
||||||
|
response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.spring.infra.security.handler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 유저 정보 없이 접근한 경우 : SC_UNAUTHORIZED (401) 응답
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void commence(HttpServletRequest request, HttpServletResponse response,
|
||||||
|
AuthenticationException authException) throws IOException, ServletException {
|
||||||
|
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.spring.infra.security.jwt;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ConfigurationProperties(prefix = "jwt")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public final class JwtProperties {
|
||||||
|
|
||||||
|
private final TokenProperties accessToken;
|
||||||
|
private final TokenProperties refreshToken;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class TokenProperties {
|
||||||
|
private final String secret;
|
||||||
|
private final long expiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package com.spring.infra.security.jwt;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class JwtTokenGenerator {
|
||||||
|
|
||||||
|
private final JwtProperties jwtProperties;
|
||||||
|
|
||||||
|
public String generateAccessToken(Authentication authentication) {
|
||||||
|
return Jwts.builder()
|
||||||
|
.setHeader(createHeader())
|
||||||
|
.setClaims(createClaims(authentication))
|
||||||
|
.setSubject(authentication.getName())
|
||||||
|
.setExpiration(Date.from(Instant.now().plus(jwtProperties.getAccessToken().getExpiration(), ChronoUnit.HOURS)))
|
||||||
|
.signWith(new SecretKeySpec(jwtProperties.getAccessToken().getSecret().getBytes(), SignatureAlgorithm.HS512.getJcaName()))
|
||||||
|
.compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateRefreshToken(Authentication authentication) {
|
||||||
|
return Jwts.builder()
|
||||||
|
.setHeader(createHeader())
|
||||||
|
.setSubject(authentication.getName())
|
||||||
|
.setExpiration(Date.from(Instant.now().plus(jwtProperties.getRefreshToken().getExpiration(), ChronoUnit.HOURS)))
|
||||||
|
.signWith(new SecretKeySpec(jwtProperties.getRefreshToken().getSecret().getBytes(), SignatureAlgorithm.HS512.getJcaName()))
|
||||||
|
.compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> createHeader() {
|
||||||
|
Map<String, Object> header = new HashMap<>();
|
||||||
|
header.put("typ", "JWT");
|
||||||
|
header.put("alg", "HS512");
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> createClaims(Authentication authentication) {
|
||||||
|
Map<String, Object> claims = new HashMap<>();
|
||||||
|
claims.put(JwtTokenRule.AUTHORITIES_KEY.getValue(), authentication.getAuthorities().stream()
|
||||||
|
.map(GrantedAuthority::getAuthority)
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
return claims;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.spring.infra.security.jwt;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public enum JwtTokenRule {
|
||||||
|
|
||||||
|
JWT_ISSUE_HEADER("Set-Cookie"),
|
||||||
|
JWT_RESOLVE_HEADER("Cookie"),
|
||||||
|
ACCESS_PREFIX("access"),
|
||||||
|
REFRESH_PREFIX("refresh"),
|
||||||
|
BEARER_PREFIX("Bearer "),
|
||||||
|
AUTHORITIES_KEY("auth");
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package com.spring.infra.security.jwt;
|
||||||
|
|
||||||
|
import java.security.Key;
|
||||||
|
|
||||||
|
import org.springframework.http.ResponseCookie;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.spring.infra.security.service.UserPrincipalService;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import jakarta.servlet.http.Cookie;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class JwtTokenService {
|
||||||
|
|
||||||
|
private final JwtTokenUtil jwtTokenUtil;
|
||||||
|
private final JwtTokenGenerator jwtTokenGenerator;
|
||||||
|
private final UserPrincipalService userPrincipalService;
|
||||||
|
|
||||||
|
private final Key ACCESS_SECRET_KEY;
|
||||||
|
private final Key REFRESH_SECRET_KEY;
|
||||||
|
private final long ACCESS_EXPIRATION;
|
||||||
|
private final long REFRESH_EXPIRATION;
|
||||||
|
|
||||||
|
public JwtTokenService(
|
||||||
|
JwtTokenUtil jwtTokenUtil,
|
||||||
|
JwtTokenGenerator jwtTokenGenerator,
|
||||||
|
UserPrincipalService userPrincipalService,
|
||||||
|
JwtProperties jwtProperties
|
||||||
|
) {
|
||||||
|
this.jwtTokenUtil = jwtTokenUtil;
|
||||||
|
this.jwtTokenGenerator = jwtTokenGenerator;
|
||||||
|
this.userPrincipalService = userPrincipalService;
|
||||||
|
this.ACCESS_SECRET_KEY = jwtTokenUtil.getSigningKey(jwtProperties.getAccessToken().getSecret());
|
||||||
|
this.REFRESH_SECRET_KEY = jwtTokenUtil.getSigningKey(jwtProperties.getRefreshToken().getSecret());
|
||||||
|
this.ACCESS_EXPIRATION = jwtProperties.getAccessToken().getExpiration();
|
||||||
|
this.REFRESH_EXPIRATION = jwtProperties.getRefreshToken().getExpiration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateAccessToken(HttpServletResponse response, Authentication authentication) {
|
||||||
|
String accessToken = jwtTokenGenerator.generateAccessToken(authentication);
|
||||||
|
ResponseCookie cookie = setTokenToCookie(JwtTokenRule.ACCESS_PREFIX.getValue(), accessToken, ACCESS_EXPIRATION / 1000);
|
||||||
|
response.addHeader(JwtTokenRule.JWT_ISSUE_HEADER.getValue(), cookie.toString());
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateRefreshToken(HttpServletResponse response, Authentication authentication) {
|
||||||
|
String refreshToken = jwtTokenGenerator.generateRefreshToken(authentication);
|
||||||
|
ResponseCookie cookie = setTokenToCookie(JwtTokenRule.REFRESH_PREFIX.getValue(), refreshToken, REFRESH_EXPIRATION / 1000);
|
||||||
|
response.addHeader(JwtTokenRule.JWT_ISSUE_HEADER.getValue(), cookie.toString());
|
||||||
|
return refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResponseCookie setTokenToCookie(String tokenPrefix, String token, long maxAgeSeconds) {
|
||||||
|
return ResponseCookie.from(tokenPrefix, token)
|
||||||
|
.path("/")
|
||||||
|
.maxAge(maxAgeSeconds)
|
||||||
|
.httpOnly(true)
|
||||||
|
.sameSite("None")
|
||||||
|
.secure(true)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean validateAccessToken(String token) {
|
||||||
|
return jwtTokenUtil.getTokenStatus(token, ACCESS_SECRET_KEY) == JwtTokenStatus.AUTHENTICATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean validateRefreshToken(String token) {
|
||||||
|
return jwtTokenUtil.getTokenStatus(token, REFRESH_SECRET_KEY) == JwtTokenStatus.AUTHENTICATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String resolveTokenFromCookie(HttpServletRequest request, JwtTokenRule tokenPrefix) {
|
||||||
|
Cookie[] cookies = request.getCookies();
|
||||||
|
if (cookies == null) {
|
||||||
|
throw new RuntimeException("JWT_TOKEN_NOT_FOUND");
|
||||||
|
}
|
||||||
|
return jwtTokenUtil.resolveTokenFromCookie(cookies, tokenPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Authentication getAuthentication(String token) {
|
||||||
|
UserDetails principal = userPrincipalService.loadUserByUsername(getUserPk(token, ACCESS_SECRET_KEY));
|
||||||
|
return new UsernamePasswordAuthenticationToken(principal, "", principal.getAuthorities());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getUserPk(String token, Key secretKey) {
|
||||||
|
return Jwts.parserBuilder()
|
||||||
|
.setSigningKey(secretKey)
|
||||||
|
.build()
|
||||||
|
.parseClaimsJws(token)
|
||||||
|
.getBody()
|
||||||
|
.getSubject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteCookie(HttpServletResponse response) {
|
||||||
|
Cookie accessCookie = jwtTokenUtil.resetToken(JwtTokenRule.ACCESS_PREFIX);
|
||||||
|
Cookie refreshCookie = jwtTokenUtil.resetToken(JwtTokenRule.REFRESH_PREFIX);
|
||||||
|
response.addCookie(accessCookie);
|
||||||
|
response.addCookie(refreshCookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.spring.infra.security.jwt;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public enum JwtTokenStatus {
|
||||||
|
AUTHENTICATED,
|
||||||
|
EXPIRED,
|
||||||
|
INVALID
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.spring.infra.security.jwt;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.ExpiredJwtException;
|
||||||
|
import io.jsonwebtoken.JwtException;
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.security.Keys;
|
||||||
|
import jakarta.servlet.http.Cookie;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class JwtTokenUtil {
|
||||||
|
|
||||||
|
public JwtTokenStatus getTokenStatus(String token, Key secretKey) {
|
||||||
|
try {
|
||||||
|
Jwts.parserBuilder()
|
||||||
|
.setSigningKey(secretKey)
|
||||||
|
.build()
|
||||||
|
.parseClaimsJws(token);
|
||||||
|
return JwtTokenStatus.AUTHENTICATED;
|
||||||
|
} catch (ExpiredJwtException | IllegalArgumentException e) {
|
||||||
|
log.error("만료된 JWT 토큰입니다.");
|
||||||
|
return JwtTokenStatus.EXPIRED;
|
||||||
|
} catch (JwtException e) {
|
||||||
|
log.error("JWT 토큰이 잘못되었습니다.");
|
||||||
|
return JwtTokenStatus.INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String resolveTokenFromCookie(Cookie[] cookies, JwtTokenRule tokenPrefix) {
|
||||||
|
return Arrays.stream(cookies)
|
||||||
|
.filter(cookie -> cookie.getName().equals(tokenPrefix.getValue()))
|
||||||
|
.findFirst()
|
||||||
|
.map(Cookie::getValue)
|
||||||
|
.orElse("");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Key getSigningKey(String secretKey) {
|
||||||
|
String encodedKey = encodeToBase64(secretKey);
|
||||||
|
return Keys.hmacShaKeyFor(encodedKey.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String encodeToBase64(String secretKey) {
|
||||||
|
return Base64.getEncoder().encodeToString(secretKey.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cookie resetToken(JwtTokenRule tokenPrefix) {
|
||||||
|
Cookie cookie = new Cookie(tokenPrefix.getValue(), null);
|
||||||
|
cookie.setMaxAge(0);
|
||||||
|
cookie.setPath("/");
|
||||||
|
return cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.spring.infra.security.service;
|
||||||
|
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import com.spring.domain.user.entity.AppUser;
|
||||||
|
import com.spring.domain.user.repository.AppUserRepository;
|
||||||
|
import com.spring.infra.security.domain.UserPrincipal;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class UserPrincipalService implements UserDetailsService {
|
||||||
|
|
||||||
|
private final AppUserRepository appUserRepository;
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
@Override
|
||||||
|
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||||
|
AppUser user = appUserRepository.findByLoginId(username)
|
||||||
|
.orElseThrow(() -> new UsernameNotFoundException("NOT FOUND USER"));
|
||||||
|
return UserPrincipal.valueOf(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
{"properties": [
|
||||||
|
{
|
||||||
|
"name": "jwt.secret",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'jwt.secret'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "jwt.access-token.expiration",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'jwt.access-token.expiration'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "jwt.refresh-token.expiration",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'jwt.refresh-token.expiration'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "jwt.access-token.secret",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'jwt.access-token.secret'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "jwt.refresh-token.secret",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'jwt.refresh-token.secret'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.mob.driver-class-name",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.mob.driver-class-name'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.mob.url",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.mob.url'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.mob.username",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.mob.username'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.mob.password",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.mob.password'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.app.hikari.pool-name",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.app.hikari.pool-name'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.app.hikari.maximum-pool-size",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.app.hikari.maximum-pool-size'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.app.hikari.minimum-idle",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.app.hikari.minimum-idle'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.mob.hikari.pool-name",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.mob.hikari.pool-name'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.mob.hikari.maximum-pool-size",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.mob.hikari.maximum-pool-size'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.mob.hikari.minimum-idle",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.mob.hikari.minimum-idle'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.primary.driver-class-name",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.primary.driver-class-name'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.primary.url",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.primary.url'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.primary.username",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.primary.username'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.primary.password",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.primary.password'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.primary.hikari.pool-name",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.primary.hikari.pool-name'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.primary.hikari.maximum-pool-size",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.primary.hikari.maximum-pool-size'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.primary.hikari.minimum-idle",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.primary.hikari.minimum-idle'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.secondary.driver-class-name",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.secondary.driver-class-name'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.secondary.url",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.secondary.url'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.secondary.username",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.secondary.username'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.secondary.password",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.secondary.password'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.secondary.hikari.pool-name",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.secondary.hikari.pool-name'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.secondary.hikari.maximum-pool-size",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.secondary.hikari.maximum-pool-size'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.datasource.secondary.hikari.minimum-idle",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "A description for 'spring.datasource.secondary.hikari.minimum-idle'"
|
||||||
|
}
|
||||||
|
]}
|
||||||
85
batch-quartz/src/main/resources/application.yml
Normal file
85
batch-quartz/src/main/resources/application.yml
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
server:
|
||||||
|
port: 8081
|
||||||
|
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: spring-batch-quartz
|
||||||
|
datasource:
|
||||||
|
primary:
|
||||||
|
driver-class-name: org.h2.Driver
|
||||||
|
url: 'jdbc:h2:mem:app'
|
||||||
|
username: mindol1004
|
||||||
|
password: 1111
|
||||||
|
hikari:
|
||||||
|
pool-name: HikariPool-1
|
||||||
|
maximum-pool-size: 10
|
||||||
|
minimum-idle: 5
|
||||||
|
secondary:
|
||||||
|
driver-class-name: org.h2.Driver
|
||||||
|
url: 'jdbc:h2:mem:mob'
|
||||||
|
username: mindol1004
|
||||||
|
password: 1111
|
||||||
|
hikari:
|
||||||
|
pool-name: HikariPool-2
|
||||||
|
maximum-pool-size: 10
|
||||||
|
minimum-idle: 5
|
||||||
|
# sql:
|
||||||
|
# init:
|
||||||
|
# mode: always
|
||||||
|
# schema-locations:
|
||||||
|
# - classpath:batch-schema.sql
|
||||||
|
# - classpath:quartz-schema.sql
|
||||||
|
|
||||||
|
jpa:
|
||||||
|
database-platform: org.hibernate.dialect.H2Dialect
|
||||||
|
hibernate:
|
||||||
|
ddl-auto: create
|
||||||
|
properties:
|
||||||
|
hibernate:
|
||||||
|
dialect: org.hibernate.dialect.H2Dialect
|
||||||
|
"[format_sql]": true # 쿼리 로그 포맷 (정렬)
|
||||||
|
"[show_sql]": true # 쿼리 로그 출력
|
||||||
|
naming:
|
||||||
|
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
|
||||||
|
show-sql: true
|
||||||
|
|
||||||
|
batch:
|
||||||
|
jdbc:
|
||||||
|
initialize-schema: never
|
||||||
|
|
||||||
|
quartz:
|
||||||
|
jdbc:
|
||||||
|
initialize-schema: never
|
||||||
|
wait-for-jobs-to-complete-on-shutdown: true
|
||||||
|
job-store-type: jdbc
|
||||||
|
properties:
|
||||||
|
org:
|
||||||
|
quartz:
|
||||||
|
scheduler:
|
||||||
|
instanceName: BatchQuartzScheduler
|
||||||
|
instanceId: AUTO
|
||||||
|
jobStore:
|
||||||
|
class: org.quartz.impl.jdbcjobstore.JobStoreTX
|
||||||
|
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
|
||||||
|
tablePrefix: QRTZ_
|
||||||
|
isClustered: true
|
||||||
|
clusterCheckinInterval: 20000
|
||||||
|
threadPool:
|
||||||
|
class: org.quartz.simpl.SimpleThreadPool
|
||||||
|
threadCount: 10
|
||||||
|
threadPriority: 5
|
||||||
|
|
||||||
|
h2:
|
||||||
|
console: # H2 DB를 웹에서 관리할 수 있는 기능
|
||||||
|
enabled: true # H2 Console 사용 여부
|
||||||
|
path: /h2-console # H2 Console 접속 주소
|
||||||
|
settings:
|
||||||
|
web-allow-others: true
|
||||||
|
|
||||||
|
jwt:
|
||||||
|
access-token:
|
||||||
|
secret: bnhjdXMyLjAtcGxhdGZvcm0tcHJvamVjdC13aXRoLXNwcmluZy1ib290
|
||||||
|
expiration: 900 # 15분
|
||||||
|
refresh-token:
|
||||||
|
secret: bnhjdXMyLjAtcGxhdGZvcm0tcHJvamVjdC13aXRoLXNwcmluZy1ib290
|
||||||
|
expiration: 604800 # 7일
|
||||||
78
batch-quartz/src/main/resources/batch-schema.sql
Normal file
78
batch-quartz/src/main/resources/batch-schema.sql
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
-- Batch
|
||||||
|
|
||||||
|
CREATE TABLE BATCH_JOB_INSTANCE (
|
||||||
|
JOB_INSTANCE_ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY ,
|
||||||
|
VERSION BIGINT ,
|
||||||
|
JOB_NAME VARCHAR(100) NOT NULL,
|
||||||
|
JOB_KEY VARCHAR(32) NOT NULL,
|
||||||
|
constraint JOB_INST_UN unique (JOB_NAME, JOB_KEY)
|
||||||
|
) ;
|
||||||
|
|
||||||
|
CREATE TABLE BATCH_JOB_EXECUTION (
|
||||||
|
JOB_EXECUTION_ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY ,
|
||||||
|
VERSION BIGINT ,
|
||||||
|
JOB_INSTANCE_ID BIGINT NOT NULL,
|
||||||
|
CREATE_TIME TIMESTAMP(9) NOT NULL,
|
||||||
|
START_TIME TIMESTAMP(9) DEFAULT NULL ,
|
||||||
|
END_TIME TIMESTAMP(9) DEFAULT NULL ,
|
||||||
|
STATUS VARCHAR(10) ,
|
||||||
|
EXIT_CODE VARCHAR(2500) ,
|
||||||
|
EXIT_MESSAGE VARCHAR(2500) ,
|
||||||
|
LAST_UPDATED TIMESTAMP(9),
|
||||||
|
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
|
||||||
|
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
|
||||||
|
) ;
|
||||||
|
|
||||||
|
CREATE TABLE BATCH_JOB_EXECUTION_PARAMS (
|
||||||
|
JOB_EXECUTION_ID BIGINT NOT NULL ,
|
||||||
|
PARAMETER_NAME VARCHAR(100) NOT NULL ,
|
||||||
|
PARAMETER_TYPE VARCHAR(100) NOT NULL ,
|
||||||
|
PARAMETER_VALUE VARCHAR(2500) ,
|
||||||
|
IDENTIFYING CHAR(1) NOT NULL ,
|
||||||
|
constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)
|
||||||
|
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
|
||||||
|
) ;
|
||||||
|
|
||||||
|
CREATE TABLE BATCH_STEP_EXECUTION (
|
||||||
|
STEP_EXECUTION_ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY ,
|
||||||
|
VERSION BIGINT NOT NULL,
|
||||||
|
STEP_NAME VARCHAR(100) NOT NULL,
|
||||||
|
JOB_EXECUTION_ID BIGINT NOT NULL,
|
||||||
|
CREATE_TIME TIMESTAMP(9) NOT NULL,
|
||||||
|
START_TIME TIMESTAMP(9) DEFAULT NULL ,
|
||||||
|
END_TIME TIMESTAMP(9) DEFAULT NULL ,
|
||||||
|
STATUS VARCHAR(10) ,
|
||||||
|
COMMIT_COUNT BIGINT ,
|
||||||
|
READ_COUNT BIGINT ,
|
||||||
|
FILTER_COUNT BIGINT ,
|
||||||
|
WRITE_COUNT BIGINT ,
|
||||||
|
READ_SKIP_COUNT BIGINT ,
|
||||||
|
WRITE_SKIP_COUNT BIGINT ,
|
||||||
|
PROCESS_SKIP_COUNT BIGINT ,
|
||||||
|
ROLLBACK_COUNT BIGINT ,
|
||||||
|
EXIT_CODE VARCHAR(2500) ,
|
||||||
|
EXIT_MESSAGE VARCHAR(2500) ,
|
||||||
|
LAST_UPDATED TIMESTAMP(9),
|
||||||
|
constraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID)
|
||||||
|
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
|
||||||
|
) ;
|
||||||
|
|
||||||
|
CREATE TABLE BATCH_STEP_EXECUTION_CONTEXT (
|
||||||
|
STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
|
||||||
|
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
|
||||||
|
SERIALIZED_CONTEXT LONGVARCHAR ,
|
||||||
|
constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID)
|
||||||
|
references BATCH_STEP_EXECUTION(STEP_EXECUTION_ID)
|
||||||
|
) ;
|
||||||
|
|
||||||
|
CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT (
|
||||||
|
JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
|
||||||
|
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
|
||||||
|
SERIALIZED_CONTEXT LONGVARCHAR ,
|
||||||
|
constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID)
|
||||||
|
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
|
||||||
|
) ;
|
||||||
|
|
||||||
|
CREATE SEQUENCE BATCH_STEP_EXECUTION_SEQ;
|
||||||
|
CREATE SEQUENCE BATCH_JOB_EXECUTION_SEQ;
|
||||||
|
CREATE SEQUENCE BATCH_JOB_SEQ;
|
||||||
238
batch-quartz/src/main/resources/quartz-schema.sql
Normal file
238
batch-quartz/src/main/resources/quartz-schema.sql
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
CREATE TABLE QRTZ_CALENDARS (
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
CALENDAR_NAME VARCHAR (200) NOT NULL ,
|
||||||
|
CALENDAR IMAGE NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_CRON_TRIGGERS (
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR (200) NOT NULL ,
|
||||||
|
TRIGGER_GROUP VARCHAR (200) NOT NULL ,
|
||||||
|
CRON_EXPRESSION VARCHAR (120) NOT NULL ,
|
||||||
|
TIME_ZONE_ID VARCHAR (80)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_FIRED_TRIGGERS (
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
ENTRY_ID VARCHAR (95) NOT NULL ,
|
||||||
|
TRIGGER_NAME VARCHAR (200) NOT NULL ,
|
||||||
|
TRIGGER_GROUP VARCHAR (200) NOT NULL ,
|
||||||
|
INSTANCE_NAME VARCHAR (200) NOT NULL ,
|
||||||
|
FIRED_TIME BIGINT NOT NULL ,
|
||||||
|
SCHED_TIME BIGINT NOT NULL ,
|
||||||
|
PRIORITY INTEGER NOT NULL ,
|
||||||
|
STATE VARCHAR (16) NOT NULL,
|
||||||
|
JOB_NAME VARCHAR (200) NULL ,
|
||||||
|
JOB_GROUP VARCHAR (200) NULL ,
|
||||||
|
IS_NONCONCURRENT BOOLEAN NULL ,
|
||||||
|
REQUESTS_RECOVERY BOOLEAN NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR (200) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_SCHEDULER_STATE (
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
INSTANCE_NAME VARCHAR (200) NOT NULL ,
|
||||||
|
LAST_CHECKIN_TIME BIGINT NOT NULL ,
|
||||||
|
CHECKIN_INTERVAL BIGINT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_LOCKS (
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
LOCK_NAME VARCHAR (40) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_JOB_DETAILS (
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
JOB_NAME VARCHAR (200) NOT NULL ,
|
||||||
|
JOB_GROUP VARCHAR (200) NOT NULL ,
|
||||||
|
DESCRIPTION VARCHAR (250) NULL ,
|
||||||
|
JOB_CLASS_NAME VARCHAR (250) NOT NULL ,
|
||||||
|
IS_DURABLE BOOLEAN NOT NULL ,
|
||||||
|
IS_NONCONCURRENT BOOLEAN NOT NULL ,
|
||||||
|
IS_UPDATE_DATA BOOLEAN NOT NULL ,
|
||||||
|
REQUESTS_RECOVERY BOOLEAN NOT NULL ,
|
||||||
|
JOB_DATA IMAGE NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR (200) NOT NULL ,
|
||||||
|
TRIGGER_GROUP VARCHAR (200) NOT NULL ,
|
||||||
|
REPEAT_COUNT BIGINT NOT NULL ,
|
||||||
|
REPEAT_INTERVAL BIGINT NOT NULL ,
|
||||||
|
TIMES_TRIGGERED BIGINT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_SIMPROP_TRIGGERS (
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||||
|
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||||
|
STR_PROP_1 VARCHAR(512) NULL,
|
||||||
|
STR_PROP_2 VARCHAR(512) NULL,
|
||||||
|
STR_PROP_3 VARCHAR(512) NULL,
|
||||||
|
INT_PROP_1 INTEGER NULL,
|
||||||
|
INT_PROP_2 INTEGER NULL,
|
||||||
|
LONG_PROP_1 BIGINT NULL,
|
||||||
|
LONG_PROP_2 BIGINT NULL,
|
||||||
|
DEC_PROP_1 NUMERIC(13,4) NULL,
|
||||||
|
DEC_PROP_2 NUMERIC(13,4) NULL,
|
||||||
|
BOOL_PROP_1 BOOLEAN NULL,
|
||||||
|
BOOL_PROP_2 BOOLEAN NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_BLOB_TRIGGERS (
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR (200) NOT NULL ,
|
||||||
|
TRIGGER_GROUP VARCHAR (200) NOT NULL ,
|
||||||
|
BLOB_DATA IMAGE NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE QRTZ_TRIGGERS (
|
||||||
|
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||||
|
TRIGGER_NAME VARCHAR (200) NOT NULL ,
|
||||||
|
TRIGGER_GROUP VARCHAR (200) NOT NULL ,
|
||||||
|
JOB_NAME VARCHAR (200) NOT NULL ,
|
||||||
|
JOB_GROUP VARCHAR (200) NOT NULL ,
|
||||||
|
DESCRIPTION VARCHAR (250) NULL ,
|
||||||
|
NEXT_FIRE_TIME BIGINT NULL ,
|
||||||
|
PREV_FIRE_TIME BIGINT NULL ,
|
||||||
|
PRIORITY INTEGER NULL ,
|
||||||
|
TRIGGER_STATE VARCHAR (16) NOT NULL ,
|
||||||
|
TRIGGER_TYPE VARCHAR (8) NOT NULL ,
|
||||||
|
START_TIME BIGINT NOT NULL ,
|
||||||
|
END_TIME BIGINT NULL ,
|
||||||
|
CALENDAR_NAME VARCHAR (200) NULL ,
|
||||||
|
MISFIRE_INSTR SMALLINT NULL ,
|
||||||
|
JOB_DATA IMAGE NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE QRTZ_CALENDARS ADD
|
||||||
|
CONSTRAINT PK_QRTZ_CALENDARS PRIMARY KEY
|
||||||
|
(
|
||||||
|
SCHED_NAME,
|
||||||
|
CALENDAR_NAME
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE QRTZ_CRON_TRIGGERS ADD
|
||||||
|
CONSTRAINT PK_QRTZ_CRON_TRIGGERS PRIMARY KEY
|
||||||
|
(
|
||||||
|
SCHED_NAME,
|
||||||
|
TRIGGER_NAME,
|
||||||
|
TRIGGER_GROUP
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE QRTZ_FIRED_TRIGGERS ADD
|
||||||
|
CONSTRAINT PK_QRTZ_FIRED_TRIGGERS PRIMARY KEY
|
||||||
|
(
|
||||||
|
SCHED_NAME,
|
||||||
|
ENTRY_ID
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE QRTZ_PAUSED_TRIGGER_GRPS ADD
|
||||||
|
CONSTRAINT PK_QRTZ_PAUSED_TRIGGER_GRPS PRIMARY KEY
|
||||||
|
(
|
||||||
|
SCHED_NAME,
|
||||||
|
TRIGGER_GROUP
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE QRTZ_SCHEDULER_STATE ADD
|
||||||
|
CONSTRAINT PK_QRTZ_SCHEDULER_STATE PRIMARY KEY
|
||||||
|
(
|
||||||
|
SCHED_NAME,
|
||||||
|
INSTANCE_NAME
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE QRTZ_LOCKS ADD
|
||||||
|
CONSTRAINT PK_QRTZ_LOCKS PRIMARY KEY
|
||||||
|
(
|
||||||
|
SCHED_NAME,
|
||||||
|
LOCK_NAME
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE QRTZ_JOB_DETAILS ADD
|
||||||
|
CONSTRAINT PK_QRTZ_JOB_DETAILS PRIMARY KEY
|
||||||
|
(
|
||||||
|
SCHED_NAME,
|
||||||
|
JOB_NAME,
|
||||||
|
JOB_GROUP
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD
|
||||||
|
CONSTRAINT PK_QRTZ_SIMPLE_TRIGGERS PRIMARY KEY
|
||||||
|
(
|
||||||
|
SCHED_NAME,
|
||||||
|
TRIGGER_NAME,
|
||||||
|
TRIGGER_GROUP
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD
|
||||||
|
CONSTRAINT PK_QRTZ_SIMPROP_TRIGGERS PRIMARY KEY
|
||||||
|
(
|
||||||
|
SCHED_NAME,
|
||||||
|
TRIGGER_NAME,
|
||||||
|
TRIGGER_GROUP
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE QRTZ_TRIGGERS ADD
|
||||||
|
CONSTRAINT PK_QRTZ_TRIGGERS PRIMARY KEY
|
||||||
|
(
|
||||||
|
SCHED_NAME,
|
||||||
|
TRIGGER_NAME,
|
||||||
|
TRIGGER_GROUP
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE QRTZ_CRON_TRIGGERS ADD
|
||||||
|
CONSTRAINT FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY
|
||||||
|
(
|
||||||
|
SCHED_NAME,
|
||||||
|
TRIGGER_NAME,
|
||||||
|
TRIGGER_GROUP
|
||||||
|
) REFERENCES QRTZ_TRIGGERS (
|
||||||
|
SCHED_NAME,
|
||||||
|
TRIGGER_NAME,
|
||||||
|
TRIGGER_GROUP
|
||||||
|
) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD
|
||||||
|
CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY
|
||||||
|
(
|
||||||
|
SCHED_NAME,
|
||||||
|
TRIGGER_NAME,
|
||||||
|
TRIGGER_GROUP
|
||||||
|
) REFERENCES QRTZ_TRIGGERS (
|
||||||
|
SCHED_NAME,
|
||||||
|
TRIGGER_NAME,
|
||||||
|
TRIGGER_GROUP
|
||||||
|
) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD
|
||||||
|
CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY
|
||||||
|
(
|
||||||
|
SCHED_NAME,
|
||||||
|
TRIGGER_NAME,
|
||||||
|
TRIGGER_GROUP
|
||||||
|
) REFERENCES QRTZ_TRIGGERS (
|
||||||
|
SCHED_NAME,
|
||||||
|
TRIGGER_NAME,
|
||||||
|
TRIGGER_GROUP
|
||||||
|
) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE QRTZ_TRIGGERS ADD
|
||||||
|
CONSTRAINT FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS FOREIGN KEY
|
||||||
|
(
|
||||||
|
SCHED_NAME,
|
||||||
|
JOB_NAME,
|
||||||
|
JOB_GROUP
|
||||||
|
) REFERENCES QRTZ_JOB_DETAILS (
|
||||||
|
SCHED_NAME,
|
||||||
|
JOB_NAME,
|
||||||
|
JOB_GROUP
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
40
batch-quartz/src/main/resources/quartz.yml
Normal file
40
batch-quartz/src/main/resources/quartz.yml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
spring:
|
||||||
|
quartz:
|
||||||
|
scheduler:
|
||||||
|
instanceName: batch-quartz
|
||||||
|
instance-id: SYS_PROP
|
||||||
|
name: BatchQuartzScheduler
|
||||||
|
|
||||||
|
org:
|
||||||
|
quartz:
|
||||||
|
jobStore:
|
||||||
|
tablePrefix: QRTZ_
|
||||||
|
isClustered: true
|
||||||
|
misfireThreshold: 2000
|
||||||
|
clusterCheckinInterval: 1000
|
||||||
|
class: org.quartz.impl.jdbcjobstore.JobStoreTX
|
||||||
|
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate #org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
|
||||||
|
acquireTriggersWithinLock: true
|
||||||
|
scheduler:
|
||||||
|
instance-id:
|
||||||
|
instanceName:
|
||||||
|
rmi:
|
||||||
|
export: false
|
||||||
|
proxy: false
|
||||||
|
batchTriggerAcquisitionMaxCount: 20
|
||||||
|
idleWaitTime: 1000
|
||||||
|
skipUpdateCheck: true
|
||||||
|
threadPool:
|
||||||
|
class: org.quartz.simpl.SimpleThreadPool
|
||||||
|
threadCount: 10
|
||||||
|
threadPriority: 5
|
||||||
|
threadsInheritContextClassLoaderOfInitializingThread: true
|
||||||
|
threadNamePrefix: BatchQuartz
|
||||||
|
# dataSource:
|
||||||
|
# nxcus:
|
||||||
|
# driver: org.h2.Driver #oracle.jdbc.driver.OracleDriver
|
||||||
|
# URL: 'jdbc:h2:mem:test' #jdbc:oracle:thin:@polarbear:1521:dev
|
||||||
|
# user: mindol1004
|
||||||
|
# password: 1111
|
||||||
|
# maxConnections: 5
|
||||||
|
# validationQuery: select 0 from dual
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.spring.batch_quartz;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
class BatchQuartzApplicationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user