From 2034b5b1bc414860c9b8e17ae36f243c9a40103a Mon Sep 17 00:00:00 2001 From: ham sangki Date: Wed, 28 Feb 2024 16:11:57 +0900 Subject: [PATCH] Init Version 20240228 --- mvnw | 308 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mvnw.cmd | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pom.xml | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/MatchingAiApplication.java | 17 +++++++++++++++++ src/main/java/daeucna/batch/controller/JobController.java | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/batch/request/JobParamsRequest.java | 11 +++++++++++ src/main/java/daeucna/batch/service/JobService.java | 327 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/batch/util/FileUtil.java | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/batch/util/StatisticsUtil.java | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/batch/AsyncConfig.java | 42 ++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/batch/BatchMatchingConfig.java | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/batch/MatchingExtraProcessorAuto.java | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/batch/MatchingItemProcessorAuto.java | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/batch/MatchingItemReader.java | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/batch/MatchingItemWriter.java | 35 +++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/batch/MatchingSetup.java | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/datasource/MultipleDataSourceConfiguration.java | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/datasource/PrimaryMybatisConfiguration.java | 39 +++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/datasource/SecondaryMyBatisConfiguration.java | 36 ++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/handler/RootController.java | 20 ++++++++++++++++++++ src/main/java/daeucna/config/p6spy/P6SpyFomatter.java | 40 ++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/security/JwtSecurityConfig.java | 25 +++++++++++++++++++++++++ src/main/java/daeucna/config/security/SecurityConfig.java | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/security/UserInitializer.java | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/security/controller/AuthController.java | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/security/controller/ExceptionController.java | 22 ++++++++++++++++++++++ src/main/java/daeucna/config/security/controller/UserController.java | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/security/dto/AuthorityDto.java | 28 ++++++++++++++++++++++++++++ src/main/java/daeucna/config/security/dto/LoginDto.java | 25 +++++++++++++++++++++++++ src/main/java/daeucna/config/security/dto/TokenDto.java | 19 +++++++++++++++++++ src/main/java/daeucna/config/security/dto/UserDto.java | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/security/entity/Authority.java | 25 +++++++++++++++++++++++++ src/main/java/daeucna/config/security/entity/User.java | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/security/jwt/JwtAuthenticationEntryPoint.java | 23 +++++++++++++++++++++++ src/main/java/daeucna/config/security/jwt/JwtFilter.java | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/security/jwt/JwtTokenProvider.java | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/security/repository/UserRepository.java | 13 +++++++++++++ src/main/java/daeucna/config/security/service/CustomUserDetailsService.java | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/security/service/UserService.java | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/security/utils/CommonJson.java | 34 ++++++++++++++++++++++++++++++++++ src/main/java/daeucna/config/security/utils/DuplicateMemberException.java | 16 ++++++++++++++++ src/main/java/daeucna/config/security/utils/NotFoundMemberException.java | 16 ++++++++++++++++ src/main/java/daeucna/config/security/utils/SecurityUtil.java | 37 +++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/mapper/primary/batch/MatchingInnerDelingMapper.java | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/daeucna/mapper/primary/system/CodeMapper.java | 12 ++++++++++++ src/main/java/daeucna/mapper/secondary/batch/OracleMapper.java | 32 ++++++++++++++++++++++++++++++++ src/main/java/daeucna/system/code/CodeController.java | 33 +++++++++++++++++++++++++++++++++ src/main/java/daeucna/system/code/CodeDto.java | 28 ++++++++++++++++++++++++++++ src/main/java/daeucna/system/code/CodeService.java | 10 ++++++++++ src/main/java/daeucna/system/code/CodeServiceImpl.java | 36 ++++++++++++++++++++++++++++++++++++ src/main/resources/application.properties | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/resources/data.sql | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/main/resources/matchingSetup.json | 3573 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/resources/mybatis/mybatis-config.xml | 27 +++++++++++++++++++++++++++ src/main/resources/mybatis/primary/batch/MatchingInnerDelingMapper.xml | 542 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/resources/mybatis/primary/system/CodeMapper.xml | 32 ++++++++++++++++++++++++++++++++ src/main/resources/mybatis/secondary/OracleMapper.HN | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/resources/mybatis/secondary/OracleMapper.LS | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/resources/mybatis/secondary/OracleMapper.xml | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/resources/schema.sql | 385 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/test/java/daeucna/MatchingAiApplicationTests.java | 213 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 61 files changed, 8688 insertions(+), 0 deletions(-) create mode 100644 mvnw create mode 100644 mvnw.cmd create mode 100644 pom.xml create mode 100644 src/main/java/daeucna/MatchingAiApplication.java create mode 100644 src/main/java/daeucna/batch/controller/JobController.java create mode 100644 src/main/java/daeucna/batch/request/JobParamsRequest.java create mode 100644 src/main/java/daeucna/batch/service/JobService.java create mode 100644 src/main/java/daeucna/batch/util/FileUtil.java create mode 100644 src/main/java/daeucna/batch/util/StatisticsUtil.java create mode 100644 src/main/java/daeucna/config/batch/AsyncConfig.java create mode 100644 src/main/java/daeucna/config/batch/BatchMatchingConfig.java create mode 100644 src/main/java/daeucna/config/batch/MatchingExtraProcessorAuto.java create mode 100644 src/main/java/daeucna/config/batch/MatchingItemProcessorAuto.java create mode 100644 src/main/java/daeucna/config/batch/MatchingItemReader.java create mode 100644 src/main/java/daeucna/config/batch/MatchingItemWriter.java create mode 100644 src/main/java/daeucna/config/batch/MatchingSetup.java create mode 100644 src/main/java/daeucna/config/datasource/MultipleDataSourceConfiguration.java create mode 100644 src/main/java/daeucna/config/datasource/PrimaryMybatisConfiguration.java create mode 100644 src/main/java/daeucna/config/datasource/SecondaryMyBatisConfiguration.java create mode 100644 src/main/java/daeucna/config/handler/RootController.java create mode 100644 src/main/java/daeucna/config/p6spy/P6SpyFomatter.java create mode 100644 src/main/java/daeucna/config/security/JwtSecurityConfig.java create mode 100644 src/main/java/daeucna/config/security/SecurityConfig.java create mode 100644 src/main/java/daeucna/config/security/UserInitializer.java create mode 100644 src/main/java/daeucna/config/security/controller/AuthController.java create mode 100644 src/main/java/daeucna/config/security/controller/ExceptionController.java create mode 100644 src/main/java/daeucna/config/security/controller/UserController.java create mode 100644 src/main/java/daeucna/config/security/dto/AuthorityDto.java create mode 100644 src/main/java/daeucna/config/security/dto/LoginDto.java create mode 100644 src/main/java/daeucna/config/security/dto/TokenDto.java create mode 100644 src/main/java/daeucna/config/security/dto/UserDto.java create mode 100644 src/main/java/daeucna/config/security/entity/Authority.java create mode 100644 src/main/java/daeucna/config/security/entity/User.java create mode 100644 src/main/java/daeucna/config/security/jwt/JwtAuthenticationEntryPoint.java create mode 100644 src/main/java/daeucna/config/security/jwt/JwtFilter.java create mode 100644 src/main/java/daeucna/config/security/jwt/JwtTokenProvider.java create mode 100644 src/main/java/daeucna/config/security/repository/UserRepository.java create mode 100644 src/main/java/daeucna/config/security/service/CustomUserDetailsService.java create mode 100644 src/main/java/daeucna/config/security/service/UserService.java create mode 100644 src/main/java/daeucna/config/security/utils/CommonJson.java create mode 100644 src/main/java/daeucna/config/security/utils/DuplicateMemberException.java create mode 100644 src/main/java/daeucna/config/security/utils/NotFoundMemberException.java create mode 100644 src/main/java/daeucna/config/security/utils/SecurityUtil.java create mode 100644 src/main/java/daeucna/mapper/primary/batch/MatchingInnerDelingMapper.java create mode 100644 src/main/java/daeucna/mapper/primary/system/CodeMapper.java create mode 100644 src/main/java/daeucna/mapper/secondary/batch/OracleMapper.java create mode 100644 src/main/java/daeucna/system/code/CodeController.java create mode 100644 src/main/java/daeucna/system/code/CodeDto.java create mode 100644 src/main/java/daeucna/system/code/CodeService.java create mode 100644 src/main/java/daeucna/system/code/CodeServiceImpl.java create mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/data.sql create mode 100644 src/main/resources/matchingSetup.json create mode 100644 src/main/resources/mybatis/mybatis-config.xml create mode 100644 src/main/resources/mybatis/primary/batch/MatchingInnerDelingMapper.xml create mode 100644 src/main/resources/mybatis/primary/system/CodeMapper.xml create mode 100644 src/main/resources/mybatis/secondary/OracleMapper.HN create mode 100644 src/main/resources/mybatis/secondary/OracleMapper.LS create mode 100644 src/main/resources/mybatis/secondary/OracleMapper.xml create mode 100644 src/main/resources/schema.sql create mode 100644 src/test/java/daeucna/MatchingAiApplicationTests.java diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..66df285 --- /dev/null +++ b/mvnw @@ -0,0 +1,308 @@ +#!/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.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..95ba6f5 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,205 @@ +@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.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c7c8b2b --- /dev/null +++ b/pom.xml @@ -0,0 +1,178 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.2 + + + com.batch + SpringBatch + 0.0.1-SNAPSHOT + spring_batch + Batch application + + 17 + + + + org.springframework.boot + spring-boot-starter-batch + + + org.springframework.boot + spring-boot-starter-web + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 3.0.3 + + + + org.postgresql + postgresql + runtime + + + com.oracle.database.jdbc + ojdbc11 + runtime + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.mybatis.spring.boot + mybatis-spring-boot-starter-test + 3.0.3 + test + + + org.springframework.batch + spring-batch-test + test + + + org.springframework.boot + spring-boot-devtools + + + + com.github.gavlyukovskiy + p6spy-spring-boot-starter + 1.9.1 + + + + com.google.code.gson + gson + 2.10.1 + + + + org.springframework.batch + spring-batch-integration + 5.1.0 + + + + + org.zeroturnaround + zt-exec + 1.12 + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.3.0 + + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + 3.2.3 + + + + org.springframework.boot + spring-boot-starter-security + 3.2.3 + + + + org.springframework.boot + spring-boot-starter-validation + 3.2.3 + + + + io.jsonwebtoken + jjwt-api + 0.12.5 + + + + io.jsonwebtoken + jjwt-impl + 0.12.5 + runtime + + + + io.jsonwebtoken + jjwt-jackson + 0.12.5 + runtime + + + + org.springframework.security + spring-security-test + 6.2.2 + test + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter-test + 3.0.3 + test + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + + diff --git a/src/main/java/daeucna/MatchingAiApplication.java b/src/main/java/daeucna/MatchingAiApplication.java new file mode 100644 index 0000000..7855a92 --- /dev/null +++ b/src/main/java/daeucna/MatchingAiApplication.java @@ -0,0 +1,17 @@ +package daeucna; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.scheduling.annotation.EnableAsync; + +@EnableAsync +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) +public class MatchingAiApplication { + + public static void main(String[] args) { + SpringApplication.run(MatchingAiApplication.class, args); + + } + +} diff --git a/src/main/java/daeucna/batch/controller/JobController.java b/src/main/java/daeucna/batch/controller/JobController.java new file mode 100644 index 0000000..6e6899e --- /dev/null +++ b/src/main/java/daeucna/batch/controller/JobController.java @@ -0,0 +1,181 @@ +package daeucna.batch.controller; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +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.google.gson.JsonObject; + +import daeucna.batch.service.JobService; +import daeucna.batch.util.FileUtil; +import daeucna.config.batch.MatchingSetup; +import daeucna.config.batch.MatchingSetup.Matching; +import daeucna.mapper.primary.batch.MatchingInnerDelingMapper; +import lombok.extern.slf4j.Slf4j; + +@RestController +@RequestMapping("/api/job") +@Slf4j +public class JobController { + + @Autowired + private JobService jobService; + @Autowired + private MatchingInnerDelingMapper matchingInnerDelingMapper; + + + @PostMapping("/create") + public String createJob( @RequestBody Map params) throws Exception { + + /* + * { + * "sysSe": "LS_ALL", + * "accnutYm": "202306", + * } + */ + log.debug("Start Create Job"); + jobService.createData(params); + log.debug("End Create Job"); + + + return "신규 작업데이타를 생성합니다. 작업이 끝난후 작업결과는 별도로 확인 바랍니다."; + } + + + @PostMapping("/matching") + public String matchingJob( @RequestBody Map params) throws Exception { + + /* + * { + * "sysSe": "LS_ALL", + * "accnutYm": "202306", + * } + */ + log.debug("Start Matching Job"); + jobService.matchingJob(params); + log.debug("End Matching Job"); + + + return "매칭작업을 시작합니다. 작업이 끝난후 작업결과는 별도로 확인 바랍니다."; + } + + @PostMapping("/extramatching") + public String extraMatchingJob( @RequestBody Map params) throws Exception { + + /* + * { + * "sysSe": "LS_ALL", + * "accnutYm": "202306", + * } + */ + log.debug("Start Extra Matching Job"); + List retData = matchingInnerDelingMapper.getCustomItemReadData(params); +// List retData = new ArrayList(); +// Map m = new HashMap(); +// m.put("sys_se", "LS_ALL"); +// m.put("accnut_ym", "202311"); +// m.put("cpr_code", "A15300"); +// m.put("partn_cpr", "A01100"); +// retData.add(m); + for(Map curMap : retData) { + jobService.extraJobSub(curMap); + } + log.debug("End Extra Matching Job"); + + + return "Extra 매칭작업을 시작합니다. 작업이 끝난후 작업결과는 별도로 확인 바랍니다."; + } + + + @PostMapping("/aimatching") + public String aiMatchingJob( @RequestBody Map params) throws Exception { + + /* + * { + * "sysSe": "LS_ALL", + * "accnutYm": "202306", + * } + */ + log.debug("Start AI Matching Job"); + List retData = matchingInnerDelingMapper.getAiReadData(params); + for(Map curMap : retData) { + jobService.aiJobSub(curMap); + } + log.debug("End AI Matching Job"); + + + return "AI 매칭작업을 시작합니다. 작업이 끝난후 작업결과는 별도로 확인 바랍니다."; + } + + @PostMapping("/return") + public String returnJob( @RequestBody Map params) throws Exception { + + /* + * { + * "sysSe": "LS_ALL", + * "accnutYm": "202306", + * } + */ + log.debug("Start Return Job"); + jobService.returnRwsultData(params); + log.debug("End Return Job"); + + + return "매칭결과 반영을 시작합니다. 작업이 끝난후 작업결과는 별도로 확인 바랍니다."; + } + + + @GetMapping("/configJobStr") + public String configJobStr() throws Exception { + + StringBuffer sb = FileUtil.readFileToString("matchingSetup.json"); + + return sb.toString(); + } + + @GetMapping("/configJobJsonObj") + public JsonObject configJobJsonObj() throws Exception { + + StringBuffer sb = FileUtil.readFileToString("matchingSetup.json"); + JsonObject jobj = FileUtil.strToJsonObj(sb.toString()); + + return jobj; + } + + @GetMapping("/configJobObj") + public Object configJobObj() throws Exception { + + StringBuffer sb = FileUtil.readFileToString("matchingSetup.json"); + MatchingSetup matchingSetup = (MatchingSetup) FileUtil.strToObj(sb.toString(), MatchingSetup.class); + + return matchingSetup; + } + + @GetMapping("/config") + public Object config() throws Exception { + return configJobObj(); + } + + @GetMapping("/config/jobList") + public Object configJobList() throws Exception { + + StringBuffer sb = FileUtil.readFileToString("matchingSetup.json"); + MatchingSetup matchingSetup = (MatchingSetup) FileUtil.strToObj(sb.toString(), MatchingSetup.class); + + List lJobList = new ArrayList(); + for (Matching curMatching : matchingSetup.getMatchingSetup()) { + lJobList.add(curMatching.getType() + ':' + curMatching.getTypeName()); + } + + return lJobList; + } + + +} diff --git a/src/main/java/daeucna/batch/request/JobParamsRequest.java b/src/main/java/daeucna/batch/request/JobParamsRequest.java new file mode 100644 index 0000000..a9408a3 --- /dev/null +++ b/src/main/java/daeucna/batch/request/JobParamsRequest.java @@ -0,0 +1,11 @@ +package daeucna.batch.request; + +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +public class JobParamsRequest { + private String paramKey; + private String paramValue; +} \ No newline at end of file diff --git a/src/main/java/daeucna/batch/service/JobService.java b/src/main/java/daeucna/batch/service/JobService.java new file mode 100644 index 0000000..5a46e67 --- /dev/null +++ b/src/main/java/daeucna/batch/service/JobService.java @@ -0,0 +1,327 @@ +package daeucna.batch.service; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.JobParametersInvalidException; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; +import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; +import org.springframework.batch.core.repository.JobRestartException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.zeroturnaround.exec.ProcessExecutor; +import org.zeroturnaround.exec.stream.LogOutputStream; + +import daeucna.batch.util.FileUtil; +import daeucna.config.batch.MatchingExtraProcessorAuto; +import daeucna.config.batch.MatchingSetup; +import daeucna.config.batch.MatchingSetup.Matching; +import daeucna.mapper.primary.batch.MatchingInnerDelingMapper; +import daeucna.mapper.secondary.batch.OracleMapper; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class JobService { + + @Value("${pytyon.path}") + String sPythonPrg; + + @Value("${python.ai.target}") + String sPythonAiTarget; + + @Autowired + private JobLauncher jobLauncher; + + @Autowired + private ApplicationContext context; + + @Autowired + private MatchingInnerDelingMapper matchingInnerDelingMapper; + + @Autowired + private OracleMapper oracleMapper; + + + @SuppressWarnings("rawtypes") + @Async("commAsync") + public void matchingJob( Map params) throws Exception { + + long startTime = System.currentTimeMillis(); + log.info("Job Started : " + startTime); + log.debug("params=" + params.toString()); + + StringBuffer sb = FileUtil.readFileToString("matchingSetup.json"); + MatchingSetup matchingSetup = (MatchingSetup) FileUtil.strToObj(sb.toString(), MatchingSetup.class); + + String sJobTypeList = params.get("jobType").toUpperCase(); + List lJobType = Arrays.asList(sJobTypeList != null?sJobTypeList.split(","):new String[0]); + + //파라미터가 ALL일 경우 ALL 대신 등록된 모든 Type를 넣어준다. + if (lJobType.size() > 0 && lJobType.indexOf("ALL") != -1) { + lJobType = new ArrayList(); + for (Matching matching : matchingSetup.getMatchingSetup()) { + if (matching.getActive()) { + lJobType.add(matching.getType()); + } else { + log.info("JobType(" + matching.getType() + ") is Disabled"); + } + } + } + + + for (String sJobType : lJobType) { + log.info("Current running job type: " + sJobType); + JobExecution jobExe = invokeJob("matchingInnerDelng", sJobType, params); + if (!jobExe.getStatus().equals(BatchStatus.COMPLETED)) { + throw new Exception("Job execution error : Batchstatus(" + jobExe.getStatus() + "), ExitStatus(" + jobExe.getExitStatus() + ")" ); + } + } + + long endTime = System.currentTimeMillis(); + log.info("Job Type : " + lJobType.toString()); + log.info("Job Ended: " + endTime); + log.info("Running Time : " + (endTime - startTime) + "ms"); + + } + + + @SuppressWarnings("rawtypes") + @Async("aiAsync") + public void extraJobSub(Map paramRec) throws Exception { + + long startTime = System.currentTimeMillis(); + log.info("Job Started : " + startTime); + log.debug("params=" + paramRec.toString()); + + MatchingExtraProcessorAuto matchingExtraProcessorAuto = new MatchingExtraProcessorAuto(matchingInnerDelingMapper); + + //2건씩 합산 매칭일 경우 최대 20000건 까지 + for (int i=0; i<20000;i=i+1000) { + matchingExtraProcessorAuto.process(paramRec, 1, 2, 0, i); + } + for (int i=0; i<20000;i=i+1000) { + matchingExtraProcessorAuto.process(paramRec, 2, 1, i, 0); + } + for (int i=0; i<20000;i=i+1000) { + matchingExtraProcessorAuto.process(paramRec, 2, 2, i, i); + } + + //3건씩 매칭일 경우 최대 5000건 까지 + for (int i=0; i<2000;i=i+100) { + matchingExtraProcessorAuto.process(paramRec, 1, 3, 0, i); + } + for (int i=0; i<2000;i=i+100) { + matchingExtraProcessorAuto.process(paramRec, 3, 1, i, 0); + } + + long endTime = System.currentTimeMillis(); + log.info("Job Ended: " + endTime); + log.info("Running Time : " + (endTime - startTime) + "ms"); + + } + + @SuppressWarnings("rawtypes") + @Async("aiAsync") + public void aiJobSub(Map paramRec) throws Exception { + + + //Job Create Log + UUID uuid = UUID.randomUUID(); + HashMap mt = new HashMap(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss"); + String sDate = dateFormat.format(new Date()) + ":" + uuid.toString(); + + Map paramLog = new HashMap(); + paramLog.put("user_job_id", sDate); + paramLog.put("user_job_name", "AI매칭(" + paramRec.toString() + ")"); + matchingInnerDelingMapper.createUserJob(paramLog); + + + long startTime = System.currentTimeMillis(); + log.info("Job Started : " + startTime); + log.debug("params=" + paramRec.toString()); + + String sSysSe = (String) paramRec.get("sys_se"); + String sAccnutYm = (String) paramRec.get("accnut_ym"); + String sCprCode = (String) paramRec.get("cpr_code"); + String sPartCpr = (String) paramRec.get("partn_cpr"); + String sDelngCrncy = (String) paramRec.get("delng_crncy"); + + log.debug("call python"); + new ProcessExecutor() + .command(sPythonPrg, sPythonAiTarget, sSysSe, sAccnutYm, sCprCode, sPartCpr, sDelngCrncy) + .redirectOutput(new LogOutputStream() { + @Override + protected void processLine(String line) { + log.info(line); + } + }) + .execute(); + + long endTime = System.currentTimeMillis(); + log.info("Job Ended: " + endTime); + log.info("Running Time : " + (endTime - startTime) + "ms"); + + + //작업종료에 대한 로그 업데이트 + paramLog.put("exit_code", "0"); + paramLog.put("exit_message", ""); + matchingInnerDelingMapper.finishUserJob(paramLog); + + } + + + + public JobExecution invokeJob(String jobName, String jobType, Map params) throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + + UUID uuid = UUID.randomUUID(); + HashMap mt = new HashMap(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss"); + final String date = dateFormat.format(new Date()) + ":" + uuid.toString(); + JobParameters jobParameters = new JobParametersBuilder() + .addString("syncDate", date) + .addString("jobType", jobType) + .addString("sysSe", params.get("sysSe")) + .addString("accnutYm", params.get("accnutYm")) + .addString("searchCond", params.get("searchCond")) + .toJobParameters(); + + var jobToStart = context.getBean(jobName, Job.class); + JobExecution jobExe = jobLauncher.run(jobToStart, jobParameters); + + return jobExe; + } + + + + @SuppressWarnings("rawtypes") + @Async("commAsync") + public void createData( Map params) throws Exception { + + //Job Create Log + UUID uuid = UUID.randomUUID(); + HashMap mt = new HashMap(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss"); + String sDate = dateFormat.format(new Date()) + ":" + uuid.toString(); + + Map paramLog = new HashMap(); + paramLog.put("user_job_id", sDate); + paramLog.put("user_job_name", "작업데이타생성(" + params.toString() + ")"); + matchingInnerDelingMapper.createUserJob(paramLog); + + + long startTime = System.currentTimeMillis(); + log.info("Create Data Started : " + startTime); + log.debug("params=" + params.toString()); + + //기존데이타 삭제 + int iDeleted = matchingInnerDelingMapper.deleteOriginalData(params); + log.debug("Deleted OrgData : " + iDeleted + "건"); + + //신규데이타 생성 + //매칭키에 대한 정보 (sql로 조인하여 조회하기에는 너무 느리고 데이타 중복도 발생함) + List lMatchingInfo = oracleMapper.getMatchingInfo(params); + Map mMatchingInfo = new HashMap(); + for (Map curMap : lMatchingInfo) { + String sKey = String.valueOf(curMap.get("SEQ")); + mMatchingInfo.put(sKey, curMap); + } + + List lOrgData = oracleMapper.getOriginalData(params); + int iInserted = 0; + int limit = 1000; //1000건씩 batch + List lInserted = new ArrayList(); + for (Map curRec : lOrgData) { + String sKey = String.valueOf(curRec.get("SEQ")); + Map curMatchingInfo = mMatchingInfo.get(sKey); + if (curMatchingInfo != null) { + curRec.put("MATCHING_CAUSE", curMatchingInfo.get("MATCHING_CAUSE")); + curRec.put("MATCH_KEY", curMatchingInfo.get("MATCH_KEY")); + } + lInserted.add(curRec); + if (lInserted.size() == limit) { + matchingInnerDelingMapper.insertOriginalData(Map.of("itemList", lInserted)); + iInserted = iInserted + lInserted.size(); + lInserted.clear(); + } + } + if (lInserted.size() > 0) { + matchingInnerDelingMapper.insertOriginalData(Map.of("itemList", lInserted)); + iInserted = iInserted + lInserted.size(); + } + log.info("Inserted OrgData : " + iInserted + "건"); + + iDeleted = matchingInnerDelingMapper.deleteData(params); + log.debug("Deleted Work Data : " + iDeleted + "건"); + iInserted = matchingInnerDelingMapper.insertDataFromOriginal(params); + log.info("Inserted Work Data : " + iInserted + "건"); + + iDeleted = matchingInnerDelingMapper.deleteDataAi(params); + log.debug("Deleted Work AI Data : " + iDeleted + "건"); + iInserted = matchingInnerDelingMapper.insertDataAiFromOriginal(params); + log.info("Inserted Work AI Data : " + iInserted + "건"); + + long endTime = System.currentTimeMillis(); + log.info("Create Data Ended : " + endTime); + log.info("Running Time : " + (endTime - startTime) + "ms"); + + //작업종료에 대한 로그 업데이트 + paramLog.put("exit_code", "0"); + paramLog.put("exit_message", ""); + matchingInnerDelingMapper.finishUserJob(paramLog); + + } + + + + @SuppressWarnings("rawtypes") + @Async("commAsync") + public void returnRwsultData( Map params) throws Exception { + + //Job Create Log + UUID uuid = UUID.randomUUID(); + HashMap mt = new HashMap(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss"); + String sDate = dateFormat.format(new Date()) + ":" + uuid.toString(); + + Map paramLog = new HashMap(); + paramLog.put("user_job_id", sDate); + paramLog.put("user_job_name", "결과데이타리턴(" + params.toString() + ")"); + matchingInnerDelingMapper.createUserJob(paramLog); + + long startTime = System.currentTimeMillis(); + log.info("Update Data Started : " + startTime); + log.debug("params=" + params.toString()); + + //기존데이타 삭제 + int iUpdated = matchingInnerDelingMapper.updateNewMatchKey(params); + log.debug("Updated OrgData : " + iUpdated + "건"); + + long endTime = System.currentTimeMillis(); + log.info("Update Data Ended : " + endTime); + log.info("Running Time : " + (endTime - startTime) + "ms"); + + + //작업종료에 대한 로그 업데이트 + paramLog.put("exit_code", "0"); + paramLog.put("exit_message", ""); + matchingInnerDelingMapper.finishUserJob(paramLog); + + } +} diff --git a/src/main/java/daeucna/batch/util/FileUtil.java b/src/main/java/daeucna/batch/util/FileUtil.java new file mode 100644 index 0000000..60ff251 --- /dev/null +++ b/src/main/java/daeucna/batch/util/FileUtil.java @@ -0,0 +1,48 @@ +package daeucna.batch.util; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +import org.springframework.core.io.ClassPathResource; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class FileUtil { + + public static StringBuffer readFileToString(String resourceName) { + StringBuffer sb = new StringBuffer(); + try { + ClassPathResource resource = new ClassPathResource(resourceName); + BufferedReader br = new BufferedReader(new InputStreamReader(resource.getInputStream())); + + // br.readLine() 이 null 인지 검사할 때 한번 사용되므로 String 에 먼저 저장해둬야한다. + String s = ""; + while((s = br.readLine()) != null){ + sb.append(s); + } + } catch (Exception e) { + sb.append(e.getStackTrace()); + } + return sb; + } + + public static JsonObject strToJsonObj(String jsonString) { + JsonObject jsonObject = JsonParser.parseString(jsonString).getAsJsonObject(); + return jsonObject; + } + + public static Object strToObj(String jsonString, Class anyClass) { + Gson gson = new Gson(); + Object convertedObject = gson.fromJson(jsonString, anyClass); + return convertedObject; + } + + public static String objToStr(Object obj) { + Gson gson = new Gson(); + String stringObject = gson.toJson(obj); + return stringObject; + } + +} diff --git a/src/main/java/daeucna/batch/util/StatisticsUtil.java b/src/main/java/daeucna/batch/util/StatisticsUtil.java new file mode 100644 index 0000000..6ed3d5b --- /dev/null +++ b/src/main/java/daeucna/batch/util/StatisticsUtil.java @@ -0,0 +1,58 @@ +package daeucna.batch.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class StatisticsUtil { + +// public static void main(String[] args) { +// +// List arr = new ArrayList(); +// arr.add(Map.of("col", 100)); +// arr.add(Map.of("col", 200)); +// arr.add(Map.of("col", 300)); +// arr.add(Map.of("col", 400)); +// arr.add(Map.of("col", 500)); +// +// List result = new ArrayList(); +// List> resultAll = new ArrayList>(); +// reculsion(arr, result, 3, arr.size(), 2, resultAll); +// +// log.info("resultAll=" + resultAll.toString()); +// } + + /** + * 조합 구하기 + * + * @param arr : 기준 리스트 + * @param result : 결과를 담아줄 리스트 + * @param index : 반복문 시작 인덱스 + * @param n : 전체 갯수 + * @param r : 뽑을 갯수 + */ + public static void reculsion(List arr, List result, int index, int n, int r, List> resultAll) { + + if (r == 0) { + + log.debug("Reuslt=" + result.toString()); + List lmConfirmList = new ArrayList(); + lmConfirmList.addAll(result); + resultAll.add(lmConfirmList); + + return; + } + + for (int i = index; i < n; i++) { + + result.add(arr.get(i)); + reculsion(arr, result, i + 1, n, r - 1, resultAll); + result.remove(result.size() - 1); + } + + } + +} diff --git a/src/main/java/daeucna/config/batch/AsyncConfig.java b/src/main/java/daeucna/config/batch/AsyncConfig.java new file mode 100644 index 0000000..4d3b30d --- /dev/null +++ b/src/main/java/daeucna/config/batch/AsyncConfig.java @@ -0,0 +1,42 @@ +package daeucna.config.batch; + +import java.util.concurrent.Executor; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +@Configuration +@EnableAsync +public class AsyncConfig { + + @Bean(name = "commAsync") + public Executor commAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(5); + executor.setMaxPoolSize(50); + executor.setKeepAliveSeconds(30); + executor.setAllowCoreThreadTimeOut(true); + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setThreadNamePrefix("commAsync-processor-"); + executor.initialize(); + + return executor; + } + + @Bean(name = "aiAsync") + public Executor aiAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(50); + executor.setMaxPoolSize(100); + executor.setQueueCapacity(1000); + executor.setKeepAliveSeconds(30); + executor.setAllowCoreThreadTimeOut(true); + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setThreadNamePrefix("aiAsync-processor-"); + executor.initialize(); + + return executor; + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/batch/BatchMatchingConfig.java b/src/main/java/daeucna/config/batch/BatchMatchingConfig.java new file mode 100644 index 0000000..d525d66 --- /dev/null +++ b/src/main/java/daeucna/config/batch/BatchMatchingConfig.java @@ -0,0 +1,109 @@ +package daeucna.config.batch; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.configuration.annotation.JobScope; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.launch.support.RunIdIncrementer; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.item.adapter.ItemWriterAdapter; +import org.springframework.batch.item.support.CompositeItemProcessor; +import org.springframework.batch.item.support.ListItemReader; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.PlatformTransactionManager; + +import daeucna.mapper.primary.batch.MatchingInnerDelingMapper; +import lombok.extern.slf4j.Slf4j; + +@Configuration +@Slf4j +public class BatchMatchingConfig { + + final JobRepository jobRepository; + final PlatformTransactionManager batchTransactionManager; + private static final int BATCH_SIZE = 50; + + @Autowired + MatchingInnerDelingMapper matchingInnerDelingMapper; + @Autowired + MatchingItemReader customItemReader; + @Autowired + MatchingItemWriter> matchingItemWriter; + + public BatchMatchingConfig(JobRepository jobRepository, PlatformTransactionManager batchTransactionManager) { + this.jobRepository = jobRepository; + this.batchTransactionManager = batchTransactionManager; + } + + /** + * Job which contains multiple steps + */ + @Bean + public Job matchingInnerDelng() { + return new JobBuilder("자료매칭 job", jobRepository) + .incrementer(new RunIdIncrementer()) + .start(chunkStep()) + .build(); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Bean + @JobScope + public Step chunkStep() { + log.debug("chunkStep"); + return new StepBuilder("자료매칭 step", jobRepository) + .chunk(BATCH_SIZE, batchTransactionManager) + .reader(reader()) + .processor(compositeProcessor()) + .writer(writer()) + .build(); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Bean + public CompositeItemProcessor compositeProcessor() { + log.debug("CompositeItemProcessor"); + + List delegates = new ArrayList<>(2); + MatchingItemProcessorAuto customItemProcessorAuto = new MatchingItemProcessorAuto(); + customItemProcessorAuto.setMapper(matchingInnerDelingMapper); + delegates.add(customItemProcessorAuto); + + CompositeItemProcessor processor = new CompositeItemProcessor(); + + processor.setDelegates(delegates); + + return processor; + } + + @Bean + @JobScope + public ItemReader reader() { + + log.debug("run ItemReader"); + + List lmData = customItemReader.customRead(); + return new ListItemReader<>(lmData); + } + + @Bean + public ItemWriter writer() { + + ItemWriterAdapter writer = new ItemWriterAdapter<>(); + writer.setTargetObject(matchingItemWriter); // 대상 클래스 + writer.setTargetMethod("customWrite"); // 대상 메서드 + return writer; + } + + +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/batch/MatchingExtraProcessorAuto.java b/src/main/java/daeucna/config/batch/MatchingExtraProcessorAuto.java new file mode 100644 index 0000000..2bdfe7d --- /dev/null +++ b/src/main/java/daeucna/config/batch/MatchingExtraProcessorAuto.java @@ -0,0 +1,226 @@ +package daeucna.config.batch; + +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import daeucna.batch.util.StatisticsUtil; +import daeucna.mapper.primary.batch.MatchingInnerDelingMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RequiredArgsConstructor +public class MatchingExtraProcessorAuto { + + private final MatchingInnerDelingMapper matchingInnerDelingMapper; + + @SuppressWarnings("unchecked") + public void process(Map paramRec, int iCmbnOwnCnt, int iCmbnTranCnt, int iStartOwn, int iStartTran) throws Exception { + + //Job Create Log + UUID uuid = UUID.randomUUID(); + HashMap mt = new HashMap(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss"); + String sDate = dateFormat.format(new Date()) + ":" + uuid.toString(); + + Map paramLog = new HashMap(); + paramLog.put("user_job_id", sDate); + paramLog.put("user_job_name", "자동조합매칭(" + paramRec.toString() + ",[" + iCmbnOwnCnt + "," + iStartOwn + "],[" + iCmbnTranCnt + "," + iStartTran + "])"); + matchingInnerDelingMapper.createUserJob(paramLog); + + + int iUpdated = 0; + + String sSysSe = (String) paramRec.get("sys_se"); + String sAccnutYm = (String) paramRec.get("accnut_ym"); + String sCprCode = (String) paramRec.get("cpr_code"); + String sPartCpr = (String) paramRec.get("partn_cpr"); + + //작업시작 + Map mParam = new HashMap(); + mParam.put("sysSe", sSysSe); + mParam.put("accnutYm", sAccnutYm); + + //---------------------------------------------------------------------------- + //자기법인 데이타 가져오기 + mParam.put("cprCode", sCprCode); + mParam.put("partnCpr", sPartCpr); + List lMatchingDataOne = matchingInnerDelingMapper.getMatchingExtraDataOne(mParam); + + //상대법인 데이타 가져오기 + mParam.put("cprCode", sPartCpr); + mParam.put("partnCpr", sCprCode); + List lMatchingDataTwo = matchingInnerDelingMapper.getMatchingExtraDataTwo(mParam); + + //Combination 데이타 만들기 + List compResult = new ArrayList(); + List> llMatchingDataOne = new ArrayList>(); + List> llMatchingDataTwo = new ArrayList>(); + + int iEndOwn = lMatchingDataOne.size(); + if (iCmbnOwnCnt == 2) { + iEndOwn = iStartOwn + 1000; + if (iEndOwn > lMatchingDataOne.size()) iEndOwn = lMatchingDataOne.size(); + } + if (iCmbnOwnCnt > 2) { + iEndOwn = iStartOwn + 100; + if (iEndOwn > lMatchingDataOne.size()) iEndOwn = lMatchingDataOne.size(); + } + int iEndTran = lMatchingDataTwo.size(); + if (iCmbnTranCnt == 2) { + iEndTran = iStartTran + 1000; + if (iEndTran > lMatchingDataTwo.size()) iEndTran = lMatchingDataTwo.size(); + } + if (iCmbnTranCnt > 2) { + iEndTran = iStartTran + 100; + if (iEndTran > lMatchingDataTwo.size()) iEndTran = lMatchingDataTwo.size(); + } + + StatisticsUtil.reculsion(lMatchingDataOne, compResult, iStartOwn, iEndOwn, iCmbnOwnCnt, llMatchingDataOne); + StatisticsUtil.reculsion(lMatchingDataTwo, compResult, iStartTran, iEndTran, iCmbnTranCnt, llMatchingDataTwo); + + //---------------------------------------------------------------------------- + //자기법인 데이타를 맵으로 처리한다. + Map>> mMatchingDataOne = new HashMap>>(); + for (List curlMap : llMatchingDataOne) { + BigDecimal bdKey = BigDecimal.ZERO; + for(Map curMap : curlMap) { + bdKey = bdKey.add((BigDecimal) curMap.get("delng_amt")); + } + List> curllMap = new ArrayList>(); + if (mMatchingDataOne.containsKey(bdKey)) curllMap = mMatchingDataOne.get(bdKey); + curllMap.add(curlMap); + mMatchingDataOne.put(bdKey, curllMap); + } + + //상대법인 데이타를 맵으로 처리한다. + Map>> mMatchingDataTwo = new HashMap>>(); + for (List curlMap : llMatchingDataTwo) { + BigDecimal bdKey = BigDecimal.ZERO; + for(Map curMap : curlMap) { + bdKey = bdKey.add((BigDecimal) curMap.get("delng_amt")); + } + List> curllMap = new ArrayList>(); + if (mMatchingDataTwo.containsKey(bdKey)) curllMap = mMatchingDataTwo.get(bdKey); + curllMap.add(curlMap); + mMatchingDataTwo.put(bdKey, curllMap); + } + + //여기서 매칭 비교 + //비교 lMatchingDataOne vs mMatchingDataTwo + List lMatchingResultUpdate = new ArrayList(); //업데이트할 대상 + + int mtchNumber = 0; + String mtchSys = "AUTO"; + String mtchType = "EX_" + iCmbnOwnCnt + "_" + iCmbnTranCnt; + String mtchTypeName = "자기(" + iCmbnOwnCnt + "건Sum), 상대(" + iCmbnTranCnt + "건Sum), 비교(금액)"; + for (BigDecimal curKey : mMatchingDataOne.keySet()) { + if (mMatchingDataTwo.containsKey(curKey)) { + List> llMapOne = mMatchingDataOne.get(curKey); + List> llMapTwo = mMatchingDataTwo.get(curKey); + + //위와 관련된 동일 레코드가 있는 리스트 삭제 + for (int i=llMapOne.size()-1; i>=0;i--) { + List curlMap = llMapOne.get(i); + for (Map curMap : lMatchingResultUpdate) { + int curIdx = curlMap.indexOf(curMap); + if (curIdx != -1) { + llMapOne.remove(i); + break; + } + } + } + for (int i=llMapTwo.size()-1; i>=0;i--) { + List curlMap = llMapTwo.get(i); + for (Map curMap : lMatchingResultUpdate) { + int curIdx = curlMap.indexOf(curMap); + if (curIdx != -1) { + llMapTwo.remove(i); + break; + } + } + } + + + int iMin = Math.min(llMapOne.size(), llMapTwo.size()); + if (iMin > 0) mtchNumber++; + while (iMin > 0) { + List curlMapOne = llMapOne.get(0); + for (Map curMap : curlMapOne) { + curMap.put("mtch_sys", mtchSys); + curMap.put("mtch_ty", mtchType); + curMap.put("mtch_ty_nm", mtchTypeName); + curMap.put("mtch_ky", mtchNumber); + lMatchingResultUpdate.add(curMap); + } + llMapOne.remove(0); + + List curlMapTwo = llMapTwo.get(0); + for (Map curMap : curlMapTwo) { + curMap.put("mtch_sys", mtchSys); + curMap.put("mtch_ty", mtchType); + curMap.put("mtch_ty_nm", mtchTypeName); + curMap.put("mtch_ky", mtchNumber); + lMatchingResultUpdate.add(curMap); + } + llMapTwo.remove(0); + + //위와 관련된 동일 레코드가 있는 리스트 삭제(추가 업데이트 목록) + for (int i=llMapOne.size()-1; i>=0;i--) { + List curlMap = llMapOne.get(i); + for (Map curMap : curlMapOne) { + int curIdx = curlMap.indexOf(curMap); + if (curIdx != -1) { + llMapOne.remove(i); + break; + } + } + } + for (int i=llMapTwo.size()-1; i>=0;i--) { + List curlMap = llMapTwo.get(i); + for (Map curMap : curlMapTwo) { + int curIdx = curlMap.indexOf(curMap); + if (curIdx != -1) { + llMapTwo.remove(i); + break; + } + } + } + iMin = Math.min(llMapOne.size(), llMapTwo.size()); + } + } + } + + //---------------------------------------------------------------------------- + //여기서 결과 업데이트 + iUpdated = 0; + int limit = 1000; //1000건씩 batch + List lUpdated = new ArrayList(); + for (Map curMap : lMatchingResultUpdate) { + lUpdated.add(curMap); + if (lUpdated.size() == limit) { + matchingInnerDelingMapper.setExtraResult(Map.of("itemList", lUpdated)); + iUpdated = iUpdated + lUpdated.size(); + lUpdated.clear(); + } + } + if (lUpdated.size() > 0) { + matchingInnerDelingMapper.setExtraResult(Map.of("itemList", lUpdated)); + iUpdated = iUpdated + lUpdated.size(); + } + log.debug("Updated OrgData : " + iUpdated + "건"); + + //작업종료에 대한 로그 업데이트 + paramLog.put("exit_code", "0"); + paramLog.put("exit_message", ""); + matchingInnerDelingMapper.finishUserJob(paramLog); + + } + +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/batch/MatchingItemProcessorAuto.java b/src/main/java/daeucna/config/batch/MatchingItemProcessorAuto.java new file mode 100644 index 0000000..8ec0724 --- /dev/null +++ b/src/main/java/daeucna/config/batch/MatchingItemProcessorAuto.java @@ -0,0 +1,214 @@ +package daeucna.config.batch; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.batch.core.configuration.annotation.StepScope; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.stereotype.Component; + +import daeucna.config.batch.MatchingSetup.Cond; +import daeucna.config.batch.MatchingSetup.Matching; +import daeucna.mapper.primary.batch.MatchingInnerDelingMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@StepScope +@Component +@RequiredArgsConstructor +public class MatchingItemProcessorAuto implements ItemProcessor { + + MatchingInnerDelingMapper matchingInnerDelingMapper; + + public void setMapper(MatchingInnerDelingMapper matchingInnerDelingMapper) { + this.matchingInnerDelingMapper = matchingInnerDelingMapper; + } + + @SuppressWarnings("unchecked") + public Map process(Map item) throws Exception { + Map params = new HashMap((Map) item.get("jobParameters")); + Matching matching = (Matching) item.get("matchingType"); + Cond condOne = matching.getCondOne(); + Cond condTwo = matching.getCondTwo(); + List lCompareField = matching.getCompareField(); + String mtchType = matching.getType(); + String mtchTypeName = matching.getTypeName(); + int mtchNumber = 0; + int iUpdated = 0; + + log.debug("CustomItemProcessorA.params : " + params.toString()); + log.debug("CustomItemProcessorA.item : " + item.get("cpr_code") + "," + item.get("partn_cpr")); + + //---------------------------------------------------------------------------- + //자기법인 업데이트 + params.put("cprCode", item.get("cpr_code")); + params.put("partnCpr", item.get("partn_cpr")); + + params.put("cond", condOne.getCond() ); //조건리스트 + params.put("compareKey", matching.getCompareKey() ); + params.put("makeCompareKey", "'" + mtchType + ":' || " + condOne.getMakeCompareKey() ); + + iUpdated = matchingInnerDelingMapper.setDataMakeCompareKy(params); + log.debug("matchingInnerDelingMapper.setDataMakeCompareKy ; " + iUpdated); + + //상대법인업데이트 + params.put("cprCode", item.get("partn_cpr")); + params.put("partnCpr", item.get("cpr_code")); + + params.put("cond", condTwo.getCond() ); //조건리스트 + params.put("compareKey", matching.getCompareKey() ); + params.put("makeCompareKey", "'" + mtchType + ":' || " + condTwo.getMakeCompareKey() ); + + iUpdated = matchingInnerDelingMapper.setDataMakeCompareKy(params); + log.debug("matchingInnerDelingMapper.setDataMakeCompareKy ; " + iUpdated); + + //---------------------------------------------------------------------------- + //자기법인 데이타 가져오기 + params.put("cprCode", item.get("cpr_code")); + params.put("partnCpr", item.get("partn_cpr")); + params.put("amtField", matching.getAmtField()); + params.put("cond", condOne.getCond() ); //조건리스트 + List lMatchingDataOne = matchingInnerDelingMapper.getMatchingData(params); + + //상대법인 데이타 가져오기 + params.put("cprCode", item.get("partn_cpr")); + params.put("partnCpr", item.get("cpr_code")); + params.put("amtField", matching.getAmtField()); + params.put("cond", condTwo.getCond() ); //조건리스트 + List lMatchingDataTwo = matchingInnerDelingMapper.getMatchingData(params); + + //---------------------------------------------------------------------------- + //자기법인 데이타를 맵으로 처리한다. + Map> mMatchingDataOne = new HashMap>(); + for (Map curMap : lMatchingDataOne) { + StringBuffer sbKey = new StringBuffer(); + for (String curField : lCompareField) { + if (sbKey.length() > 0) sbKey.append(":"); + sbKey.append(curMap.get(curField).toString()); + } + + List curlMap = new ArrayList(); + String sKey = sbKey.toString(); + if (mMatchingDataOne.containsKey(sKey)) curlMap = mMatchingDataOne.get(sKey); + curlMap.add(curMap); + mMatchingDataOne.put(sKey, curlMap); + } + + //상대법인 데이타를 맵으로 처리한다. + Map> mMatchingDataTwo = new HashMap>(); + for (Map curMap : lMatchingDataTwo) { + StringBuffer sbKey = new StringBuffer(); + for (String curField : lCompareField) { + if (sbKey.length() > 0) sbKey.append(":"); + sbKey.append(curMap.get(curField).toString()); + } + + List curlMap = new ArrayList(); + String sKey = sbKey.toString(); + if (mMatchingDataTwo.containsKey(sKey)) curlMap = mMatchingDataTwo.get(sKey); + curlMap.add(curMap); + mMatchingDataTwo.put(sKey, curlMap); + } + + //여기서 매칭 비교 + //비교 lMatchingDataOne vs mMatchingDataTwo + for (String curKey : mMatchingDataOne.keySet()) { + if (mMatchingDataTwo.containsKey(curKey)) { + List lMapOne = mMatchingDataOne.get(curKey); + List lMapTwo = mMatchingDataTwo.get(curKey); + + int iMin = Math.min(lMapOne.size(), lMapTwo.size()); + if (iMin > 0) mtchNumber++; + for (int i=0; i lMatchingResultUpdate = new ArrayList(); //업데이트할 대상 + String sCompareKey = matching.getCompareKey(); + + //자기법인 데이타 가져오기 + params.put("cprCode", item.get("cpr_code")); + params.put("partnCpr", item.get("partn_cpr")); + params.put("cond", condOne.getCond() ); //조건리스트 + List lMatchingResultOne = matchingInnerDelingMapper.getMatchingResult(params); + + Map mMatchingResultOne = new HashMap(); + for (Map curMap : lMatchingDataOne) { + String curComapreKeyVal = (String)curMap.get(sCompareKey); + boolean curBlnMatching = curMap.get("mtchType")!=null && curMap.get("mtchNumber")!=null; + if (curBlnMatching) mMatchingResultOne.put(curComapreKeyVal, curMap); + } + for (Map curMap : lMatchingResultOne) { + String curComapreKeyVal = (String)curMap.get(sCompareKey); + if ( mMatchingResultOne.containsKey(curComapreKeyVal) ) { + Map mResult = mMatchingResultOne.get(curComapreKeyVal); + curMap.put(matching.getMatchingType() , mResult.get("mtchType")); + curMap.put(matching.getMatchingTypeName(), mResult.get("mtchTypeName")); + curMap.put(matching.getMatchingNumber(), mResult.get("mtchNumber")); + lMatchingResultUpdate.add(curMap); + } + } + + //상대법인 데이타 가져오기 + params.put("cprCode", item.get("partn_cpr")); + params.put("partnCpr", item.get("cpr_code")); + params.put("cond", condTwo.getCond() ); //조건리스트 + List lMatchingResultTwo = matchingInnerDelingMapper.getMatchingResult(params); + + Map mMatchingResultTwo = new HashMap(); + for (Map curMap : lMatchingDataTwo) { + String curComapreKeyVal = (String)curMap.get(sCompareKey); + boolean curBlnMatching = curMap.get("mtchType")!=null && curMap.get("mtchNumber")!=null; + if (curBlnMatching) mMatchingResultTwo.put(curComapreKeyVal, curMap); + } + for (Map curMap : lMatchingResultTwo) { + String curComapreKeyVal = (String)curMap.get(sCompareKey); + if ( mMatchingResultTwo.containsKey(curComapreKeyVal) ) { + Map mResult = mMatchingResultTwo.get(curComapreKeyVal); + curMap.put(matching.getMatchingType() , mResult.get("mtchType")); + curMap.put(matching.getMatchingTypeName(), mResult.get("mtchTypeName")); + curMap.put(matching.getMatchingNumber(), mResult.get("mtchNumber")); + lMatchingResultUpdate.add(curMap); + } + } + + iUpdated = 0; + int limit = 1000; //1000건씩 batch + List lUpdated = new ArrayList(); + for (Map curMap : lMatchingResultUpdate) { + curMap.put("matchingType", matching.getMatchingType()); + curMap.put("matchingTypeVal", curMap.get(matching.getMatchingType())); + curMap.put("matchingTypeName", matching.getMatchingTypeName()); + curMap.put("matchingTypeNameVal", curMap.get(matching.getMatchingTypeName())); + curMap.put("matchingNumber", matching.getMatchingNumber()); + curMap.put("matchingNumberVal", curMap.get(matching.getMatchingNumber())); + lUpdated.add(curMap); + if (lUpdated.size() == limit) { + matchingInnerDelingMapper.setResult(Map.of("itemList", lUpdated)); + iUpdated = iUpdated + lUpdated.size(); + lUpdated.clear(); + } + } + if (lUpdated.size() > 0) { + matchingInnerDelingMapper.setResult(Map.of("itemList", lUpdated)); + iUpdated = iUpdated + lUpdated.size(); + } + log.debug("Updated OrgData : " + iUpdated + "건"); + + //작업이 정상적으로 작동 되었을 경우 현재 처리하고 있는 데이타 그대로 넘겨준다. + return item; + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/batch/MatchingItemReader.java b/src/main/java/daeucna/config/batch/MatchingItemReader.java new file mode 100644 index 0000000..1e2aa1a --- /dev/null +++ b/src/main/java/daeucna/config/batch/MatchingItemReader.java @@ -0,0 +1,52 @@ +package daeucna.config.batch; + +import java.util.List; +import java.util.Map; + +import org.springframework.batch.core.configuration.annotation.StepScope; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import daeucna.batch.util.FileUtil; +import daeucna.config.batch.MatchingSetup.Matching; +import daeucna.mapper.primary.batch.MatchingInnerDelingMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +@StepScope +@RequiredArgsConstructor +public class MatchingItemReader { + + @Value("#{jobParameters}") + private final Map params; + + @Autowired + MatchingInnerDelingMapper matchingInnerDelingMapper; + + /* + * 자기 상대 법인단위로 작업할 단위를 읽는다. + */ + public List customRead(){ + log.debug("customRead.params : " + this.params.toString()); + // customRead.params : {sysSe=KUMKANG, searchCond=mtch_ky is null, run.id=1, syncDate=2024-02-02-03-52-27:50deede8-ce3d-4841-ba65-f733bdd38533, jobType=F, accnutYm=202112} + String sMatchType = this.params.get("jobType"); + StringBuffer sb = FileUtil.readFileToString("matchingSetup.json"); + MatchingSetup matchingSetup = (MatchingSetup) FileUtil.strToObj(sb.toString(), MatchingSetup.class); + Matching matcning = matchingSetup.getMatching(sMatchType); + + List retData = matchingInnerDelingMapper.getCustomItemReadData(this.params); + + //레코드에 jobParameters 정보 추가 + for (Map rec : retData) { + rec.put("jobParameters", this.params); + rec.put("matchingType", matcning); + } + + log.debug(">> customRead >> " + FileUtil.objToStr(retData)); + return retData; + } + +} diff --git a/src/main/java/daeucna/config/batch/MatchingItemWriter.java b/src/main/java/daeucna/config/batch/MatchingItemWriter.java new file mode 100644 index 0000000..0d9cd8b --- /dev/null +++ b/src/main/java/daeucna/config/batch/MatchingItemWriter.java @@ -0,0 +1,35 @@ +package daeucna.config.batch; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.batch.core.configuration.annotation.JobScope; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import daeucna.mapper.primary.batch.MatchingInnerDelingMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +@RequiredArgsConstructor +public class MatchingItemWriter { + + @Autowired + MatchingInnerDelingMapper matchingInnerDelingMapper; + + @SuppressWarnings("unchecked") + public void customWrite(T item){ + Map params = (Map) ((Map) item).get("jobParameters"); + + log.debug("customWrite.params : " + params.toString()); + +// matchingInnerDelingMapper.setTest((Map) item); + log.debug("item test = " + item); + } + +} diff --git a/src/main/java/daeucna/config/batch/MatchingSetup.java b/src/main/java/daeucna/config/batch/MatchingSetup.java new file mode 100644 index 0000000..7d5b79d --- /dev/null +++ b/src/main/java/daeucna/config/batch/MatchingSetup.java @@ -0,0 +1,116 @@ +package daeucna.config.batch; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +import lombok.Data; + +@Data +public class MatchingSetup { + + List matchingSetup; + + @Data + public class Matching { + String type; + String typeName; + Cond condOne; + Cond condTwo; + List uniqueKey; + String compareKey; + List compareField; + String amtField; + String matchingType; + String matchingTypeName; + String matchingNumber; + Boolean active; + + public Matching() { + this.uniqueKey = new ArrayList(); + this.condOne = new Cond(); + this.condTwo = new Cond(); + this.compareField = new ArrayList(); + } + + }; + + @Data + public class Cond { + List cond; + List makeCompareKey; + + public Cond() { + this.cond = new ArrayList(); + this.makeCompareKey = new ArrayList(); + } + + public String getMakeCompareKey() { + StringBuffer sbMakeCompareKey = new StringBuffer(); + + for (String curStr : this.makeCompareKey) { + if (sbMakeCompareKey.length() > 0) sbMakeCompareKey.append(" || ':' || "); + sbMakeCompareKey.append(curStr); + } + String sRtnVal = sbMakeCompareKey.toString(); + if (sRtnVal.length() < this.makeCompareKey.size()) sRtnVal = "NULL"; + return sbMakeCompareKey.toString(); + } + } + + public Matching getMatching(String sName) { + Matching matching = null; + + for (Matching curObj : this.matchingSetup) { + if (curObj.getType().equalsIgnoreCase(sName)) { + matching = curObj; + break; + } + } + + return matching; + } + +} + +/* + * 예시 데이타 + */ +/* +{ + "matchingSetup": [ + { + "type": "A1", + "typeName": "A type", + + "condOne": { + "cond": [ + "dta_ty in ('11', '12')" + ], + "makeCompareKey": [ + "cmpnsp_ky" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('21', '22')" + ], + "makeCompareKey": [ + "cmpnsp_ky" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "delng_amt", + "compareField": [ + "accnut_ym", + "compare_ky" + ] + }, + ] +} +*/ \ No newline at end of file diff --git a/src/main/java/daeucna/config/datasource/MultipleDataSourceConfiguration.java b/src/main/java/daeucna/config/datasource/MultipleDataSourceConfiguration.java new file mode 100644 index 0000000..3046eff --- /dev/null +++ b/src/main/java/daeucna/config/datasource/MultipleDataSourceConfiguration.java @@ -0,0 +1,46 @@ +package daeucna.config.datasource; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Qualifier; +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.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; + +@Configuration +public class MultipleDataSourceConfiguration { + + + @Bean + @Primary + @Qualifier("primaryHikariConfig") + @ConfigurationProperties(prefix="spring.datasource.hikari.primary") + public HikariConfig primaryHikariConfig() { + return new HikariConfig(); + } + + @Bean + @Primary + @Qualifier("primaryDataSource") + public DataSource primaryDataSource() throws Exception { + return new HikariDataSource(primaryHikariConfig()); + } + + @Bean + @Qualifier("secondaryHikariConfig") + @ConfigurationProperties(prefix="spring.datasource.hikari.secondary") + public HikariConfig secondaryHikariConfig() { + return new HikariConfig(); + } + + @Bean + @Qualifier("secondaryDataSource") + public DataSource secondaryDataSource() throws Exception { + return new HikariDataSource(secondaryHikariConfig()); + } + +} diff --git a/src/main/java/daeucna/config/datasource/PrimaryMybatisConfiguration.java b/src/main/java/daeucna/config/datasource/PrimaryMybatisConfiguration.java new file mode 100644 index 0000000..5024a51 --- /dev/null +++ b/src/main/java/daeucna/config/datasource/PrimaryMybatisConfiguration.java @@ -0,0 +1,39 @@ +package daeucna.config.datasource; + +import javax.sql.DataSource; + +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.SqlSessionTemplate; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Configuration +@MapperScan(value = "daeucna.mapper.primary", sqlSessionFactoryRef="primarySqlSessionFactory") +public class PrimaryMybatisConfiguration { + + @Primary + @Bean(name = "primarySqlSessionFactory") + public SqlSessionFactory sqlSessionFactory( + @Qualifier("primaryDataSource") DataSource dataSource, ApplicationContext applicationContext) throws Exception { + SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); + sqlSessionFactoryBean.setDataSource(dataSource); + sqlSessionFactoryBean.setConfigLocation(applicationContext.getResource("classpath:mybatis/mybatis-config.xml")); + sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:mybatis/primary/**/*.xml")); + + return sqlSessionFactoryBean.getObject(); + } + + @Primary + @Bean(name = "primarySqlSessionTemplate") + public SqlSessionTemplate sqlSessionTemplate( + @Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) { + return new SqlSessionTemplate(sqlSessionFactory); + } + +} diff --git a/src/main/java/daeucna/config/datasource/SecondaryMyBatisConfiguration.java b/src/main/java/daeucna/config/datasource/SecondaryMyBatisConfiguration.java new file mode 100644 index 0000000..5e803d1 --- /dev/null +++ b/src/main/java/daeucna/config/datasource/SecondaryMyBatisConfiguration.java @@ -0,0 +1,36 @@ +package daeucna.config.datasource; + +import javax.sql.DataSource; + +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.SqlSessionTemplate; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Configuration +@MapperScan(value = "daeucna.mapper.secondary", sqlSessionFactoryRef="secondarySqlSessionFactory") +public class SecondaryMyBatisConfiguration { + + @Bean(name = "secondarySqlSessionFactory") + public SqlSessionFactory sqlSessionFactory( + @Qualifier("secondaryDataSource") DataSource dataSource, ApplicationContext applicationContext) throws Exception { + SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); + sqlSessionFactoryBean.setDataSource(dataSource); + sqlSessionFactoryBean.setConfigLocation(applicationContext.getResource("classpath:mybatis/mybatis-config.xml")); + sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:mybatis/secondary/**/*.xml")); + + return sqlSessionFactoryBean.getObject(); + } + + @Bean(name = "secondarySqlSessionTemplate") + public SqlSessionTemplate sqlSessionTemplate( + @Qualifier("secondarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) { + return new SqlSessionTemplate(sqlSessionFactory); + } + +} diff --git a/src/main/java/daeucna/config/handler/RootController.java b/src/main/java/daeucna/config/handler/RootController.java new file mode 100644 index 0000000..39aa3d4 --- /dev/null +++ b/src/main/java/daeucna/config/handler/RootController.java @@ -0,0 +1,20 @@ +package daeucna.config.handler; + +import org.springframework.boot.web.servlet.error.ErrorController; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class RootController implements ErrorController { + // url 직접 접근할 경우 대체 경로 추가 + private final String ERROR_PATH = "/error"; + + @GetMapping(ERROR_PATH) + public String redirectRoot(){ + return "forward:/index.html"; + } + + public String getErrorPath(){ + return null; + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/p6spy/P6SpyFomatter.java b/src/main/java/daeucna/config/p6spy/P6SpyFomatter.java new file mode 100644 index 0000000..f0b699f --- /dev/null +++ b/src/main/java/daeucna/config/p6spy/P6SpyFomatter.java @@ -0,0 +1,40 @@ +package daeucna.config.p6spy; + +import java.util.Locale; + +import org.hibernate.engine.jdbc.internal.FormatStyle; +import org.springframework.context.annotation.Configuration; + +import com.p6spy.engine.logging.Category; +import com.p6spy.engine.spy.P6SpyOptions; +import com.p6spy.engine.spy.appender.MessageFormattingStrategy; + +import jakarta.annotation.PostConstruct; + +@Configuration +public class P6SpyFomatter implements MessageFormattingStrategy { + + @PostConstruct + public void setLogMessageFormat() { + P6SpyOptions.getActiveInstance().setLogMessageFormat(this.getClass().getName()); + } + + @Override + public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String url) { + sql = formatSql(category, sql); + return String.format("[%s] | %d ms | %s", category, elapsed, formatSql(category, sql)); + } + + private String formatSql(String category, String sql) { + if (sql != null && !sql.trim().isEmpty() && Category.STATEMENT.getName().equals(category)) { + String trimmedSQL = sql.trim().toLowerCase(Locale.ROOT); + if (trimmedSQL.startsWith("create") || trimmedSQL.startsWith("alter") || trimmedSQL.startsWith("comment")) { + sql = FormatStyle.DDL.getFormatter().format(sql); + } else { + sql = FormatStyle.BASIC.getFormatter().format(sql); + } + return sql; + } + return sql; + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/JwtSecurityConfig.java b/src/main/java/daeucna/config/security/JwtSecurityConfig.java new file mode 100644 index 0000000..182bed1 --- /dev/null +++ b/src/main/java/daeucna/config/security/JwtSecurityConfig.java @@ -0,0 +1,25 @@ +package daeucna.config.security; + +import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +import daeucna.config.security.jwt.JwtFilter; +import daeucna.config.security.jwt.JwtTokenProvider; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class JwtSecurityConfig extends SecurityConfigurerAdapter { + private final JwtTokenProvider tokenProvider; + + @Override + public void configure(HttpSecurity http) { + + // security 로직에 JwtFilter 등록 + http.addFilterBefore( + new JwtFilter(tokenProvider), + UsernamePasswordAuthenticationFilter.class + ); + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/SecurityConfig.java b/src/main/java/daeucna/config/security/SecurityConfig.java new file mode 100644 index 0000000..a413d72 --- /dev/null +++ b/src/main/java/daeucna/config/security/SecurityConfig.java @@ -0,0 +1,69 @@ +package daeucna.config.security; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +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.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; + +import daeucna.config.security.jwt.JwtAuthenticationEntryPoint; +import daeucna.config.security.jwt.JwtTokenProvider; +import lombok.RequiredArgsConstructor; + +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +public class SecurityConfig { + + private final JwtTokenProvider tokenProvider; + private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + + // PasswordEncoder는 BCryptPasswordEncoder를 사용 + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { + httpSecurity + // token을 사용하는 방식이기 때문에 csrf를 disable합니다. + .csrf(AbstractHttpConfigurer::disable) + .securityMatcher("/api/**") + .authorizeHttpRequests((authorizeHttpRequests) -> + authorizeHttpRequests + .requestMatchers("/api/admin/**").hasRole("ADMIN") + .requestMatchers("/api/authenticate").permitAll() // 로그인 api + .requestMatchers("/api/refreshtoken").permitAll() // Refresh Token api + .requestMatchers("/api/signup").permitAll() // 회원가입 api + .requestMatchers("/api/exceptionDenied").permitAll() // Exception Denied +// .anyRequest().permitAll() + .anyRequest().authenticated() // 그 외 인증 없이 접근X + ) + .formLogin(Customizer.withDefaults()) + .headers((headers) -> + headers + .frameOptions(frameOptions -> frameOptions + .sameOrigin() + ) + ) + .exceptionHandling(exceptionHandling -> exceptionHandling + .authenticationEntryPoint(jwtAuthenticationEntryPoint) + .accessDeniedPage("/api/exceptionDenied") + ) + // 세션을 사용하지 않기 때문에 STATELESS로 설정 + .sessionManagement((sessionManagement) -> + sessionManagement + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + ) + .apply(new JwtSecurityConfig(tokenProvider)); // JwtFilter를 addFilterBefore로 등록했던 JwtSecurityConfig class 적용 + + return httpSecurity.build(); + } + +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/UserInitializer.java b/src/main/java/daeucna/config/security/UserInitializer.java new file mode 100644 index 0000000..61d4efe --- /dev/null +++ b/src/main/java/daeucna/config/security/UserInitializer.java @@ -0,0 +1,44 @@ +package daeucna.config.security; +import java.util.Arrays; +import java.util.HashSet; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import daeucna.config.security.dto.AuthorityDto; +import daeucna.config.security.dto.UserDto; +import daeucna.config.security.service.UserService; + +@Component +public class UserInitializer implements ApplicationRunner { + + private final UserService userService; + private final Environment env; + + @Autowired + public UserInitializer(Environment env, UserService userService) { + this.userService = userService; + this.env = env; + } + + @Override + public void run(ApplicationArguments args) { + //초기 Admin User 넣어주기 + AuthorityDto authorityDto = AuthorityDto.builder().authorityName("ROLE_ADMIN").build(); + UserDto userDto = UserDto.builder() + .username("sangkiham") + .password("sangkiham") + .nickname("sangkiham") + .authorityDtoSet(new HashSet( Arrays.asList(authorityDto) )) + .build(); + + //사용자 정보가 없으면 Insert한다. + boolean blnAdminInit = Boolean.parseBoolean(env.getProperty("admin.init")); + if (blnAdminInit && userService.getUserWithAuthorities(userDto.getUsername()) == null) { + userService.signup(userDto); + } + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/controller/AuthController.java b/src/main/java/daeucna/config/security/controller/AuthController.java new file mode 100644 index 0000000..55e1e52 --- /dev/null +++ b/src/main/java/daeucna/config/security/controller/AuthController.java @@ -0,0 +1,98 @@ +package daeucna.config.security.controller; + +import java.util.HashMap; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import daeucna.config.security.dto.LoginDto; +import daeucna.config.security.dto.TokenDto; +import daeucna.config.security.jwt.JwtFilter; +import daeucna.config.security.jwt.JwtTokenProvider; +import daeucna.config.security.utils.CommonJson; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@RestController +@RequestMapping("/api") +@RequiredArgsConstructor +@Slf4j +public class AuthController { + private final JwtTokenProvider tokenProvider; + private final AuthenticationManagerBuilder authenticationManagerBuilder; + + @PostMapping("/authenticate") + public ResponseEntity authorize( + @Valid @RequestBody LoginDto loginDto, + @Value("${jwt.token-validity-in-seconds}") long tokenValidityInSeconds, + @Value("${jwt.refresh-token-validity-in-seconds}") long refreshTokenValidityInSeconds + ) { + + return fnAuthorize(loginDto, tokenValidityInSeconds, refreshTokenValidityInSeconds, false); + } + + public ResponseEntity fnAuthorize(LoginDto loginDto, long tokenValidityInSeconds, long refreshTokenValidityInSeconds, boolean blnRefresh) { + + UsernamePasswordAuthenticationToken authenticationToken = + new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword()); + + // authenticate 메소드가 실행이 될 때 CustomUserDetailsService class의 loadUserByUsername 메소드가 실행 + Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); + // 해당 객체를 SecurityContextHolder에 저장하고 + SecurityContextHolder.getContext().setAuthentication(authentication); + // authentication 객체를 createToken 메소드를 통해서 JWT Token을 생성 + String jwt = tokenProvider.createToken(authentication, tokenValidityInSeconds, loginDto); + String jwtRefresh = tokenProvider.createToken(authentication, refreshTokenValidityInSeconds, loginDto); + //요청이 RefreshToken 아닐 경우만 생성 + if (blnRefresh) jwtRefresh = null; + + HttpHeaders httpHeaders = new HttpHeaders(); + // response header에 jwt token에 넣어줌 + httpHeaders.add(JwtFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); + + // tokenDto를 이용해 response body에도 넣어서 리턴 + log.debug("jwt = " + jwt); + log.debug("jwtRefresh = " + jwtRefresh); + return new ResponseEntity<>(new TokenDto(jwt, jwtRefresh), httpHeaders, HttpStatus.OK); + } + @PostMapping("/refreshtoken") + public ResponseEntity refreshToken( + @RequestHeader HttpHeaders header, + @Value("${jwt.token-validity-in-seconds}") long tokenValidityInSeconds, + @Value("${jwt.refresh-token-validity-in-seconds}") long refreshTokenValidityInSeconds + ) { + + String sRefreshToken = header.getFirst(JwtFilter.AUTHORIZATION_REFRESH_HEADER); + LoginDto loginDto = null; + if (tokenProvider.validateToken(sRefreshToken)) { + Jws claims = tokenProvider.getClaims(sRefreshToken); + + log.debug("parseJwt = " + CommonJson.objectToString(claims)); + log.debug("parseJwt(getSubject) = " + claims.getBody().getSubject()); + log.debug("parseJwt(auth) = " + (String) claims.getBody().get("auth")); + + HashMap hmLoginDto = claims.getBody().get("loginDto", HashMap.class); + loginDto = LoginDto.builder() + .username(hmLoginDto.get("username")) + .password(hmLoginDto.get("password")) + .build(); + log.debug("parseJwt(LoginDto) = " + CommonJson.objectToString(loginDto)); + } + + return fnAuthorize(loginDto, tokenValidityInSeconds, refreshTokenValidityInSeconds, true); + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/controller/ExceptionController.java b/src/main/java/daeucna/config/security/controller/ExceptionController.java new file mode 100644 index 0000000..dfbbc92 --- /dev/null +++ b/src/main/java/daeucna/config/security/controller/ExceptionController.java @@ -0,0 +1,22 @@ +package daeucna.config.security.controller; + +import org.springframework.security.access.AccessDeniedException; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.v3.oas.annotations.Operation; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RestController +@RequestMapping("/api") +public class ExceptionController { + + @Operation(summary = "인가 거부", description = "인가에 따른 예외가 발생했습니다.") + @RequestMapping(value = "/exceptionDenied", method = {RequestMethod.GET, RequestMethod.POST}) + public void AccessDeniedException() { + throw new AccessDeniedException(""); + } + +} diff --git a/src/main/java/daeucna/config/security/controller/UserController.java b/src/main/java/daeucna/config/security/controller/UserController.java new file mode 100644 index 0000000..96e8902 --- /dev/null +++ b/src/main/java/daeucna/config/security/controller/UserController.java @@ -0,0 +1,55 @@ +package daeucna.config.security.controller; + +import java.io.IOException; + +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +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 daeucna.config.security.dto.UserDto; +import daeucna.config.security.service.UserService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api") +public class UserController { + private final UserService userService; + + @GetMapping("/hello") + public ResponseEntity hello() { + return ResponseEntity.ok("hello"); + } + + @PostMapping("/test-redirect") + public void testRedirect(HttpServletResponse response) throws IOException { + response.sendRedirect("/api/user"); + } + + @PostMapping("/signup") + public ResponseEntity signup( + @Valid @RequestBody UserDto userDto + ) { + return ResponseEntity.ok(userService.signup(userDto)); + } + + @GetMapping("/user") + @PreAuthorize("hasAnyRole('USER','ADMIN')") + public ResponseEntity getMyUserInfo(HttpServletRequest request) { + return ResponseEntity.ok(userService.getMyUserWithAuthorities()); + } + + @GetMapping("/user/{username}") + @PreAuthorize("hasAnyRole('ADMIN')") + public ResponseEntity getUserInfo(@PathVariable String username) { + return ResponseEntity.ok(userService.getUserWithAuthorities(username)); + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/dto/AuthorityDto.java b/src/main/java/daeucna/config/security/dto/AuthorityDto.java new file mode 100644 index 0000000..041a33f --- /dev/null +++ b/src/main/java/daeucna/config/security/dto/AuthorityDto.java @@ -0,0 +1,28 @@ +package daeucna.config.security.dto; + +import daeucna.config.security.entity.Authority; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter @Setter @Builder +@AllArgsConstructor +@NoArgsConstructor +public class AuthorityDto { + + @NotNull + @Size(min = 3, max = 50) + private String authorityName; + + public static AuthorityDto from(Authority authority) { + if(authority == null) return null; + + return AuthorityDto.builder() + .authorityName(authority.getAuthorityName()) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/dto/LoginDto.java b/src/main/java/daeucna/config/security/dto/LoginDto.java new file mode 100644 index 0000000..6fbe89b --- /dev/null +++ b/src/main/java/daeucna/config/security/dto/LoginDto.java @@ -0,0 +1,25 @@ +package daeucna.config.security.dto; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class LoginDto { + + @NotNull + @Size(min = 3, max = 50) + private String username; + + @NotNull + @Size(min = 3, max = 100) + private String password; +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/dto/TokenDto.java b/src/main/java/daeucna/config/security/dto/TokenDto.java new file mode 100644 index 0000000..0a18039 --- /dev/null +++ b/src/main/java/daeucna/config/security/dto/TokenDto.java @@ -0,0 +1,19 @@ +package daeucna.config.security.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TokenDto { + + private String token; + private String refreshToken; + +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/dto/UserDto.java b/src/main/java/daeucna/config/security/dto/UserDto.java new file mode 100644 index 0000000..a528244 --- /dev/null +++ b/src/main/java/daeucna/config/security/dto/UserDto.java @@ -0,0 +1,49 @@ +package daeucna.config.security.dto; + +import java.util.Set; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import daeucna.config.security.entity.User; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter @Setter @Builder +@AllArgsConstructor +@NoArgsConstructor +public class UserDto { + + @NotNull + @Size(min = 3, max = 50) + private String username; + +// @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + @NotNull + @Size(min = 3, max = 100) + private String password; + + @NotNull + @Size(min = 3, max = 50) + private String nickname; + + private Set authorityDtoSet; + + public static UserDto from(User user) { + if(user == null) return null; + + return UserDto.builder() + .username(user.getUsername()) + .password(user.getPassword()) + .nickname(user.getNickname()) + .authorityDtoSet(user.getAuthorities().stream() + .map(authority -> AuthorityDto.builder().authorityName(authority.getAuthorityName()).build()) + .collect(Collectors.toSet())) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/entity/Authority.java b/src/main/java/daeucna/config/security/entity/Authority.java new file mode 100644 index 0000000..fbca813 --- /dev/null +++ b/src/main/java/daeucna/config/security/entity/Authority.java @@ -0,0 +1,25 @@ +package daeucna.config.security.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Table(name = "authority") +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class Authority { + + @Id + @Column(name = "authority_name", length = 50) + private String authorityName; +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/entity/User.java b/src/main/java/daeucna/config/security/entity/User.java new file mode 100644 index 0000000..928102b --- /dev/null +++ b/src/main/java/daeucna/config/security/entity/User.java @@ -0,0 +1,58 @@ +package daeucna.config.security.entity; + +import java.util.Set; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity // DB의 테이블과 1:1 매핑되는 객체 +@Table(name = "users") +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class User { + + @JsonIgnore + @Id // primary key + @Column(name = "user_id") + // 자동 증가 되는 + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long userId; + + @Column(name = "username", length = 50, unique = true) + private String username; + + @JsonIgnore + @Column(name = "password", length = 100) + private String password; + + @Column(name = "nickname", length = 50) + private String nickname; + + @JsonIgnore + @Column(name = "activated") + private boolean activated; + + @ManyToMany + @JoinTable( + name = "user_authority", + joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "user_id")}, + inverseJoinColumns = {@JoinColumn(name = "authority_name", referencedColumnName = "authority_name")}) + private Set authorities; +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/jwt/JwtAuthenticationEntryPoint.java b/src/main/java/daeucna/config/security/jwt/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..e6fd1c7 --- /dev/null +++ b/src/main/java/daeucna/config/security/jwt/JwtAuthenticationEntryPoint.java @@ -0,0 +1,23 @@ +package daeucna.config.security.jwt; + +import java.io.IOException; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + @Override + public void commence(HttpServletRequest request, + HttpServletResponse response, + AuthenticationException authException) throws IOException { + // 유효한 자격증명을 제공하지 않고 접근하려 할때 401 + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/jwt/JwtFilter.java b/src/main/java/daeucna/config/security/jwt/JwtFilter.java new file mode 100644 index 0000000..1425e89 --- /dev/null +++ b/src/main/java/daeucna/config/security/jwt/JwtFilter.java @@ -0,0 +1,55 @@ +package daeucna.config.security.jwt; + +import java.io.IOException; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.GenericFilterBean; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@RequiredArgsConstructor +@Slf4j +public class JwtFilter extends GenericFilterBean { + + public static final String AUTHORIZATION_HEADER = "Authorization"; + public static final String AUTHORIZATION_REFRESH_HEADER = "REFRESH_TOKEN"; + private final JwtTokenProvider tokenProvider; + + // 실제 필터릴 로직 + // 토큰의 인증정보를 SecurityContext에 저장하는 역할 수행 + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; + String jwt = resolveToken(httpServletRequest); + String requestURI = httpServletRequest.getRequestURI(); + + if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) { + Authentication authentication = tokenProvider.getAuthentication(jwt); + SecurityContextHolder.getContext().setAuthentication(authentication); + log.debug("Security Context에 '{}' 인증 정보를 저장했습니다, uri: {}", authentication.getName(), requestURI); + } else { + log.debug("유효한 JWT 토큰이 없습니다, uri: {}", requestURI); + } + + filterChain.doFilter(servletRequest, servletResponse); + } + + // Request Header 에서 토큰 정보를 꺼내오기 위한 메소드 + private String resolveToken(HttpServletRequest request) { + String bearerToken = request.getHeader(AUTHORIZATION_HEADER); + + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); + } + + return null; + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/jwt/JwtTokenProvider.java b/src/main/java/daeucna/config/security/jwt/JwtTokenProvider.java new file mode 100644 index 0000000..d788f18 --- /dev/null +++ b/src/main/java/daeucna/config/security/jwt/JwtTokenProvider.java @@ -0,0 +1,129 @@ +package daeucna.config.security.jwt; + +import java.security.Key; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.crypto.SecretKey; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Component; + +import daeucna.config.security.dto.LoginDto; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.UnsupportedJwtException; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class JwtTokenProvider implements InitializingBean { + + private static final String AUTHORITIES_KEY = "auth"; + private final String secret; + private final long tokenValidityInMilliseconds; + private final long freshTokenValidityInMilliseconds; + private SecretKey key; + + public JwtTokenProvider( + @Value("${jwt.secret}") String secret, + @Value("${jwt.token-validity-in-seconds}") long tokenValidityInSeconds, + @Value("${jwt.refresh-token-validity-in-seconds}") long refreshTokenValidityInSeconds) { + this.secret = secret; + this.tokenValidityInMilliseconds = tokenValidityInSeconds * 1000; + this.freshTokenValidityInMilliseconds = refreshTokenValidityInSeconds * 1000; + } + + // 빈이 생성되고 주입을 받은 후에 secret값을 Base64 Decode해서 key 변수에 할당하기 위해 + @Override + public void afterPropertiesSet() { + byte[] keyBytes = Decoders.BASE64URL.decode(secret); + this.key = Keys.hmacShaKeyFor(keyBytes); + } + + public SecretKey getSecretKey() { + return this.key; + } + + public String createToken(Authentication authentication, long tokenValidityInMilliseconds, LoginDto loginDto) { + String authorities = authentication.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.joining(",")); + + // 토큰의 expire 시간을 설정 + long now = (new Date()).getTime(); + Date validity = new Date(now + (tokenValidityInMilliseconds * 1000) ); //1000분의 1초 + + return Jwts.builder() + .subject(authentication.getName()) + .claim(AUTHORITIES_KEY, authorities) // 정보 저장 + .claims() + .add(Map.of("loginDto", loginDto)) + .and() + .signWith(key, Jwts.SIG.HS512) // 사용할 암호화 알고리즘과 , signature 에 들어갈 secret값 세팅 + .expiration(validity) // set Expire Time 해당 옵션 안넣으면 expire안함 + .compact(); + } + + // 토큰으로 클레임을 만들고 이를 이용해 유저 객체를 만들어서 최종적으로 authentication 객체를 리턴 + public Authentication getAuthentication(String token) { + Claims claims = Jwts + .parser() + .verifyWith(key) + .build() + .parseSignedClaims(token) + .getPayload(); + + Collection authorities = + Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(",")) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + + User principal = new User(claims.getSubject(), "", authorities); + + return new UsernamePasswordAuthenticationToken(principal, token, authorities); + } + + public Jws getClaims(String sToken) { + return Jwts.parser() + .verifyWith(this.getSecretKey()) + .build() + .parseSignedClaims(sToken); + } + + // 토큰의 유효성 검증을 수행 + public boolean validateToken(String token) { + try { + Jwts.parser().verifyWith(key).build().parseSignedClaims(token); + return true; + } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) { + + log.info("잘못된 JWT 서명입니다."); + } catch (ExpiredJwtException e) { + + log.info("만료된 JWT 토큰입니다."); + } catch (UnsupportedJwtException e) { + + log.info("지원되지 않는 JWT 토큰입니다."); + } catch (IllegalArgumentException e) { + + log.info("JWT 토큰이 잘못되었습니다."); + } + return false; + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/repository/UserRepository.java b/src/main/java/daeucna/config/security/repository/UserRepository.java new file mode 100644 index 0000000..d8be945 --- /dev/null +++ b/src/main/java/daeucna/config/security/repository/UserRepository.java @@ -0,0 +1,13 @@ +package daeucna.config.security.repository; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; + +import daeucna.config.security.entity.User; + +public interface UserRepository extends JpaRepository { + @EntityGraph(attributePaths = "authorities") + Optional findOneWithAuthoritiesByUsername(String username); +} diff --git a/src/main/java/daeucna/config/security/service/CustomUserDetailsService.java b/src/main/java/daeucna/config/security/service/CustomUserDetailsService.java new file mode 100644 index 0000000..44da223 --- /dev/null +++ b/src/main/java/daeucna/config/security/service/CustomUserDetailsService.java @@ -0,0 +1,46 @@ +package daeucna.config.security.service; + +import java.util.List; +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 org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import daeucna.config.security.entity.User; +import daeucna.config.security.repository.UserRepository; +import lombok.RequiredArgsConstructor; + +@Component("userDetailsService") +@RequiredArgsConstructor +public class CustomUserDetailsService implements UserDetailsService { + private final UserRepository userRepository; + + @Override + @Transactional + // 로그인시에 DB에서 유저정보와 권한정보를 가져와서 해당 정보를 기반으로 userdetails.User 객체를 생성해 리턴 + public UserDetails loadUserByUsername(final String username) { + + return userRepository.findOneWithAuthoritiesByUsername(username) + .map(user -> createUser(username, user)) + .orElseThrow(() -> new UsernameNotFoundException(username + " -> 데이터베이스에서 찾을 수 없습니다.")); + } + + private org.springframework.security.core.userdetails.User createUser(String username, User user) { + if (!user.isActivated()) { + throw new RuntimeException(username + " -> 활성화되어 있지 않습니다."); + } + + List grantedAuthorities = user.getAuthorities().stream() + .map(authority -> new SimpleGrantedAuthority(authority.getAuthorityName())) + .collect(Collectors.toList()); + + return new org.springframework.security.core.userdetails.User(user.getUsername(), + user.getPassword(), + grantedAuthorities); + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/service/UserService.java b/src/main/java/daeucna/config/security/service/UserService.java new file mode 100644 index 0000000..f9587fd --- /dev/null +++ b/src/main/java/daeucna/config/security/service/UserService.java @@ -0,0 +1,71 @@ +package daeucna.config.security.service; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import daeucna.config.security.dto.AuthorityDto; +import daeucna.config.security.dto.UserDto; +import daeucna.config.security.entity.Authority; +import daeucna.config.security.entity.User; +import daeucna.config.security.repository.UserRepository; +import daeucna.config.security.utils.CommonJson; +import daeucna.config.security.utils.DuplicateMemberException; +import daeucna.config.security.utils.SecurityUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Service +@RequiredArgsConstructor +@Slf4j +public class UserService { + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + + @Transactional + public UserDto signup(UserDto userDto) { + if (userRepository.findOneWithAuthoritiesByUsername(userDto.getUsername()).orElse(null) != null) { + throw new DuplicateMemberException("이미 가입되어 있는 유저입니다."); + } + + Set setAuthority = new HashSet(); + Set setAuthorityDto = userDto.getAuthorityDtoSet(); + Iterator itAuthorityDto = setAuthorityDto.iterator(); + while(itAuthorityDto.hasNext()) { + AuthorityDto curAuthorityDto = itAuthorityDto.next(); + setAuthority.add( + Authority.builder() + .authorityName(curAuthorityDto.getAuthorityName()) + .build() + ); + + log.debug("setAuthority = " + CommonJson.objectToString(setAuthority)); + } + + + + User user = User.builder() + .username(userDto.getUsername()) + .password(passwordEncoder.encode(userDto.getPassword())) + .nickname(userDto.getNickname()) + .authorities(setAuthority) + .activated(true) + .build(); + + return UserDto.from(userRepository.save(user)); + } + + @Transactional(readOnly = true) + public UserDto getUserWithAuthorities(String username) { + return UserDto.from(userRepository.findOneWithAuthoritiesByUsername(username).orElse(null)); + } + + @Transactional(readOnly = true) + public UserDto getMyUserWithAuthorities() { + return UserDto.from(SecurityUtil.getCurrentUsername().flatMap(userRepository::findOneWithAuthoritiesByUsername).orElse(null)); + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/utils/CommonJson.java b/src/main/java/daeucna/config/security/utils/CommonJson.java new file mode 100644 index 0000000..3056ea7 --- /dev/null +++ b/src/main/java/daeucna/config/security/utils/CommonJson.java @@ -0,0 +1,34 @@ +package daeucna.config.security.utils; + +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.ObjectMapper; + +@Component +public class CommonJson { + + public static String objectToString(Object object) { + String rtnVal = ""; + try { + ObjectMapper objectMapper = new ObjectMapper(); + rtnVal = objectMapper.writeValueAsString(object); + } catch (Exception e) { + e.printStackTrace(); + rtnVal = "Error"; + } + return rtnVal; + } + + public static Object stringToObject(String sJson, Class objClass) { + Object rtnVal; + try { + ObjectMapper objectMapper = new ObjectMapper(); + rtnVal = objectMapper.readValue(sJson, objClass); + } catch (Exception e) { + e.printStackTrace(); + rtnVal = "Error"; + } + return rtnVal; + } + +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/utils/DuplicateMemberException.java b/src/main/java/daeucna/config/security/utils/DuplicateMemberException.java new file mode 100644 index 0000000..c4df20e --- /dev/null +++ b/src/main/java/daeucna/config/security/utils/DuplicateMemberException.java @@ -0,0 +1,16 @@ +package daeucna.config.security.utils; + +public class DuplicateMemberException extends RuntimeException { + public DuplicateMemberException() { + super(); + } + public DuplicateMemberException(String message, Throwable cause) { + super(message, cause); + } + public DuplicateMemberException(String message) { + super(message); + } + public DuplicateMemberException(Throwable cause) { + super(cause); + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/utils/NotFoundMemberException.java b/src/main/java/daeucna/config/security/utils/NotFoundMemberException.java new file mode 100644 index 0000000..10d40b6 --- /dev/null +++ b/src/main/java/daeucna/config/security/utils/NotFoundMemberException.java @@ -0,0 +1,16 @@ +package daeucna.config.security.utils; + +public class NotFoundMemberException extends RuntimeException { + public NotFoundMemberException() { + super(); + } + public NotFoundMemberException(String message, Throwable cause) { + super(message, cause); + } + public NotFoundMemberException(String message) { + super(message); + } + public NotFoundMemberException(Throwable cause) { + super(cause); + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/config/security/utils/SecurityUtil.java b/src/main/java/daeucna/config/security/utils/SecurityUtil.java new file mode 100644 index 0000000..10fba71 --- /dev/null +++ b/src/main/java/daeucna/config/security/utils/SecurityUtil.java @@ -0,0 +1,37 @@ +package daeucna.config.security.utils; + +import java.util.Optional; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SecurityUtil { + + private SecurityUtil() {} + + // getCurrentUsername 메소드의 역할은 Security Cont + public static Optional getCurrentUsername() { + + // authentication객체가 저장되는 시점은 JwtFilter의 doFilter 메소드에서 + // Request가 들어올 때 SecurityContext에 Authentication 객체를 저장해서 사용 + final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (authentication == null) { + log.debug("Security Context에 인증 정보가 없습니다."); + return Optional.empty(); + } + + String username = null; + if (authentication.getPrincipal() instanceof UserDetails springSecurityUser) { + username = springSecurityUser.getUsername(); + } else if (authentication.getPrincipal() instanceof String) { + username = (String) authentication.getPrincipal(); + } + + return Optional.ofNullable(username); + } +} \ No newline at end of file diff --git a/src/main/java/daeucna/mapper/primary/batch/MatchingInnerDelingMapper.java b/src/main/java/daeucna/mapper/primary/batch/MatchingInnerDelingMapper.java new file mode 100644 index 0000000..784ce3c --- /dev/null +++ b/src/main/java/daeucna/mapper/primary/batch/MatchingInnerDelingMapper.java @@ -0,0 +1,158 @@ +package daeucna.mapper.primary.batch; + +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface MatchingInnerDelingMapper { + + /* + * 작업리스트 + */ + @SuppressWarnings("rawtypes") + List getCustomItemReadData(Map param); + + + /** + * 작업키 업데이트 (파라미터 : 자기데이타/상대데이타) + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + int setDataMakeCompareKy(Map param); + + + /** + * 매칭작업할 데이타 가져오기(파라미터 : 자기데이타/상대데이타) + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + List getMatchingData(Map param); + + /** + * 업데이트할 데이타 가져오기(파라미터 : 자기데이타/상대데이타) + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + List getMatchingResult(Map param); + + /** + * 결과 업데이트 + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + int setResult(Map param); + + + + + /** + * Original Data 삭제 + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + int deleteOriginalData(Map param); + + + /** + * Original Data 생성 + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + int insertOriginalData(Map param); + + + /** + * 작업영역 데이타 삭제 + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + int deleteData(Map param); + + /** + * 작업영역 데이타 생성(From Original Data) + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + int insertDataFromOriginal(Map param); + + /** + * 작업영역 ai데이타 삭제 + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + int deleteDataAi(Map param); + + /** + * 작업영역 데이타 생성(From Original Data) + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + int insertDataAiFromOriginal(Map param); + + /** + * 값을 돌려주기전 월별 새로운 일치키 생성 + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + int updateNewMatchKey(Map param); + + /** + * Extra matching을 위한 자료 조회 + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + List getMatchingExtraDataOne(Map param); + + /** + * Extra matching을 위한 자료 조회 + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + List getMatchingExtraDataTwo(Map param); + + /** + * Extra matching 데이타 적용 + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + int setExtraResult(Map param); + + /** + * User Job Start + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + int createUserJob(Map param); + + /** + * User Job End + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + int finishUserJob(Map param); + + /* + * ai 작업리스트 + */ + @SuppressWarnings("rawtypes") + List getAiReadData(Map param); + +} \ No newline at end of file diff --git a/src/main/java/daeucna/mapper/primary/system/CodeMapper.java b/src/main/java/daeucna/mapper/primary/system/CodeMapper.java new file mode 100644 index 0000000..5d7ab46 --- /dev/null +++ b/src/main/java/daeucna/mapper/primary/system/CodeMapper.java @@ -0,0 +1,12 @@ +package daeucna.mapper.primary.system; + +import java.util.List; + +import org.apache.ibatis.annotations.Mapper; + +import daeucna.system.code.CodeDto; + +@Mapper +public interface CodeMapper { + List getCmmnCode(CodeDto param); +} \ No newline at end of file diff --git a/src/main/java/daeucna/mapper/secondary/batch/OracleMapper.java b/src/main/java/daeucna/mapper/secondary/batch/OracleMapper.java new file mode 100644 index 0000000..5f292d5 --- /dev/null +++ b/src/main/java/daeucna/mapper/secondary/batch/OracleMapper.java @@ -0,0 +1,32 @@ +package daeucna.mapper.secondary.batch; + +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface OracleMapper { + + /* + * Original Data 조회 + */ + @SuppressWarnings("rawtypes") + List getOriginalData(Map param); + + /* + * Original Data 조회 + */ + @SuppressWarnings("rawtypes") + List getMatchingInfo(Map param); + + /** + * 원 테이블에 결과값 업데이트 + * @param param + * @return + */ + @SuppressWarnings("rawtypes") + int updateMatchingResult(Map param); + + +} \ No newline at end of file diff --git a/src/main/java/daeucna/system/code/CodeController.java b/src/main/java/daeucna/system/code/CodeController.java new file mode 100644 index 0000000..9d5f26e --- /dev/null +++ b/src/main/java/daeucna/system/code/CodeController.java @@ -0,0 +1,33 @@ +package daeucna.system.code; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +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 daeucna.system.code.CodeDto; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/code") +public class CodeController { + @Autowired + private final CodeService codeService; + + @PostMapping("/cmmncode") + public ResponseEntity> getCmmnCode(@RequestBody CodeDto param) { + List rtnVal = new ArrayList(); + + rtnVal = codeService.getCmmnCode(param); + + return ResponseEntity.ok(rtnVal); + } + +} \ No newline at end of file diff --git a/src/main/java/daeucna/system/code/CodeDto.java b/src/main/java/daeucna/system/code/CodeDto.java new file mode 100644 index 0000000..0ce98af --- /dev/null +++ b/src/main/java/daeucna/system/code/CodeDto.java @@ -0,0 +1,28 @@ +package daeucna.system.code; + +import java.math.BigDecimal; + +import lombok.Data; + +@Data +public class CodeDto { + + private String codeTy; + private String cmmnCode; + + private String mngIem1; + private String mngIem2; + private String mngIem3; + private String mngIem4; + private BigDecimal ordr; + private String useAt; + + private String lcal; + private String cmmnCodeNm; + + private String register; + private String inputDe; + private String updusr; + private String updtDe; + +} \ No newline at end of file diff --git a/src/main/java/daeucna/system/code/CodeService.java b/src/main/java/daeucna/system/code/CodeService.java new file mode 100644 index 0000000..9c388f5 --- /dev/null +++ b/src/main/java/daeucna/system/code/CodeService.java @@ -0,0 +1,10 @@ +package daeucna.system.code; + +import java.util.List; + +public interface CodeService { + + @SuppressWarnings("rawtypes") + public List getCmmnCode(CodeDto param); + +} \ No newline at end of file diff --git a/src/main/java/daeucna/system/code/CodeServiceImpl.java b/src/main/java/daeucna/system/code/CodeServiceImpl.java new file mode 100644 index 0000000..df615cf --- /dev/null +++ b/src/main/java/daeucna/system/code/CodeServiceImpl.java @@ -0,0 +1,36 @@ +package daeucna.system.code; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import daeucna.mapper.primary.system.CodeMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Service +@RequiredArgsConstructor +@Slf4j +@Repository +@Transactional(propagation = Propagation.REQUIRED, rollbackFor={Exception.class}) +public class CodeServiceImpl implements CodeService { + @Autowired + private CodeMapper codeMapper; + + + @Override + public List getCmmnCode(CodeDto param) { + List lCodeDto = new ArrayList(); + + lCodeDto = codeMapper.getCmmnCode(param); + + log.info("CodeServiceImpl"); + return lCodeDto; + } + +} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..598f3a6 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,62 @@ +server.port=8080 + +spring.mvc.converters.preferred-json-mapper=gson + +spring.mvc.view.prefix=/ +spring.mvc.view.suffix: .html +spring.mvc.hiddenmethod.filter.enabled=true + +spring.main.allow-bean-definition-overriding=true + +## JPA +spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.generate-ddl=true +spring.jpa.hibernate.ddl-auto=update +spring.jpa.defer-datasource-initialization=true + +## Datasource +# primary +spring.datasource.hikari.primary.driver-class-name=org.postgresql.Driver +spring.datasource.hikari.primary.jdbc-url=jdbc:postgresql://daeuserver.iptime.org:20430/account +spring.datasource.hikari.primary.username=account +spring.datasource.hikari.primary.password=daeucna10! + +# secondary +#spring.datasource.hikari.secondary.driver-class-name=oracle.jdbc.driver.OracleDriver +#spring.datasource.hikari.secondary.jdbc-url=jdbc:oracle:thin:@vanguardlab.kr:63522/CONFINAS19C +#spring.datasource.hikari.secondary.username=ai +#spring.datasource.hikari.secondary.password=ai +spring.datasource.hikari.secondary.driver-class-name=oracle.jdbc.driver.OracleDriver +spring.datasource.hikari.secondary.jdbc-url=jdbc:oracle:thin:@daeuserver2.iptime.org:1521/orcl +spring.datasource.hikari.secondary.username=CONFINAS3 +spring.datasource.hikari.secondary.password=CONFINAS3 + + +spring.sql.encoding=UTF-8 +spring.sql.init.mode=always + +spring.batch.jdbc.initialize-schema=always +#스프링잡 자동시작 옵션 +spring.batch.job.enabled=false + +spring.devtools.livereload.enabled=true +spring.devtools.restart.enabled=true + +#p6spy query logging +decorator.datasource.p6spy.enable-logging=true + +logging.level.root=info +logging.level.daeucna=debug +logging.level.p6spy=debug + +## Python 프로퍼티 설정 +pytyon.path=D:\\Programs\\devp\\python-3.12.2\\python.exe +python.ai.target=D:\\Working\\Python\\Test1.py + +## JWT +jwt.header=Authorization +# HS512 알고리즘을 사용할 것이기 때문에 512bit, 즉 64byte 이상의 secret key를 사용 +# echo 'jsh-springboot-and-jwt-tutorial-this-is-for-generating-jwt-secretkey-base64'|base64 +jwt.secret=4oCYc2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQtc2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXTigJkK +jwt.token-validity-in-seconds=60 +jwt.refresh-token-validity-in-seconds=86400 diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 0000000..3451d94 --- /dev/null +++ b/src/main/resources/data.sql @@ -0,0 +1,45 @@ +MERGE INTO authority m +USING ( + SELECT + 'ROLE_ADMIN' as authority_name + ) s +ON + m.authority_name = s.authority_name +WHEN NOT MATCHED THEN + INSERT (authority_name) VALUES (s.authority_name); + +MERGE INTO authority m +USING ( + SELECT + 'ROLE_USER' as authority_name + ) s +ON + m.authority_name = s.authority_name +WHEN NOT MATCHED THEN + INSERT (authority_name) VALUES (s.authority_name); + +MERGE INTO users m +USING ( + SELECT + 1 as user_id, + true as activated, + 'sangkiham' as nickname, + '$2a$10$nyHQj.Nj2tID4UzIkd1/SuMeYwlKaaHT8Gi3Wgg2x/h9K9qLQciLO' as password, + 'sangkiham' as username + ) s +ON + m.user_id = s.user_id +WHEN NOT MATCHED THEN + INSERT (user_id, activated, nickname, password, username) VALUES (s.user_id, s.activated, s.nickname, s.password, s.username); + +MERGE INTO user_authority m +USING ( + SELECT + 1 as user_id, + 'ROLE_ADMIN' as authority_name + ) s +ON + m.user_id = s.user_id + and m.authority_name = s.authority_name +WHEN NOT MATCHED THEN + INSERT (user_id, authority_name) VALUES (s.user_id, s.authority_name); diff --git a/src/main/resources/matchingSetup.json b/src/main/resources/matchingSetup.json new file mode 100644 index 0000000..40c292c --- /dev/null +++ b/src/main/resources/matchingSetup.json @@ -0,0 +1,3573 @@ +{ + "matchingSetup": [ + { + "active": true, + "type": "A-A", + "typeName": "자기수익(대사키),상대비용(대사키),비교(년월,비교키,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null", + "cmpnsp_ky is not null", + "cmpnsp_ky != ''" + ], + "makeCompareKey": [ + "cmpnsp_ky" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null", + "cmpnsp_ky is not null", + "cmpnsp_ky != ''" + ], + "makeCompareKey": [ + "cmpnsp_ky" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "compare_ky", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "A-B", + "typeName": "자기채권(대사키),상대채무(대사키),비교(년월,비교키,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null", + "cmpnsp_ky is not null", + "cmpnsp_ky != ''" + ], + "makeCompareKey": [ + "cmpnsp_ky" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null", + "cmpnsp_ky is not null", + "cmpnsp_ky != ''" + ], + "makeCompareKey": [ + "cmpnsp_ky" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "compare_ky", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + + { + "active": true, + "type": "B-A", + "typeName": "자기수익(합산키),상대비용(합산키),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null", + "ext_key1 is not null", + "ext_key1 != ''" + ], + "makeCompareKey": [ + "ext_key1" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null", + "ext_key1 is not null", + "ext_key1 != ''" + ], + "makeCompareKey": [ + "ext_key1" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "B-B", + "typeName": "자기채권(합산키),상대채무(합산키),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null", + "ext_key1 is not null", + "ext_key1 != ''" + ], + "makeCompareKey": [ + "ext_key1" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null", + "ext_key1 is not null", + "ext_key1 != ''" + ], + "makeCompareKey": [ + "ext_key1" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + + + + { + "active": true, + "type": "C-A", + "typeName": "자기수익(전표번호),상대비용(전표번호),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null", + "chit_no is not null", + "chit_no != ''" + ], + "makeCompareKey": [ + "chit_no" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null", + "chit_no is not null", + "chit_no != ''" + ], + "makeCompareKey": [ + "chit_no" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "C-B", + "typeName": "자기채권(전표번호),상대채무(전표번호),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null", + "chit_no is not null", + "chit_no != ''" + ], + "makeCompareKey": [ + "chit_no" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null", + "chit_no is not null" + ], + "makeCompareKey": [ + "chit_no" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + + + + { + "active": true, + "type": "D-A", + "typeName": "자기수익(거래일자),상대비용(거래일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "delng_de" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "D-B", + "typeName": "자기채권(거래일자),상대채무(거래일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "delng_de" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + + + { + "active": true, + "type": "E-A", + "typeName": "자기수익(거래월),상대비용(거래월),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "substring(delng_de,1,6)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "substring(delng_de,1,6)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "E-B", + "typeName": "자기채권(거래월),상대채무(거래월),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "substring(delng_de,1,6)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "substring(delng_de,1,6)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + + + + + + { + "active": true, + "type": "F-A", + "typeName": "자기수익(전체),상대비용(전체),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "F-B", + "typeName": "자기채권(전체),상대채무(전체),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + + + { + "active": true, + "type": "G-A", + "typeName": "개별자기수익,상대개별비용,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "G-B", + "typeName": "개별자기채권,상대개별채무,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + + + + + + { + "active": true, + "type": "H-AA", + "typeName": "자기수익(거래일자),개별상대비용,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "H-AB", + "typeName": "자기수익(거래월),개별상대비용,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "H-AC", + "typeName": "자기수익(전표번호),개별상대비용,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null", + "chit_no is not null", + "chit_no != ''" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "chit_no" ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "H-AD", + "typeName": "자기수익(합산키),개별상대비용,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null", + "ext_key1 is not null", + "ext_key1 != ''" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "ext_key1" ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "H-AE", + "typeName": "자기비용(거래일자),개별상대수익,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "H-AF", + "typeName": "자기비용(거래월),개별상대수익,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "H-AG", + "typeName": "자기비용(전표번호),개별상대수익,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null", + "chit_no is not null", + "chit_no != ''" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "chit_no" ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "H-AH", + "typeName": "자기비용(합산키),개별상대수익,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null", + "ext_key1 is not null", + "ext_key1 != ''" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "ext_key1" ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + { + "active": true, + "type": "H-BA", + "typeName": "자기채권(거래일자),개별상대채무,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "H-BB", + "typeName": "자기채권(거래월),개별상대채무,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "H-BC", + "typeName": "자기채권(전표번호),개별상대채무,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null", + "chit_no is not null", + "chit_no != ''" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "chit_no" ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "H-BD", + "typeName": "자기채권(합산키),개별상대채무,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "ext_key1" ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "H-BE", + "typeName": "자기채무(거래일자),개별상대채권,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "H-BF", + "typeName": "자기채무(거래월),개별상대채권,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "H-BG", + "typeName": "자기채무(전표번호),개별상대채권,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null", + "chit_no is not null", + "chit_no != ''" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "chit_no" ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "H-BH", + "typeName": "자기채무(합산키),개별상대채권,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "ext_key1" ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + + { + "active": true, + "type": "I-AA", + "typeName": "자기수익(전체),상대비용(겨래월),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "I-AB", + "typeName": "자기수익(전체),상대비용(겨래일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "I-AC", + "typeName": "자기비용(전체),상대수익(겨래월),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "I-AD", + "typeName": "자기비용(전체),상대수익(겨래일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "I-AE", + "typeName": "자기수익(전체),상대비용(법인계정코드),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cpr_acnt_code" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "I-AF", + "typeName": "자기비용(전체),상대수익(법인계정코드),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cpr_acnt_code" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + { + "active": true, + "type": "I-BA", + "typeName": "자기채권(전체),상대채무(겨래월),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "I-BB", + "typeName": "자기채권(전체),상대채무(겨래일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "I-BC", + "typeName": "자기채무(전체),상대채권(겨래월),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "I-BD", + "typeName": "자기채무(전체),상대채권(겨래일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "I-BE", + "typeName": "자기채권(전체),상대채무(계정코드),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "cpr_acnt_code" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "I-BF", + "typeName": "자기채무(전체),상대채권(계정코드),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "cpr_acnt_code" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + + { + "active": true, + "type": "J-AA", + "typeName": "자기수익(거래월),상대비용(겨래일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "J-AB", + "typeName": "자기비용(거래월),상대수익(겨래일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "J-AC", + "typeName": "자기수익(거래월),상대비용(계정코드),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cpr_acnt_code" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "J-AD", + "typeName": "자기비용(거래월),상대수익(계정코드),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cpr_acnt_code" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + { + "active": true, + "type": "J-BA", + "typeName": "자기채권(거래월),상대채무(겨래일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "J-BB", + "typeName": "자기채무(거래월),상대채권(겨래일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "J-BC", + "typeName": "자기채권(거래월),상대채무(계정코드),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cpr_acnt_code" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "J-BD", + "typeName": "자기채무(거래월),상대채권(계정코드),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cpr_acnt_code" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + + + + + + + + + + + { + "active": true, + "type": "K-AA", + "typeName": "자기수익(적요),상대비용(적요),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(sumry, 1, 80)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(sumry, 1, 80)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "K-AB", + "typeName": "자기비용(적요),상대수익(겨래일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(sumry, 1, 80)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "K-AC", + "typeName": "자기수익(적요),개별상대비용,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(sumry, 1, 80)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "K-AD", + "typeName": "자기비용(적요),개별상대수익,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(sumry, 1, 80)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "K-BA", + "typeName": "자기채권(적요),상대채무(겨래일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(sumry, 1, 80)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "K-BB", + "typeName": "자기채무(적요),상대채권(겨래일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(sumry, 1, 80)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "K-BC", + "typeName": "자기채권(적요),개별상대채무,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(sumry, 1, 80)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "K-BD", + "typeName": "자기채무(적요),개별상대채권,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(sumry, 1, 80)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + + { + "active": true, + "type": "L-A", + "typeName": "자기수익(회계일자),상대비용(회계일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null", + "elcty_de is not null", + "elcty_de != ''" + ], + "makeCompareKey": [ + "elcty_de" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null", + "elcty_de is not null", + "elcty_de != ''" + ], + "makeCompareKey": [ + "elcty_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "L-AA", + "typeName": "자기수익(회계일자),개별상대비용,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null", + "elcty_de is not null", + "elcty_de != ''" + ], + "makeCompareKey": [ + "elcty_de" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "L-AB", + "typeName": "자기비용(회계일자),개별상대수익,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null", + "elcty_de is not null", + "elcty_de != ''" + ], + "makeCompareKey": [ + "elcty_de" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + + + { + "active": true, + "type": "M-A", + "typeName": "자기수익(법인계정코드),상대비용(법인계정코드),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "cpr_acnt_code" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "cpr_acnt_code" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "M-AA", + "typeName": "자기수익(법인계정코드),개별상대비용,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "cpr_acnt_code" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "M-AB", + "typeName": "자기비용(법인계정코드),개별상대수익,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "cpr_acnt_code" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + + { + "active": true, + "type": "N-A", + "typeName": "자기수익(계정코드),상대비용(계정코드),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "cnnc_acnt_code" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "cnnc_acnt_code" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "N-AA", + "typeName": "자기수익(계정코드),개별상대비용,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "cnnc_acnt_code" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "N-AB", + "typeName": "자기비용(계정코드),개별상대수익,비교(년월,비교키,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "cnnc_acnt_code" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "N-AC", + "typeName": "자기수익(계정코드),상대비용(법인계정코드),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "cnnc_acnt_code" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "cpr_acnt_code" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "N-AD", + "typeName": "자기비용(계정코드),상대수익(법인계정코드),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "cnnc_acnt_code" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "cpr_acnt_code" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + + { + "active": true, + "type": "O-A", + "typeName": "자기수익(INVOICE),상대비용(INVOICE),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null", + "ext_key2 is not null", + "ext_key2 != ''" + ], + "makeCompareKey": [ + "ext_key2" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null", + "ext_key2 is not null", + "ext_key2 != ''" + ], + "makeCompareKey": [ + "ext_key2" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "O-AA", + "typeName": "자기수익(INVOICE),개별상대비용,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null", + "ext_key2 is not null", + "ext_key2 != ''" + ], + "makeCompareKey": [ + "ext_key2" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "O-AB", + "typeName": "자기비용(INVOICE),개별상대수익,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null", + "ext_key2 is not null", + "ext_key2 != ''" + ], + "makeCompareKey": [ + "ext_key2" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + { + "active": true, + "type": "P-A", + "typeName": "자기수익(BL),상대비용(BL),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null", + "ext_key3 is not null", + "ext_key3 != ''" + ], + "makeCompareKey": [ + "ext_key3" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null", + "ext_key3 is not null", + "ext_key3 != ''" + ], + "makeCompareKey": [ + "ext_key3" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "P-AA", + "typeName": "자기수익(BL),개별상대비용,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null", + "ext_key3 is not null", + "ext_key3 != ''" + ], + "makeCompareKey": [ + "ext_key3" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "P-AB", + "typeName": "자기비용(BL),개별상대수익,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null", + "ext_key3 is not null", + "ext_key3 != ''" + ], + "makeCompareKey": [ + "ext_key3" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + { + "active": true, + "type": "Q-A", + "typeName": "자기수익(LC),상대비용(LC),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null", + "ext_key4 is not null", + "ext_key4 != ''" + ], + "makeCompareKey": [ + "ext_key4" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null", + "ext_key4 is not null", + "ext_key4 != ''" + ], + "makeCompareKey": [ + "ext_key4" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "Q-AA", + "typeName": "자기수익(LC),개별상대비용,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null", + "ext_key4 is not null", + "ext_key4 != ''" + ], + "makeCompareKey": [ + "ext_key4" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "Q-AB", + "typeName": "자기비용(LC),개별상대수익,비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null", + "ext_key4 is not null", + "ext_key4 != ''" + ], + "makeCompareKey": [ + "ext_key4" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "cast(sn as text)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + + + + + + { + "active": true, + "type": "Z-AA", + "typeName": "[재실행]자기수익(거래일자),상대비용(거래일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "Z-AB", + "typeName": "[재실행]자기수익(거래월),상대비용(거래월),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "Z-AC", + "typeName": "[재실행]자기수익(전체),상대비용(전체),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('11','21')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('12','22')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "Z-BA", + "typeName": "[재실행]자기채권(거래일자),상대채무(거래일자),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "delng_de" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "Z-BB", + "typeName": "[재실행]자기채권(거래월),상대채무(거래월),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym", + "substring(delng_de,1,6)" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + }, + { + "active": true, + "type": "Z-BC", + "typeName": "[재실행]자기채권(전체),상대채무(전체),비교(년월,거래금액)", + + "condOne": { + "cond": [ + "dta_ty in ('31','33','35','37','41')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "condTwo": { + "cond": [ + "dta_ty in ('32','34','36','38','42')", + "mtch_ty is null" + ], + "makeCompareKey": [ + "sys_se", + "accnut_ym" + ] + }, + "uniqueKey": [ + "sys_se", + "accnut_ym", + "sn" + ], + "compareKey": "compare_ky", + "amtField": "sum(delng_amt) as delng_amt", + "compareField": [ + "accnut_ym", + "delng_amt" + ], + "matchingType": "mtch_ty", + "matchingTypeName": "mtch_ty_nm", + "matchingNumber": "mtch_ky" + } + + + ] +} \ No newline at end of file diff --git a/src/main/resources/mybatis/mybatis-config.xml b/src/main/resources/mybatis/mybatis-config.xml new file mode 100644 index 0000000..31f7889 --- /dev/null +++ b/src/main/resources/mybatis/mybatis-config.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mybatis/primary/batch/MatchingInnerDelingMapper.xml b/src/main/resources/mybatis/primary/batch/MatchingInnerDelingMapper.xml new file mode 100644 index 0000000..e0e4b4b --- /dev/null +++ b/src/main/resources/mybatis/primary/batch/MatchingInnerDelingMapper.xml @@ -0,0 +1,542 @@ + + + + + + + + + + UPDATE public.batch_tbcr_inner_delng + SET + ${compareKey} = ${makeCompareKey} + WHERE + sys_se = #{sysSe} + and accnut_ym = #{accnutYm} + and cpr_code = #{cprCode} + and partn_cpr = #{partnCpr} + + and ${item} + + + + + + + + + + + + + UPDATE public.batch_tbcr_inner_delng + SET + mtch_sys = 'AUTO', + ${item.matchingType} = #{item.matchingTypeVal}, + ${item.matchingTypeName} = #{item.matchingTypeNameVal}, + ${item.matchingNumber} = #{item.matchingNumberVal} + WHERE + sys_se = #{item.sys_se} + and accnut_ym = #{item.accnut_ym} + and sn = #{item.sn} + + + + + + + + + + DELETE FROM tbcr_transaction_history + WHERE + cons_group = #{sysSe} + and account_period = #{accnutYm} + + + + + + INSERT INTO tbcr_transaction_history ( + session_id, + cons_group, + ledger, + account_period, + seq, + tran_type, + own_comp, + tran_comp, + comp_acct_code, + comp_prod_code, + recon_key, + tran_date, + tran_currency, + tran_amt, + book_amt, + group_amt, + book_cost, + document_no, + remark, + cons_acct_code, + cons_acct_name, + prod_code, + adjust_type, + adjust_remark, + if_account_period, + if_comp_code, + if_file_id, + if_source, + equal_check, + cons_own_comp, + cons_tran_comp, + invoice_no, + lc_no, + bl_no, + own_biz_no, + partner_biz_no, + acct_date, + matching_cause, + match_key + ) values + + ( + #{item.SESSION_ID}, + #{item.CONS_GROUP}, + #{item.LEDGER}, + #{item.ACCOUNT_PERIOD}, + #{item.SEQ}, + #{item.TRAN_TYPE}, + #{item.OWN_COMP}, + #{item.TRAN_COMP}, + #{item.COMP_ACCT_CODE}, + #{item.COMP_PROD_CODE}, + #{item.RECON_KEY}, + #{item.TRAN_DATE}, + #{item.TRAN_CURRENCY}, + #{item.TRAN_AMT}, + #{item.BOOK_AMT}, + #{item.GROUP_AMT}, + #{item.BOOK_COST}, + #{item.DOCUMENT_NO}, + #{item.REMARK}, + #{item.CONS_ACCT_CODE}, + #{item.CONS_ACCT_NAME}, + #{item.PROD_CODE}, + #{item.ADJUST_TYPE}, + #{item.ADJUST_REMARK}, + #{item.IF_ACCOUNT_PERIOD}, + #{item.IF_COMP_CODE}, + #{item.IF_FILE_ID}, + #{item.IF_SOURCE}, + #{item.EQUAL_CHECK}, + #{item.CONS_OWN_COMP}, + #{item.CONS_TRAN_COMP}, + #{item.INVOICE_NO}, + #{item.LC_NO}, + #{item.BL_NO}, + #{item.OWN_BIZ_NO}, + #{item.PARTNER_BIZ_NO}, + #{item.ACCT_DATE}, + #{item.MATCHING_CAUSE}, + #{item.MATCH_KEY} + ) + + + + + DELETE FROM batch_tbcr_inner_delng + WHERE + sys_se = #{sysSe} + and accnut_ym = #{accnutYm} + + + + INSERT INTO + batch_tbcr_inner_delng + ( + sys_se + , accnut_ym + , sn + , dta_ty + , cpr_code + , partn_cpr + , cpr_acnt_code + , cnnc_acnt_code + , cnnc_acnt_nm + , delng_de + , elcty_de + , chit_no + , cmpnsp_ky + , ext_key1 + , ext_key2 + , ext_key3 + , ext_key4 + , ext_key5 + , delng_crncy + , delng_amt + , acntbk_amt + , group_amt + , suply_amount + , sumry + , org_mtch_ty + , org_mtch_ky + , new_mtch_ty + , new_mtch_ky + , compare_ky + , mtch_ty + , mtch_ty_nm + , mtch_ky + ) + SELECT + cons_group + , account_period + , seq + , tran_type + , own_comp + , tran_comp + , comp_acct_code + , cons_acct_code + , cons_acct_name + , tran_date + , acct_date + , document_no + , recon_key + , null + , invoice_no + , lc_no + , bl_no + , null + , tran_currency + , tran_amt + , book_amt + , group_amt + , book_cost + , remark + , matching_cause + , match_key + , null + , null + , null + , null + , null + , null + FROM + tbcr_transaction_history + WHERE + cons_group = #{sysSe} + and account_period = #{accnutYm} + + + + DELETE FROM batch_tbcr_inner_delng_ai + WHERE + sys_se = #{sysSe} + and accnut_ym = #{accnutYm} + + + + + INSERT INTO + batch_tbcr_inner_delng_ai + ( + sys_se + , accnut_ym + , sn + , ai_key1 + , ai_key2 + , ai_key3 + , ai_key4 + , ai_key5 + , ai_key6 + , ai_key7 + , ai_key8 + , ai_key9 + , ai_key10 + ) + SELECT + cons_group + , account_period + , seq + , regexp_replace(document_no, '[^0-9a-zA-Z]', '',1,0) as ai_key1 + , regexp_replace(recon_key, '[^0-9a-zA-Z]', '',1,0) as ai_key2 + , '' as ai_key3 + , '' as ai_key4 + , '' as ai_key5 + , '' as ai_key6 + , '' as ai_key7 + , '' as ai_key8 + , '' as ai_key9 + , '' as ai_key10 + FROM + tbcr_transaction_history + WHERE + cons_group = #{sysSe} + and account_period = #{accnutYm} + + + + merge into batch_tbcr_inner_delng m + using + ( + select + sys_se, + accnut_ym, + sn, + org_mtch_ty, + org_mtch_ky, + mtch_ty as new_mtch_ty, + mtch_ky, + DENSE_RANK() over (order by mtch_ty, mtch_ky) AS new_mtch_ky + from batch_tbcr_inner_delng + where + sys_se = #{sysSe} + AND accnut_ym = #{accnutYm} + AND mtch_ty is not null + ) t + on + m.sys_se = t.sys_se + and m.accnut_ym = t.accnut_ym + and m.sn = t.sn + when matched then + update set + new_mtch_ty = t.new_mtch_ty, + new_mtch_ky = t.new_mtch_ky + + + + + + + + + + + + + UPDATE public.batch_tbcr_inner_delng + SET + mtch_sys = #{item.mtch_sys}, + mtch_ty = #{item.mtch_ty}, + mtch_ty_nm = #{item.mtch_ty_nm}, + mtch_ky = #{item.mtch_ky} + WHERE + sys_se = #{item.sys_se} + and accnut_ym = #{item.accnut_ym} + and sn = #{item.sn} + + + + + INSERT INTO public.batch_user_job_status ( + user_job_id, + user_job_name, + start_time, + status + ) VALUES ( + #{user_job_id}, + #{user_job_name}, + now(), + 'Started' + ) + + + + UPDATE public.batch_user_job_status + SET + end_time = now(), + status = 'Finished', + exit_code = #{exit_code}, + exit_message = #{exit_message} + WHERE + user_job_id = #{user_job_id} + + + + + \ No newline at end of file diff --git a/src/main/resources/mybatis/primary/system/CodeMapper.xml b/src/main/resources/mybatis/primary/system/CodeMapper.xml new file mode 100644 index 0000000..dcef363 --- /dev/null +++ b/src/main/resources/mybatis/primary/system/CodeMapper.xml @@ -0,0 +1,32 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mybatis/secondary/OracleMapper.HN b/src/main/resources/mybatis/secondary/OracleMapper.HN new file mode 100644 index 0000000..3f0045f --- /dev/null +++ b/src/main/resources/mybatis/secondary/OracleMapper.HN @@ -0,0 +1,77 @@ + + + + + + + + + + + --결과 업데이트 + + + \ No newline at end of file diff --git a/src/main/resources/mybatis/secondary/OracleMapper.LS b/src/main/resources/mybatis/secondary/OracleMapper.LS new file mode 100644 index 0000000..ba6ce9f --- /dev/null +++ b/src/main/resources/mybatis/secondary/OracleMapper.LS @@ -0,0 +1,79 @@ + + + + + + + + + + + --결과 업데이트 + + + \ No newline at end of file diff --git a/src/main/resources/mybatis/secondary/OracleMapper.xml b/src/main/resources/mybatis/secondary/OracleMapper.xml new file mode 100644 index 0000000..ba6ce9f --- /dev/null +++ b/src/main/resources/mybatis/secondary/OracleMapper.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + --결과 업데이트 + + + \ No newline at end of file diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql new file mode 100644 index 0000000..48cecfc --- /dev/null +++ b/src/main/resources/schema.sql @@ -0,0 +1,385 @@ +CREATE TABLE IF NOT EXISTS batch_tbcr_inner_delng +( + sys_se character varying(10) NOT NULL, + accnut_ym character varying(6) NOT NULL, + sn bigint NOT NULL DEFAULT 0, + dta_ty character varying(3), + cpr_code character varying(10), + partn_cpr character varying(10), + cpr_acnt_code character varying(20), + cnnc_acnt_code character varying(20), + cnnc_acnt_nm character varying(100), + delng_de character varying(8), + elcty_de character varying(8), + chit_no character varying(100), + cmpnsp_ky character varying(100), + ext_key1 character varying(100), + ext_key2 character varying(100), + ext_key3 character varying(100), + ext_key4 character varying(100), + ext_key5 character varying(100), + delng_crncy character varying(3), + delng_amt numeric(19,2) DEFAULT 0, + acntbk_amt numeric(19,2) DEFAULT 0, + group_amt numeric(19,2) DEFAULT 0, + suply_amount numeric(19,2) DEFAULT 0, + sumry character varying(500), + org_mtch_ty character varying(10), + org_mtch_ky numeric(10,0), + new_mtch_ty character varying(10), + new_mtch_ky numeric(10,0), + compare_ky character varying(100), + mtch_sys character varying(10), + mtch_ty character varying(10), + mtch_ty_nm character varying(100), + mtch_ky bigint DEFAULT 0, + CONSTRAINT batch_tbcr_inner_delng_pkey PRIMARY KEY (sys_se, accnut_ym, sn) +); + +COMMENT ON TABLE batch_tbcr_inner_delng + IS '내부거래대사자료'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.sys_se + IS '시스템구분'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.accnut_ym + IS '회계연월'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.sn + IS '순번'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.dta_ty + IS '거래유형'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.cpr_code + IS '자기법인'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.partn_cpr + IS '상대법인'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.cpr_acnt_code + IS '법인계정코드'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.cnnc_acnt_code + IS '연결계정코드'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.cnnc_acnt_nm + IS '연결계정명'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.delng_de + IS '거래일자'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.elcty_de + IS '전기일자'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.chit_no + IS '법인전표번호'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.cmpnsp_ky + IS '대사 Key'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.ext_key1 + IS '합산Key'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.ext_key2 + IS 'INVOICE번호'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.ext_key3 + IS 'LC번호'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.ext_key4 + IS 'BL번호'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.ext_key5 + IS '기타Key5'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.delng_crncy + IS '거래통화'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.delng_amt + IS '거래통화금액'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.acntbk_amt + IS '장부통화금액'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.group_amt + IS '그룹통화금액'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.suply_amount + IS '공급가액'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.sumry + IS '적요'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.org_mtch_ty + IS 'Org.일치유형'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.org_mtch_ky + IS 'Org.일치KEY'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.new_mtch_ty + IS 'New.일치유형'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.new_mtch_ky + IS 'New.일치KEY'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.compare_ky + IS '비교키(시스템)'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.mtch_sys + IS '일치시스템'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.mtch_ty + IS '일치유형'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.mtch_ty_nm + IS '일치유형명칭'; + +COMMENT ON COLUMN batch_tbcr_inner_delng.mtch_ky + IS '일치KEY'; + +CREATE INDEX IF NOT EXISTS batch_tbcr_inner_delng_idx1 + ON batch_tbcr_inner_delng USING btree + (sys_se ASC NULLS LAST, accnut_ym ASC NULLS LAST, cpr_code ASC NULLS LAST, dta_ty ASC NULLS LAST, partn_cpr ASC NULLS LAST); + +CREATE INDEX IF NOT EXISTS batch_tbcr_inner_delng_idx2 + ON batch_tbcr_inner_delng USING btree + (sys_se ASC NULLS LAST, accnut_ym ASC NULLS LAST, cpr_code ASC NULLS LAST, partn_cpr ASC NULLS LAST, compare_ky ASC NULLS LAST); + + + + +CREATE TABLE IF NOT EXISTS tbcr_transaction_history +( + session_id character varying(5) NOT NULL, + cons_group character varying(10) NOT NULL, + ledger character varying(3) NOT NULL, + account_period character varying(6) NOT NULL, + seq numeric NOT NULL, + tran_type character varying(3), + own_comp character varying(10), + tran_comp character varying(10), + comp_acct_code character varying(20), + comp_prod_code character varying(20), + recon_key character varying(100), + tran_date character varying(8), + tran_currency character varying(3), + tran_amt numeric(17,2) DEFAULT 0, + book_amt numeric(17,2) DEFAULT 0, + group_amt numeric(17,2) DEFAULT 0, + book_cost numeric(17,2) DEFAULT 0, + document_no character varying(50), + remark character varying(500), + cons_acct_code character varying(10), + cons_acct_name character varying(100), + prod_code character varying(10), + adjust_type character varying(3), + adjust_remark character varying(255), + if_account_period character varying(6), + if_comp_code character varying(10), + if_file_id character varying(3), + if_source character varying(3), + equal_check character varying(3), + cons_own_comp character varying(10), + cons_tran_comp character varying(10), + invoice_no character varying(80), + lc_no character varying(80), + bl_no character varying(80), + own_biz_no character varying(20), + partner_biz_no character varying(20), + acct_date character varying(8), + matching_cause character varying(10), + match_key numeric(10,0), + CONSTRAINT tbcr_transaction_history_ky PRIMARY KEY (session_id, cons_group, ledger, account_period, seq) +); + + +CREATE TABLE IF NOT EXISTS batch_tbcr_inner_delng_ai +( + sys_se character varying(10) NOT NULL, + accnut_ym character varying(6) NOT NULL, + sn bigint NOT NULL DEFAULT 0, + ai_key1 character varying(100) , + ai_key2 character varying(100) , + ai_key3 character varying(100) , + ai_key4 character varying(100) , + ai_key5 character varying(100) , + ai_key6 character varying(100) , + ai_key7 character varying(100) , + ai_key8 character varying(100) , + ai_key9 character varying(100) , + ai_key10 character varying(100) , + CONSTRAINT batch_tbcr_inner_delng_aikey PRIMARY KEY (sys_se, accnut_ym, sn) +); + + +CREATE TABLE IF NOT EXISTS batch_user_job_status +( + user_job_id character varying(128) COLLATE pg_catalog."default" NOT NULL, + user_job_name character varying(200) COLLATE pg_catalog."default", + start_time timestamp with time zone, + end_time timestamp with time zone, + status character varying(50) COLLATE pg_catalog."default", + exit_code character varying(10) COLLATE pg_catalog."default", + exit_message character varying(2000) COLLATE pg_catalog."default", + CONSTRAINT batch_user_job_status_pkey PRIMARY KEY (user_job_id) + USING INDEX TABLESPACE account +); + +COMMENT ON TABLE batch_user_job_status + IS 'User Job Status'; + + + +-- Table: users + +-- DROP TABLE IF EXISTS users; + +CREATE TABLE IF NOT EXISTS users +( + user_id bigint NOT NULL DEFAULT nextval('users_user_id_seq'::regclass), + activated boolean, + nickname character varying(50) COLLATE pg_catalog."default", + password character varying(100) COLLATE pg_catalog."default", + username character varying(50) COLLATE pg_catalog."default", + CONSTRAINT users_pkey PRIMARY KEY (user_id), + CONSTRAINT uk_r43af9ap4edm43mmtq01oddj6 UNIQUE (username) +); + +-- Table: authority + +-- DROP TABLE IF EXISTS authority; + +CREATE TABLE IF NOT EXISTS authority +( + authority_name character varying(50) COLLATE pg_catalog."default" NOT NULL, + CONSTRAINT authority_pkey PRIMARY KEY (authority_name) +); + +-- Table: user_authority + +-- DROP TABLE IF EXISTS user_authority; + +CREATE TABLE IF NOT EXISTS user_authority +( + user_id bigint NOT NULL, + authority_name character varying(50) COLLATE pg_catalog."default" NOT NULL, + CONSTRAINT user_authority_pkey PRIMARY KEY (user_id, authority_name), + CONSTRAINT fk6ktglpl5mjosa283rvken2py5 FOREIGN KEY (authority_name) + REFERENCES authority (authority_name) MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE NO ACTION, + CONSTRAINT fkhi46vu7680y1hwvmnnuh4cybx FOREIGN KEY (user_id) + REFERENCES users (user_id) MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE NO ACTION +); + +-- Table: sy_cmmn_code_mng + +-- DROP TABLE IF EXISTS sy_cmmn_code_mng; + +CREATE TABLE IF NOT EXISTS sy_cmmn_code_mng +( + code_ty character varying(20) COLLATE pg_catalog."default" NOT NULL, + cmmn_code character varying(20) COLLATE pg_catalog."default" NOT NULL, + mng_iem_1 character varying(50) COLLATE pg_catalog."default", + mng_iem_2 character varying(50) COLLATE pg_catalog."default", + mng_iem_3 character varying(50) COLLATE pg_catalog."default", + mng_iem_4 character varying(50) COLLATE pg_catalog."default", + ordr bigint DEFAULT 0, + use_at character varying(1) COLLATE pg_catalog."default", + register character varying(20) COLLATE pg_catalog."default", + input_de timestamp without time zone, + updusr character varying(20) COLLATE pg_catalog."default", + updt_de timestamp without time zone, + CONSTRAINT sy_cmmn_code_mng_pkey PRIMARY KEY (code_ty, cmmn_code) +); + +COMMENT ON TABLE sy_cmmn_code_mng + IS 'SY_공통코드관리'; + +COMMENT ON COLUMN sy_cmmn_code_mng.code_ty + IS '코드타입'; + +COMMENT ON COLUMN sy_cmmn_code_mng.cmmn_code + IS '공통코드'; + +COMMENT ON COLUMN sy_cmmn_code_mng.mng_iem_1 + IS '관리항목1'; + +COMMENT ON COLUMN sy_cmmn_code_mng.mng_iem_2 + IS '관리항목2'; + +COMMENT ON COLUMN sy_cmmn_code_mng.mng_iem_3 + IS '관리항목3'; + +COMMENT ON COLUMN sy_cmmn_code_mng.mng_iem_4 + IS '관리항목4'; + +COMMENT ON COLUMN sy_cmmn_code_mng.ordr + IS '순서'; + +COMMENT ON COLUMN sy_cmmn_code_mng.use_at + IS '사용여부'; + +COMMENT ON COLUMN sy_cmmn_code_mng.register + IS '입력자'; + +COMMENT ON COLUMN sy_cmmn_code_mng.input_de + IS '입력일자'; + +COMMENT ON COLUMN sy_cmmn_code_mng.updusr + IS '수정자'; + +COMMENT ON COLUMN sy_cmmn_code_mng.updt_de + IS '수정일자'; + + +-- Table: sy_cmmn_code_mng_nls + +-- DROP TABLE IF EXISTS sy_cmmn_code_mng_nls; + +CREATE TABLE IF NOT EXISTS sy_cmmn_code_mng_nls +( + code_ty character varying(20) COLLATE pg_catalog."default" NOT NULL, + cmmn_code character varying(20) COLLATE pg_catalog."default" NOT NULL, + lcal character varying(5) COLLATE pg_catalog."default" NOT NULL, + cmmn_code_nm character varying(100) COLLATE pg_catalog."default", + register character varying(20) COLLATE pg_catalog."default", + input_de timestamp without time zone, + updusr character varying(20) COLLATE pg_catalog."default", + updt_de timestamp without time zone, + CONSTRAINT sy_cmmn_code_mng_nls_pkey PRIMARY KEY (code_ty, cmmn_code, lcal), + CONSTRAINT fk_s_mng_to_s_mng_nls FOREIGN KEY (code_ty, cmmn_code) + REFERENCES sy_cmmn_code_mng (code_ty, cmmn_code) MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE CASCADE +); + +COMMENT ON TABLE sy_cmmn_code_mng_nls + IS 'SY_공통코드관리_NLS'; + +COMMENT ON COLUMN sy_cmmn_code_mng_nls.code_ty + IS '코드타입'; + +COMMENT ON COLUMN sy_cmmn_code_mng_nls.cmmn_code + IS '공통코드'; + +COMMENT ON COLUMN sy_cmmn_code_mng_nls.lcal + IS '로케일'; + +COMMENT ON COLUMN sy_cmmn_code_mng_nls.cmmn_code_nm + IS '공통코드명'; + +COMMENT ON COLUMN sy_cmmn_code_mng_nls.register + IS '입력자'; + +COMMENT ON COLUMN sy_cmmn_code_mng_nls.input_de + IS '입력일자'; + +COMMENT ON COLUMN sy_cmmn_code_mng_nls.updusr + IS '수정자'; + +COMMENT ON COLUMN sy_cmmn_code_mng_nls.updt_de + IS '수정일자'; \ No newline at end of file diff --git a/src/test/java/daeucna/MatchingAiApplicationTests.java b/src/test/java/daeucna/MatchingAiApplicationTests.java new file mode 100644 index 0000000..7cd7224 --- /dev/null +++ b/src/test/java/daeucna/MatchingAiApplicationTests.java @@ -0,0 +1,213 @@ +package daeucna; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; + +import javax.crypto.SecretKey; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +import daeucna.config.security.dto.AuthorityDto; +import daeucna.config.security.dto.LoginDto; +import daeucna.config.security.dto.UserDto; +import daeucna.config.security.jwt.JwtFilter; +import daeucna.config.security.utils.CommonJson; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import lombok.extern.slf4j.Slf4j; + +@SpringBootTest +@ContextConfiguration(classes = MatchingAiApplication.class) +@AutoConfigureMockMvc +@Slf4j +class MatchingAiApplicationTests { + + @Autowired + private MockMvc mockMvc; + + @Test + void userSignup() throws Exception { + AuthorityDto authorityDto = AuthorityDto.builder().authorityName("ROLE_ADMIN").build(); + UserDto userDto = UserDto.builder() + .username("sangkiTest") + .password("sangkiTest") + .nickname("sangkiTest") + .authorityDtoSet(new HashSet( Arrays.asList(authorityDto) )) + .build(); + + String body = CommonJson.objectToString(userDto); + this.mockMvc.perform( + post("/api/signup") + .contentType(MediaType.APPLICATION_JSON) + .content(body) + ) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("sangkiTest"))); + } + + @Test + void authenticate() throws Exception { + fnAuthenticate(); + } + + MvcResult fnAuthenticate() throws Exception { + LoginDto loginDto = LoginDto.builder() + .username("sangkiTest") + .password("sangkiTest") + .build(); + + String body = CommonJson.objectToString(loginDto); + MvcResult mvcResult = this.mockMvc.perform( + post("/api/authenticate") + .contentType(MediaType.APPLICATION_JSON) + .content(body) + ) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("token"))) + .andReturn(); + + return mvcResult; + } + + @SuppressWarnings("unchecked") + @Test + void user() throws Exception { + MvcResult mvcResult = fnAuthenticate(); + String sReturn = mvcResult.getResponse().getContentAsString(); + log.debug("sReturn = " + sReturn); + + HashMap mapVal = (HashMap) CommonJson.stringToObject(sReturn, HashMap.class); + log.debug("token = " + mapVal.get("token") ); + + this.mockMvc.perform( + get("/api/user") + .header("Authorization", "Bearer " + mapVal.get("token")) + ) + .andDo(print()) + .andExpect(status().isOk()); + + } + + @SuppressWarnings("unchecked") + @Test + void testRedirect() throws Exception { + MvcResult mvcResult = fnAuthenticate(); + String sReturn = mvcResult.getResponse().getContentAsString(); + log.debug("sReturn = " + sReturn); + + HashMap mapVal = (HashMap) CommonJson.stringToObject(sReturn, HashMap.class); + log.debug("token = " + mapVal.get("token") ); + + this.mockMvc.perform( + post("/api/test-redirect") + .header("Authorization", "Bearer " + mapVal.get("token")) + ) + .andDo(print()) + .andExpect(status().isOk()); + + } + + @SuppressWarnings("unchecked") + @Test + void userSangki() throws Exception { + MvcResult mvcResult = fnAuthenticate(); + String sReturn = mvcResult.getResponse().getContentAsString(); + log.debug("sReturn = " + sReturn); + + HashMap mapVal = (HashMap) CommonJson.stringToObject(sReturn, HashMap.class); + log.debug("token = " + mapVal.get("token") ); + + this.mockMvc.perform( + get("/api/user/sangki") + .header("Authorization", "Bearer " + mapVal.get("token")) + ) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("sangki"))); + + } + + @SuppressWarnings("unchecked") + @Test + void hello() throws Exception { + MvcResult mvcResult = fnAuthenticate(); + String sReturn = mvcResult.getResponse().getContentAsString(); + log.debug("sReturn = " + sReturn); + + HashMap mapVal = (HashMap) CommonJson.stringToObject(sReturn, HashMap.class); + log.debug("token = " + mapVal.get("token") ); + + this.mockMvc.perform( + get("/api/hello") + .header("Authorization", "Bearer " + mapVal.get("token")) + ) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("hello"))); + + } + + @Test + void parseJwt(@Value("${jwt.secret}") String secret) throws Exception { + MvcResult mvcResult = fnAuthenticate(); + String sReturn = mvcResult.getResponse().getContentAsString(); + + HashMap mapVal = (HashMap) CommonJson.stringToObject(sReturn, HashMap.class); + String accessToken = (String) mapVal.get("token"); + byte[] keyBytes = Decoders.BASE64URL.decode(secret); + SecretKey key = Keys.hmacShaKeyFor(keyBytes); + Jws claims; + try{ + claims = Jwts.parser() + .verifyWith(key) + .build() + .parseSignedClaims(accessToken); + log.debug("parseJwt = " + CommonJson.objectToString(claims)); + log.debug("parseJwt(getSubject) = " + claims.getBody().getSubject()); + log.debug("parseJwt(claims) = " + CommonJson.objectToString(claims.getBody())); + } catch (Exception ignored) { + log.debug("parseJwt = " + ignored.getLocalizedMessage()); + } + } + + @Test + void refreshToken() throws Exception { + + MvcResult mvcResult = fnAuthenticate(); + String sReturn = mvcResult.getResponse().getContentAsString(); + + HashMap mapVal = (HashMap) CommonJson.stringToObject(sReturn, HashMap.class); + String refreshToken = (String) mapVal.get("refreshToken"); + + this.mockMvc.perform( + post("/api/refreshtoken") + .header(JwtFilter.AUTHORIZATION_REFRESH_HEADER, refreshToken) + ) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("token"))) + .andReturn(); + } + +} -- libgit2 0.21.4