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