Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b7c8e7f41c | |||
| 6c0fca22f3 |
Vendored
+153
-147
@@ -1,174 +1,180 @@
|
||||
pipeline {
|
||||
agent none
|
||||
agent { label 'djb-vm' }
|
||||
|
||||
options {
|
||||
timestamps()
|
||||
disableConcurrentBuilds()
|
||||
skipDefaultCheckout() // stage별 agent의 자동 SCM checkout 방지 (Deploy 노드는 git 접근 불필요, unstash로만 WAR 수신)
|
||||
buildDiscarder(logRotator(numToKeepStr: '20', artifactNumToKeepStr: '20'))
|
||||
}
|
||||
|
||||
environment {
|
||||
JAVA_HOME = '/apps/opts/jdk8'
|
||||
JAVA_HOME_TOMCAT = '/apps/opts/jdk17'
|
||||
GRADLE_HOME = '/apps/opts/gradle-8.7'
|
||||
GRADLE_USER_HOME = '/apps/opts/gradle-home'
|
||||
NODE_HOME = '/apps/opts/node-v24'
|
||||
PATH = "/apps/opts/jdk8/bin:/apps/opts/gradle-8.7/bin:/apps/opts/node-v24/bin:/apps/opts/bin:${env.PATH}"
|
||||
GIT_SSH_COMMAND = 'ssh -o StrictHostKeyChecking=accept-new'
|
||||
WEBHOOK_URL = 'http://172.30.1.50:18000/api/hooks/01ba51b01d3c4c98ae8f3183a23a84ed713197857d024b5da4f303458195eb32'
|
||||
CATALINA_BASE = '/prod/eapim/adminportal'
|
||||
CATALINA_HOME = '/prod/eapim/apache-tomcat-9.0.116'
|
||||
CATALINA_PID = '/prod/eapim/adminportal/temp/catalina.pid'
|
||||
DEPLOY_HTTP_PORT = '39120'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Build (djb-vm)') {
|
||||
agent { label 'djb-vm' }
|
||||
environment {
|
||||
JAVA_HOME = '/apps/opts/jdk8'
|
||||
GRADLE_HOME = '/apps/opts/gradle-8.7'
|
||||
GRADLE_USER_HOME = '/apps/opts/gradle-home'
|
||||
NODE_HOME = '/apps/opts/node-v24'
|
||||
PATH = "/apps/opts/jdk8/bin:/apps/opts/gradle-8.7/bin:/apps/opts/node-v24/bin:/apps/opts/bin:${env.PATH}"
|
||||
}
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps { checkout scm }
|
||||
}
|
||||
|
||||
stage('Checkout dependencies') {
|
||||
steps {
|
||||
sh '''
|
||||
set -eu
|
||||
cd "$WORKSPACE/.."
|
||||
|
||||
mkdir -p eapim-online
|
||||
|
||||
for REPO in elink-online-core elink-online-core-jpa elink-online-transformer elink-online-common elink-online-emsclient; do
|
||||
TARGET="eapim-online/$REPO"
|
||||
if [ ! -d "$TARGET/.git" ]; then
|
||||
rm -rf "$TARGET"
|
||||
git clone --depth=1 --branch master \
|
||||
"ssh://git@172.30.1.50:2222/djb-eapim/$REPO.git" \
|
||||
"$TARGET"
|
||||
else
|
||||
git -C "$TARGET" fetch --depth=1 origin master
|
||||
git -C "$TARGET" reset --hard origin/master
|
||||
git -C "$TARGET" clean -fdx
|
||||
fi
|
||||
done
|
||||
|
||||
for REPO in elink-portal-common eapim-admin-djb; do
|
||||
if [ ! -d "$REPO/.git" ]; then
|
||||
rm -rf "$REPO"
|
||||
git clone --depth=1 --branch master \
|
||||
"ssh://git@172.30.1.50:2222/djb-eapim/$REPO.git" \
|
||||
"$REPO"
|
||||
else
|
||||
git -C "$REPO" fetch --depth=1 origin master
|
||||
git -C "$REPO" reset --hard origin/master
|
||||
git -C "$REPO" clean -fdx
|
||||
fi
|
||||
done
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('Verify toolchain') {
|
||||
steps {
|
||||
sh '''
|
||||
set -eu
|
||||
java -version
|
||||
gradle --version
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build WAR') {
|
||||
steps { sh 'gradle clean build -x test --no-daemon -Pprofile=weblogic' }
|
||||
post {
|
||||
success {
|
||||
sh '''
|
||||
set -eu
|
||||
cd build/libs
|
||||
sha256sum eapim-admin.war > eapim-admin.war.sha256
|
||||
'''
|
||||
archiveArtifacts artifacts: 'build/libs/eapim-admin.war,build/libs/eapim-admin.war.sha256', fingerprint: true
|
||||
stash name: 'war', includes: 'build/libs/eapim-admin.war'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy (weblogic)') {
|
||||
agent { label 'weblogic' }
|
||||
environment {
|
||||
JENKINS_NODE_COOKIE = 'dontKillMe' // background weblogic를 빌드 종료 시 죽이지 않게
|
||||
WL_HOME = '/app/eapim/adminportal'
|
||||
WL_DEPLOY_DIR = '/app/eapim/adminportal'
|
||||
WL_WAR_NAME = 'eapim-admin.war'
|
||||
WL_HTTP_PORT = '39120'
|
||||
WL_NOHUP = '/logs/weblogic/domains/eapimDomain/nohup.emsSvr11.out'
|
||||
}
|
||||
stages {
|
||||
stage('Stop WebLogic') {
|
||||
steps {
|
||||
sh '"$WL_HOME/stopEms11.sh"' // 동기: 완전 종료까지 블록, 미기동 시에도 안전
|
||||
}
|
||||
}
|
||||
stage('Deploy WAR') {
|
||||
steps {
|
||||
unstash 'war'
|
||||
sh '''
|
||||
set -eu
|
||||
cp build/libs/eapim-admin.war "$WL_DEPLOY_DIR/$WL_WAR_NAME"
|
||||
ls -la "$WL_DEPLOY_DIR"
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage('Start WebLogic and readiness') {
|
||||
steps {
|
||||
sh '''
|
||||
set -eu
|
||||
"$WL_HOME/startEms11.sh" # nohup & 로 백그라운드 기동, 즉시 리턴
|
||||
|
||||
DEADLINE=$(($(date +%s) + 300))
|
||||
STATUS=000
|
||||
while [ "$(date +%s)" -lt "$DEADLINE" ]; do
|
||||
STATUS=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 3 \
|
||||
"http://localhost:$WL_HTTP_PORT/monitoring/loginForm.do" 2>/dev/null || echo "000")
|
||||
case "$STATUS" in
|
||||
200|302|401) echo "Readiness OK (/monitoring/loginForm.do HTTP $STATUS)"; break ;;
|
||||
esac
|
||||
sleep 3
|
||||
done
|
||||
|
||||
case "$STATUS" in
|
||||
200|302|401) ;;
|
||||
*)
|
||||
echo "Readiness failed within 300s, last HTTP=$STATUS"
|
||||
[ -f "$WL_NOHUP" ] && tail -120 "$WL_NOHUP"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
success {
|
||||
node('weblogic') {
|
||||
stage('Checkout dependencies') {
|
||||
steps {
|
||||
sh '''
|
||||
set +e
|
||||
payload=$(printf '{"text":"[%s #%s](%s) SUCCESS"}' "$JOB_NAME" "$BUILD_NUMBER" "$BUILD_URL")
|
||||
curl -sS --fail --max-time 5 -H 'Content-Type: application/json' -X POST --data "$payload" "$WEBHOOK_URL" >/dev/null || echo "Webhook failed"
|
||||
set -eu
|
||||
cd "$WORKSPACE/.."
|
||||
|
||||
mkdir -p eapim-online
|
||||
|
||||
for REPO in elink-online-core elink-online-core-jpa elink-online-transformer elink-online-common elink-online-emsclient; do
|
||||
TARGET="eapim-online/$REPO"
|
||||
if [ ! -d "$TARGET/.git" ]; then
|
||||
rm -rf "$TARGET"
|
||||
git clone --depth=1 --branch master \
|
||||
"ssh://git@172.30.1.50:2222/djb-eapim/$REPO.git" \
|
||||
"$TARGET"
|
||||
else
|
||||
git -C "$TARGET" fetch --depth=1 origin master
|
||||
git -C "$TARGET" reset --hard origin/master
|
||||
git -C "$TARGET" clean -fdx
|
||||
fi
|
||||
done
|
||||
|
||||
for REPO in elink-portal-common eapim-admin-djb; do
|
||||
if [ ! -d "$REPO/.git" ]; then
|
||||
rm -rf "$REPO"
|
||||
git clone --depth=1 --branch master \
|
||||
"ssh://git@172.30.1.50:2222/djb-eapim/$REPO.git" \
|
||||
"$REPO"
|
||||
else
|
||||
git -C "$REPO" fetch --depth=1 origin master
|
||||
git -C "$REPO" reset --hard origin/master
|
||||
git -C "$REPO" clean -fdx
|
||||
fi
|
||||
done
|
||||
'''
|
||||
}
|
||||
}
|
||||
failure {
|
||||
node('weblogic') {
|
||||
|
||||
stage('Verify toolchain') {
|
||||
steps {
|
||||
sh '''
|
||||
set -eu
|
||||
java -version
|
||||
gradle --version
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build WAR') {
|
||||
steps {
|
||||
sh 'gradle clean build -x test --no-daemon'
|
||||
}
|
||||
post {
|
||||
success {
|
||||
sh '''
|
||||
set -eu
|
||||
cd build/libs
|
||||
sha1sum eapim-admin.war > eapim-admin.war.sha1
|
||||
sha256sum eapim-admin.war > eapim-admin.war.sha256
|
||||
md5sum eapim-admin.war > eapim-admin.war.md5
|
||||
'''
|
||||
archiveArtifacts artifacts: 'build/libs/eapim-admin.war,build/libs/eapim-admin.war.sha1,build/libs/eapim-admin.war.sha256,build/libs/eapim-admin.war.md5', fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Stop Tomcat') {
|
||||
steps {
|
||||
sh '''
|
||||
set +e
|
||||
payload=$(printf '{"text":"[%s #%s](%s) FAILURE"}' "$JOB_NAME" "$BUILD_NUMBER" "$BUILD_URL")
|
||||
curl -sS --fail --max-time 5 -H 'Content-Type: application/json' -X POST --data "$payload" "$WEBHOOK_URL" >/dev/null || echo "Webhook failed"
|
||||
systemctl --user stop eapim-admin 2>/dev/null
|
||||
|
||||
if [ -f "$CATALINA_PID" ] && kill -0 "$(cat "$CATALINA_PID")" 2>/dev/null; then
|
||||
JAVA_HOME="$JAVA_HOME_TOMCAT" "$CATALINA_HOME/bin/shutdown.sh" 30 -force || true
|
||||
for i in $(seq 1 30); do
|
||||
[ -f "$CATALINA_PID" ] && kill -0 "$(cat "$CATALINA_PID")" 2>/dev/null || break
|
||||
sleep 1
|
||||
done
|
||||
fi
|
||||
rm -f "$CATALINA_PID"
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy monitoring.war') {
|
||||
steps {
|
||||
sh '''
|
||||
set -eu
|
||||
DEPLOY_DIR="$CATALINA_BASE/webapps"
|
||||
rm -rf "$DEPLOY_DIR/monitoring" "$DEPLOY_DIR/monitoring.war"
|
||||
cp build/libs/eapim-admin.war "$DEPLOY_DIR/monitoring.war"
|
||||
ls -la "$DEPLOY_DIR"
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('Start Tomcat and readiness') {
|
||||
steps {
|
||||
sh '''
|
||||
set -eu
|
||||
LOG="$CATALINA_BASE/logs/catalina.$(date +%Y-%m-%d).log"
|
||||
BEFORE=0
|
||||
[ -f "$LOG" ] && BEFORE=$(stat -c %s "$LOG")
|
||||
|
||||
systemctl --user start eapim-admin
|
||||
|
||||
PROBE_URL="http://localhost:$DEPLOY_HTTP_PORT/monitoring/loginForm.do"
|
||||
DEADLINE=$(($(date +%s) + 300))
|
||||
STATUS=000
|
||||
|
||||
while [ "$(date +%s)" -lt "$DEADLINE" ]; do
|
||||
STATUS=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 3 \
|
||||
"$PROBE_URL" 2>/dev/null || echo "000")
|
||||
case "$STATUS" in
|
||||
200|302|401)
|
||||
echo "Readiness OK ($PROBE_URL HTTP $STATUS)"
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -f "$LOG" ] && tail -c +$((BEFORE+1)) "$LOG" | grep -qE "Application listener .* Exception|SEVERE.*startup.Catalina"; then
|
||||
echo "Startup error detected in log"
|
||||
tail -c +$((BEFORE+1)) "$LOG" | tail -80
|
||||
exit 1
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
case "$STATUS" in
|
||||
200|302|401) ;;
|
||||
*)
|
||||
echo "Readiness probe failed within 300s, last HTTP status: $STATUS"
|
||||
echo "--- last 300 lines of catalina log ---"
|
||||
[ -f "$LOG" ] && tail -c +$((BEFORE+1)) "$LOG" | tail -300
|
||||
echo "--- systemd unit status ---"
|
||||
systemctl --user status eapim-admin --no-pager || true
|
||||
echo "--- listening ports ---"
|
||||
ss -tlnp 2>/dev/null | grep -E ":$DEPLOY_HTTP_PORT\\b" || echo "(port $DEPLOY_HTTP_PORT not listening)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "--- key boot log lines ---"
|
||||
tail -c +$((BEFORE+1)) "$LOG" | grep -E "Server startup|Deployment of web" | head -10 || true
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,4 +16,3 @@ PortalPartnershipManController_피드백/개선요청관리_APIGW_UNMASK,DELETE
|
||||
PortalPropertyController_포탈 프로퍼티 관리_APIGW_UPDATE
|
||||
PortalUserTermsManController_약관동의 이력_APIGW_UNMASK
|
||||
MessageRequestManController_메세지발송내역_APIGW_UPDATE_STATUS
|
||||
PortalInquiryManController_Q&A문의관리_APIGW_VISIBILITY
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://xmlns.oracle.com/weblogic/weblogic-web-app"
|
||||
xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
|
||||
elementFormDefault="qualified">
|
||||
|
||||
<xs:element name="weblogic-web-app">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="context-root" type="xs:string" minOccurs="0"/>
|
||||
<xs:element name="session-descriptor" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="timeout-secs" type="xs:integer" minOccurs="0"/>
|
||||
<xs:element name="persistent-store-type" type="xs:string" minOccurs="0"/>
|
||||
</xs:all>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="container-descriptor" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="prefer-application-packages" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="package-name" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="prefer-application-resources" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="resource-name" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
</xs:schema>
|
||||
@@ -1,10 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app">
|
||||
<weblogic-web-app
|
||||
xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app weblogic-web-app.xsd">
|
||||
|
||||
<context-root>monitoring</context-root>
|
||||
<session-descriptor>
|
||||
<timeout-secs>1800</timeout-secs>
|
||||
<cookie-name>JSESSIONID_PORTAL</cookie-name>
|
||||
<persistent-store-type>replicated_if_clustered</persistent-store-type>
|
||||
</session-descriptor>
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
@charset "utf-8";
|
||||
|
||||
.gnb .depth1 > li:hover > a{color:#008cc5;} /* theme */
|
||||
.gnb .sitemap-link:hover{color:#008cc5;} /* theme */
|
||||
.gnb .depth1 > li > .red_box{background:#008cc5;}/* theme */
|
||||
.gnb .depth2 > li > a:hover{color:#008cc5;}/* theme */
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
@charset "utf-8";
|
||||
|
||||
.gnb .depth1 > li:hover > a{color:#16a085;} /* theme */
|
||||
.gnb .sitemap-link:hover{color:#16a085;} /* theme */
|
||||
.gnb .depth1 > li > .red_box{background:#16a085;}/* theme */
|
||||
.gnb .depth2 > li > a:hover{color:#16a085;}/* theme */
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
@charset "utf-8";
|
||||
|
||||
.gnb .depth1 > li:hover > a{color:#e74c3c;} /* theme */
|
||||
.gnb .sitemap-link:hover{color:#e74c3c;} /* theme */
|
||||
.gnb .depth1 > li > .red_box{background:#e74c3c;}/* theme */
|
||||
.gnb .depth2 > li > a:hover{color:#e74c3c;}/* theme */
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
@charset "utf-8";
|
||||
|
||||
.gnb .depth1 > li:hover > a{color:#ff80c0;} /* theme */
|
||||
.gnb .sitemap-link:hover{color:#ff80c0;} /* theme */
|
||||
.gnb .depth1 > li > .red_box{background:#ff80c0;}/* theme */
|
||||
.gnb .depth2 > li > a:hover{color:#ff80c0;}/* theme */
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
@charset "utf-8";
|
||||
|
||||
.gnb .depth1 > li:hover > a{color:#be8200;} /* theme */
|
||||
.gnb .sitemap-link:hover{color:#be8200;} /* theme */
|
||||
.gnb .depth1 > li > .red_box{background:#be8200;}/* theme */
|
||||
.gnb .depth2 > li > a:hover{color:#be8200;}/* theme */
|
||||
|
||||
|
||||
@@ -62,8 +62,8 @@ header.sub{position:relative; padding-top:80px;}
|
||||
100% { color:rgba(255,96,78,0); }
|
||||
} */
|
||||
|
||||
.gnb_bg{position:absolute; top:80px; left:0; display:none; width:100%; height:282px; box-sizing:border-box; background:white; box-shadow: 0px 5px 5px 0px rgba(0,0,0,0.2);}
|
||||
.gnb{position:absolute; top:0px; left:180px; display:inline-block; height:80px; overflow-y:hidden;}
|
||||
.gnb_bg{position:absolute; top:80px; left:0; display:none; width:100%; height:382px; box-sizing:border-box; background:white; box-shadow: 0px 5px 5px 0px rgba(0,0,0,0.2);}
|
||||
.gnb{position:absolute; top:0px; left:230px; display:inline-block; height:80px; overflow-y:hidden;}
|
||||
.gnb:hover{height:auto; overflow-y:visible;}
|
||||
.gnb:hover + .gnb_bg{display:block;}
|
||||
.gnb h1{float:left; display:block; width:auto; height:100%; line-height:80px;}
|
||||
@@ -71,15 +71,15 @@ header.sub{position:relative; padding-top:80px;}
|
||||
|
||||
.gnb .depth1 > li{position:relative;}
|
||||
.gnb .depth1 > li > a{position:relative; display:block; box-sizing:border-box; color:#000; font-size:14px; width:160px; height:80px; text-align:center; line-height:80px; letter-spacing:-0.5px; opacity:0.7; transition:all 0.3s;}
|
||||
.gnb .depth1 > li > a:after{content:''; position:absolute; top:34px; right:0; display:inline-block; width:1px; height:13px; }
|
||||
.gnb .depth1 > li:first-child > a:before{content:''; position:absolute; top:34px; left:0; display:inline-block; width:1px; height:13px; }
|
||||
.gnb .depth1 > li > a:after{content:''; position:absolute; top:34px; right:0; display:inline-block; width:1px; height:13px; background:#ddd;}
|
||||
.gnb .depth1 > li:first-child > a:before{content:''; position:absolute; top:34px; left:0; display:inline-block; width:1px; height:13px; background:#ddd;}
|
||||
/*
|
||||
.gnb .depth1 > li:hover .red_box{transform:scaleX(1);}
|
||||
.gnb .depth1 > li:hover > a{opacity:1;}
|
||||
.gnb .depth1 > li > .red_box{display:block; position:absolute; width:100%; height:2px; top:78px; box-sizing:border-box; background:#ed1c24; transform-origin:center center; transform:scaleX(0); transition:all 0.3s;}
|
||||
*/
|
||||
.gnb .depth2{position:absolute; left:0; top:80px; width:160px; height:310px; box-sizing:border-box; padding:20px 0; border-right:1px solid #eee; text-align:center; z-index:9;}
|
||||
.gnb .depth1 > li:first-child .depth2{border-left:1px solid #eee;}
|
||||
.gnb .depth2{position:absolute; left:0; top:80px; width:160px; height:410px; box-sizing:border-box; padding:20px 0; border-right:1px solid #eee; text-align:center; z-index:9;}
|
||||
.gnb .depth2.first{border-left:1px solid #eee;}
|
||||
.gnb .depth2 > li > a{display:block; color:#000; font-size:13px; line-height:30px;}
|
||||
.gnb .depth2 > li > a:hover{color:#ff0000;}
|
||||
|
||||
@@ -94,9 +94,9 @@ header.sub{position:relative; padding-top:80px;}
|
||||
.left_box .depth3 > li:hover > a, .left_box .depth3 > li.on > a{color:#ed1c24;}
|
||||
|
||||
.content_top{position:fixed; top:0; left:0; padding:0 30px; width:100%; height:50px; line-height:50px; background:#eee; border-top:1px solid #ddd; border-left:1px solid #ddd; z-index:100;}
|
||||
.content_top .path{margin:0; padding:0;}
|
||||
.content_top .path > li{display:inline-block; margin:0; padding:0;}
|
||||
.content_top .path > li a{display:block; height:50px; line-height:50px; padding-left:10px; font-size:12px; color:#999; text-decoration:none;}
|
||||
.content_top .path{}
|
||||
.content_top .path > li{display:inline-block;}
|
||||
.content_top .path > li a{display:block; height:50px; line-height:50px; padding-left:10px; font-size:12px; color:#999;}
|
||||
.content_top .path > li a:hover{color:#666;}
|
||||
.content_top .path > li a:before{content:'>'; margin-right:10px;}
|
||||
.content_top .path > li:first-child a:before{content:'';}
|
||||
|
||||
@@ -301,7 +301,7 @@
|
||||
function goStep(n) {
|
||||
if (n < 1 || n > STEPS.length) return;
|
||||
state.step = n;
|
||||
if (n === 2) state.reqInfoTab = firstReqTabWithData(); // 요청 정보: 값 있는 탭(Header→Parameter→Body 순) 먼저
|
||||
if (n === 2) state.reqInfoTab = 'body'; // 요청/응답 정보: 진입 시 항상 Body 먼저
|
||||
if (n === 3) state.resInfoTab = 'body';
|
||||
renderStepper();
|
||||
renderForm();
|
||||
@@ -439,19 +439,6 @@
|
||||
+ '</div>';
|
||||
}
|
||||
|
||||
// 요청 정보 진입 시 먼저 보일 서브탭 = 값이 든 첫 탭(Header→Parameter→Body 순).
|
||||
// 보통 GET 은 Parameter(query), POST 는 Body 에만 값이 있음. 전부 비면 Body 로.
|
||||
function firstReqTabWithData() {
|
||||
var params = (state.data && state.data.parameters) || [];
|
||||
var hasHeader = params.some(function (p) { return p.in === 'header'; });
|
||||
var hasParam = params.some(function (p) { return p.in === 'query'; });
|
||||
var hasBody = !!(state.data && state.data.requestBody && state.data.requestBody.schema && state.data.requestBody.schema.length);
|
||||
if (hasHeader) return 'header';
|
||||
if (hasParam) return 'param';
|
||||
if (hasBody) return 'body';
|
||||
return 'body';
|
||||
}
|
||||
|
||||
// Step 2 — 요청 정보 (Header / Parameter / Body / API 설명(HTML))
|
||||
function renderReqInfo(root) {
|
||||
const tab = state.reqInfoTab || 'body';
|
||||
|
||||
@@ -1,63 +1,298 @@
|
||||
// OpenAPI 에디터 초기 상태 골격(빈 껍데기).
|
||||
// - specToData() 가 deepClone 하여 서버 spec 값으로 덮어쓰는 구조 기준값.
|
||||
// - 실제 데모/샘플 값은 두지 않는다(팝업은 항상 서버 spec 로드 후 렌더).
|
||||
// - docOptions 만 기능 기본값으로 유지(문서 미리보기 옵션).
|
||||
// locked:true = 게이트웨이 자동 주입(회색+자물쇠) / locked:false = 사용자 편집.
|
||||
// 계좌이체 API 모의 데이터
|
||||
// locked: true 인 필드는 게이트웨이가 자동 주입한 값(회색 + 자물쇠)
|
||||
// locked: false / 미지정 인 필드는 사용자가 자유롭게 편집
|
||||
|
||||
window.SAMPLE_DATA = (function () {
|
||||
function f() { return { value: '', locked: false }; }
|
||||
return {
|
||||
info: {
|
||||
title: f(),
|
||||
version: f(),
|
||||
summary: f(),
|
||||
description: f(),
|
||||
termsOfService: f(),
|
||||
contact: { name: f(), email: f(), url: f() },
|
||||
license: { name: f(), url: f() }
|
||||
title: { value: '계좌이체 API', locked: false },
|
||||
version: { value: '1.0.0', locked: false },
|
||||
summary: { value: '', locked: false },
|
||||
description: { value: '', locked: false },
|
||||
termsOfService: { value: '', locked: false },
|
||||
contact: {
|
||||
name: { value: 'DJB API Team', locked: false },
|
||||
email: { value: 'api@djb.co.kr', locked: false },
|
||||
url: { value: '', locked: false }
|
||||
},
|
||||
license: {
|
||||
name: { value: '', locked: false },
|
||||
url: { value: '', locked: false }
|
||||
}
|
||||
},
|
||||
|
||||
tags: [],
|
||||
tags: [
|
||||
{ name: 'transfer', description: '계좌이체 관련 API' }
|
||||
],
|
||||
|
||||
externalDocs: { description: f(), url: f() },
|
||||
externalDocs: {
|
||||
description: { value: '', locked: false },
|
||||
url: { value: '', locked: false }
|
||||
},
|
||||
|
||||
servers: [],
|
||||
servers: [
|
||||
{
|
||||
url: { value: 'https://api-dev.djb.co.kr', locked: true },
|
||||
env: 'development',
|
||||
description: { value: '개발 환경', locked: false }
|
||||
},
|
||||
{
|
||||
url: { value: 'https://api-stg.djb.co.kr', locked: true },
|
||||
env: 'staging',
|
||||
description: { value: '스테이징 환경', locked: false }
|
||||
},
|
||||
{
|
||||
url: { value: 'https://api.djb.co.kr', locked: true },
|
||||
env: 'production',
|
||||
description: { value: '운영 환경', locked: false }
|
||||
}
|
||||
],
|
||||
|
||||
serverVariables: [],
|
||||
serverVariables: [
|
||||
{
|
||||
name: { value: 'basePath', locked: true },
|
||||
default: { value: '/v1', locked: false },
|
||||
enumStr: { value: '/v1,/v2', locked: false },
|
||||
description: { value: 'API 버전 경로', locked: false }
|
||||
}
|
||||
],
|
||||
|
||||
operation: {
|
||||
method: f(),
|
||||
path: f(),
|
||||
operationId: f(),
|
||||
summary: f(),
|
||||
description: f(),
|
||||
tags: { value: [], locked: false },
|
||||
deprecated: { value: false, locked: false }
|
||||
method: { value: 'POST', locked: true },
|
||||
path: { value: '/v1/accounts/transfer', locked: true },
|
||||
operationId: { value: 'transferAccount', locked: false },
|
||||
summary: { value: '', locked: false },
|
||||
description: { value: '', locked: false },
|
||||
tags: { value: ['transfer'], locked: false },
|
||||
deprecated: { value: false, locked: false }
|
||||
},
|
||||
|
||||
// 파라미터 (Path/Query/Header/Cookie)
|
||||
parameters: [],
|
||||
parameters: [
|
||||
{
|
||||
in: 'header',
|
||||
name: { value: 'X-Request-Id', locked: true },
|
||||
type: { value: 'string', locked: true },
|
||||
required: { value: true, locked: true },
|
||||
format: { value: 'uuid', locked: false },
|
||||
maxLength: { value: '', locked: false },
|
||||
pattern: { value: '', locked: false },
|
||||
description: { value: '', locked: false },
|
||||
example: { value: '', locked: false }
|
||||
}
|
||||
],
|
||||
|
||||
// Request Body 스키마
|
||||
// Request Body 스키마 (중첩 3단)
|
||||
requestBody: {
|
||||
mediaType: 'application/json',
|
||||
required: { value: false, locked: false },
|
||||
schema: []
|
||||
required: { value: true, locked: true },
|
||||
schema: [
|
||||
{
|
||||
name: { value: 'transactionId', locked: true },
|
||||
type: { value: 'string', locked: true },
|
||||
required: { value: true, locked: true },
|
||||
format: { value: '', locked: false },
|
||||
maxLength: { value: '40', locked: false },
|
||||
pattern: { value: '^tx-[0-9a-zA-Z-]+$', locked: false },
|
||||
description: { value: '', locked: false },
|
||||
example: { value: 'tx-20260522-001', locked: false },
|
||||
children: null
|
||||
},
|
||||
{
|
||||
name: { value: 'sender', locked: true },
|
||||
type: { value: 'object', locked: true },
|
||||
required: { value: true, locked: true },
|
||||
format: { value: '', locked: false },
|
||||
maxLength: { value: '', locked: false },
|
||||
pattern: { value: '', locked: false },
|
||||
description: { value: '송금인 정보', locked: false },
|
||||
example: { value: '', locked: false },
|
||||
children: [
|
||||
{
|
||||
name: { value: 'accountNumber', locked: true },
|
||||
type: { value: 'string', locked: true },
|
||||
required: { value: true, locked: true },
|
||||
format: { value: '', locked: false },
|
||||
maxLength: { value: '20', locked: false },
|
||||
pattern: { value: '', locked: false },
|
||||
description: { value: '', locked: false },
|
||||
example: { value: '110-1234-567890', locked: false },
|
||||
children: null
|
||||
},
|
||||
{
|
||||
name: { value: 'bankCode', locked: true },
|
||||
type: { value: 'string', locked: true },
|
||||
required: { value: true, locked: true },
|
||||
format: { value: '', locked: false },
|
||||
maxLength: { value: '3', locked: false },
|
||||
pattern: { value: '', locked: false },
|
||||
description: { value: '', locked: false },
|
||||
example: { value: '088', locked: false },
|
||||
children: null
|
||||
},
|
||||
{
|
||||
name: { value: 'holderName', locked: true },
|
||||
type: { value: 'string', locked: true },
|
||||
required: { value: true, locked: true },
|
||||
format: { value: '', locked: false },
|
||||
maxLength: { value: '60', locked: false },
|
||||
pattern: { value: '', locked: false },
|
||||
description: { value: '', locked: false },
|
||||
example: { value: '김철수', locked: false },
|
||||
children: null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: { value: 'receiver', locked: true },
|
||||
type: { value: 'object', locked: true },
|
||||
required: { value: true, locked: true },
|
||||
format: { value: '', locked: false },
|
||||
maxLength: { value: '', locked: false },
|
||||
pattern: { value: '', locked: false },
|
||||
description: { value: '수취인 정보', locked: false },
|
||||
example: { value: '', locked: false },
|
||||
children: [
|
||||
{
|
||||
name: { value: 'accountNumber', locked: true },
|
||||
type: { value: 'string', locked: true },
|
||||
required: { value: true, locked: true },
|
||||
format: { value: '', locked: false },
|
||||
maxLength: { value: '20', locked: false },
|
||||
pattern: { value: '', locked: false },
|
||||
description: { value: '', locked: false },
|
||||
example: { value: '111-2345-678901', locked: false },
|
||||
children: null
|
||||
},
|
||||
{
|
||||
name: { value: 'bankCode', locked: true },
|
||||
type: { value: 'string', locked: true },
|
||||
required: { value: true, locked: true },
|
||||
format: { value: '', locked: false },
|
||||
maxLength: { value: '3', locked: false },
|
||||
pattern: { value: '', locked: false },
|
||||
description: { value: '', locked: false },
|
||||
example: { value: '020', locked: false },
|
||||
children: null
|
||||
},
|
||||
{
|
||||
name: { value: 'holderName', locked: true },
|
||||
type: { value: 'string', locked: true },
|
||||
required: { value: true, locked: true },
|
||||
format: { value: '', locked: false },
|
||||
maxLength: { value: '60', locked: false },
|
||||
pattern: { value: '', locked: false },
|
||||
description: { value: '', locked: false },
|
||||
example: { value: '이영희', locked: false },
|
||||
children: null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: { value: 'amount', locked: true },
|
||||
type: { value: 'object', locked: true },
|
||||
required: { value: true, locked: true },
|
||||
format: { value: '', locked: false },
|
||||
maxLength: { value: '', locked: false },
|
||||
pattern: { value: '', locked: false },
|
||||
description: { value: '이체 금액', locked: false },
|
||||
example: { value: '', locked: false },
|
||||
children: [
|
||||
{
|
||||
name: { value: 'value', locked: true },
|
||||
type: { value: 'integer', locked: true },
|
||||
required: { value: true, locked: true },
|
||||
format: { value: 'int64', locked: false },
|
||||
maxLength: { value: '', locked: false },
|
||||
pattern: { value: '', locked: false },
|
||||
description: { value: '', locked: false },
|
||||
example: { value: '50000', locked: false },
|
||||
children: null
|
||||
},
|
||||
{
|
||||
name: { value: 'currency', locked: true },
|
||||
type: { value: 'string', locked: true },
|
||||
required: { value: true, locked: true },
|
||||
format: { value: '', locked: false },
|
||||
maxLength: { value: '3', locked: false },
|
||||
pattern: { value: '^[A-Z]{3}$', locked: false },
|
||||
description: { value: 'ISO 4217 통화코드', locked: false },
|
||||
example: { value: 'KRW', locked: false },
|
||||
children: null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: { value: 'memo', locked: true },
|
||||
type: { value: 'string', locked: true },
|
||||
required: { value: false, locked: true },
|
||||
format: { value: '', locked: false },
|
||||
maxLength: { value: '100', locked: false },
|
||||
pattern: { value: '', locked: false },
|
||||
description: { value: '', locked: false },
|
||||
example: { value: '5월 회비', locked: false },
|
||||
children: null
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// 응답 스키마 (상태코드 별)
|
||||
responses: {
|
||||
'200': { description: f(), schema: [] }
|
||||
'200': {
|
||||
description: { value: '이체 성공', locked: false },
|
||||
schema: [
|
||||
{ name: { value: 'transactionId', locked: true }, type: { value: 'string', locked: true }, required: { value: true, locked: true }, format: { value: '', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: 'tx-20260522-001', locked: false }, children: null },
|
||||
{ name: { value: 'status', locked: true }, type: { value: 'string', locked: true }, required: { value: true, locked: true }, format: { value: '', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: 'COMPLETED', locked: false }, children: null },
|
||||
{ name: { value: 'completedAt', locked: true }, type: { value: 'string', locked: true }, required: { value: true, locked: true }, format: { value: 'date-time', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: '2026-05-22T10:00:00Z', locked: false }, children: null },
|
||||
{
|
||||
name: { value: 'balance', locked: true }, type: { value: 'object', locked: true }, required: { value: true, locked: true }, format: { value: '', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '잔액 정보', locked: false }, example: { value: '', locked: false },
|
||||
children: [
|
||||
{ name: { value: 'before', locked: true }, type: { value: 'integer', locked: true }, required: { value: true, locked: true }, format: { value: 'int64', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: '1000000', locked: false }, children: null },
|
||||
{ name: { value: 'after', locked: true }, type: { value: 'integer', locked: true }, required: { value: true, locked: true }, format: { value: 'int64', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: '950000', locked: false }, children: null }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
'400': {
|
||||
description: { value: '잘못된 요청', locked: false },
|
||||
schema: [
|
||||
{
|
||||
name: { value: 'error', locked: true }, type: { value: 'object', locked: true }, required: { value: true, locked: true }, format: { value: '', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: '', locked: false },
|
||||
children: [
|
||||
{ name: { value: 'code', locked: true }, type: { value: 'string', locked: true }, required: { value: true, locked: true }, format: { value: '', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: 'INVALID_AMOUNT', locked: false }, children: null },
|
||||
{ name: { value: 'message', locked: true }, type: { value: 'string', locked: true }, required: { value: true, locked: true }, format: { value: '', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: '금액이 올바르지 않습니다', locked: false }, children: null },
|
||||
{ name: { value: 'details', locked: true }, type: { value: 'array', locked: true }, required: { value: false, locked: true }, format: { value: '', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: '', locked: false }, itemsType: { value: 'string', locked: false }, children: null }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
'401': { description: { value: '인증 실패', locked: false }, schema: [] },
|
||||
'500': { description: { value: '서버 오류', locked: false }, schema: [] }
|
||||
},
|
||||
|
||||
// 보안 스킴
|
||||
securitySchemes: [],
|
||||
globalSecurity: [],
|
||||
securitySchemes: [
|
||||
{
|
||||
key: 'ApiKeyAuth',
|
||||
type: 'apiKey',
|
||||
locked: true,
|
||||
name: { value: 'X-API-Key', locked: true },
|
||||
in: { value: 'header', locked: true },
|
||||
description: { value: '', locked: false }
|
||||
}
|
||||
],
|
||||
globalSecurity: ['ApiKeyAuth'],
|
||||
|
||||
// 예제
|
||||
examples: {
|
||||
request: {},
|
||||
response: {}
|
||||
request: {
|
||||
'application/json': {
|
||||
default: '{\n "transactionId": "tx-20260522-001",\n "sender": {\n "accountNumber": "110-1234-567890",\n "bankCode": "088",\n "holderName": "김철수"\n },\n "receiver": {\n "accountNumber": "111-2345-678901",\n "bankCode": "020",\n "holderName": "이영희"\n },\n "amount": {\n "value": 50000,\n "currency": "KRW"\n },\n "memo": "5월 회비"\n}'
|
||||
}
|
||||
},
|
||||
response: {
|
||||
'200': { body: '{\n "transactionId": "tx-20260522-001",\n "status": "COMPLETED"\n}', headers: [ { name: 'X-RateLimit-Remaining', type: 'integer', description: '남은 요청 횟수', example: '99' } ] }
|
||||
}
|
||||
},
|
||||
|
||||
// 문서 옵션
|
||||
|
||||
@@ -54,18 +54,10 @@ function detail(key){
|
||||
$('#systemCode').val(data.systemCode);
|
||||
$('#logTypeText').val(data.logTypeText);
|
||||
$('#remoteAddress').val(data.remoteAddress);
|
||||
$('#logMsg').val(data.message);
|
||||
$('#logSubMsg').val(data.command);
|
||||
$('#parameters').val(data.parameters);
|
||||
|
||||
// 사유(message)는 값이 있을 때만 노출
|
||||
if (data.message) {
|
||||
$('#logMsg').val(data.message);
|
||||
$('#messageRow').show();
|
||||
} else {
|
||||
$('#logMsg').val('');
|
||||
$('#messageRow').hide();
|
||||
}
|
||||
|
||||
},
|
||||
error:function(e){
|
||||
alert(e.responseText);
|
||||
@@ -129,9 +121,6 @@ $(document).ready(function() {
|
||||
<tr>
|
||||
<th><%= localeMessage.getString("auditLogMan.command") %></th><td><input type="text" id="logSubMsg" name="logSubMsg" readonly="readonly"/></td>
|
||||
</tr>
|
||||
<tr id="messageRow" style="display:none;">
|
||||
<th><%= localeMessage.getString("auditLogMan.message") %></th><td><textarea id="logMsg" name="logMsg" style="width:100%;height:80px" readonly="readonly"></textarea></td>
|
||||
</tr>
|
||||
<tr height="100px">
|
||||
<th><%= localeMessage.getString("auditLogMan.parameters") %></th><td><textarea id="parameters" name="parameters" style="width:100%;height:200px" readonly="readonly"></textarea></td>
|
||||
</tr>
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8"%>
|
||||
<%@ page import="java.util.List"%>
|
||||
<%@ page import="com.eactive.eai.rms.common.acl.sitemap.ui.SitemapNode"%>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||
<%!
|
||||
private void printNodeLabel(javax.servlet.jsp.JspWriter out, SitemapNode node) throws java.io.IOException {
|
||||
String url = node.getMenuUrl();
|
||||
boolean hasLink = url != null && !url.trim().isEmpty() && !"NAN".equalsIgnoreCase(url.trim());
|
||||
if (hasLink) {
|
||||
out.print("<a href=\"javascript:void(0);\" class=\"sitemap-name\" onclick=\"goPage('"
|
||||
+ escapeJs(url) + "','" + escapeJs(node.getMenuId()) + "');return false;\">"
|
||||
+ escapeHtml(node.getMenuName()) + "</a>");
|
||||
} else {
|
||||
out.print("<span class=\"sitemap-name\">" + escapeHtml(node.getMenuName()) + "</span>");
|
||||
}
|
||||
}
|
||||
|
||||
private void printSitemapNode(javax.servlet.jsp.JspWriter out, SitemapNode node) throws java.io.IOException {
|
||||
out.print("<li>");
|
||||
printNodeLabel(out, node);
|
||||
|
||||
List<SitemapNode> children = node.getChildren();
|
||||
if (children != null && !children.isEmpty()) {
|
||||
out.print("<ul>");
|
||||
for (SitemapNode child : children) {
|
||||
printSitemapNode(out, child);
|
||||
}
|
||||
out.print("</ul>");
|
||||
}
|
||||
out.print("</li>");
|
||||
}
|
||||
|
||||
private String escapeHtml(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return value.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """);
|
||||
}
|
||||
|
||||
private String escapeJs(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return value.replace("\\", "\\\\").replace("'", "\\'");
|
||||
}
|
||||
%>
|
||||
<%
|
||||
response.setHeader("Pragma", "No-cache");
|
||||
response.setHeader("Cache-Control", "no-cache");
|
||||
response.setHeader("Expires", "0");
|
||||
|
||||
List<SitemapNode> sitemapTree = (List<SitemapNode>) request.getAttribute("sitemapTree");
|
||||
%>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<jsp:include page="/jsp/common/include/css.jsp"/>
|
||||
<jsp:include page="/jsp/common/include/script.jsp"/>
|
||||
<style>
|
||||
.sitemap-columns { display: flex; flex-wrap: wrap; gap: 40px; }
|
||||
.sitemap-column { min-width: 180px; }
|
||||
.sitemap-category { font-size: 1.1em; font-weight: bold; padding-bottom: 6px; margin-bottom: 8px; border-bottom: 2px solid #ccc; }
|
||||
.sitemap-tree, .sitemap-tree ul { list-style-type: disc; margin: 0; padding-left: 18px; }
|
||||
.sitemap-tree { padding-left: 0; list-style-type: none; }
|
||||
.sitemap-tree li { line-height: 1.8; }
|
||||
a.sitemap-name { text-decoration: none; cursor: pointer; }
|
||||
a.sitemap-name:hover { text-decoration: underline; }
|
||||
</style>
|
||||
<script language="javascript">
|
||||
function goPage(url, menuId) {
|
||||
var serviceType = sessionStorage["serviceType"];
|
||||
|
||||
var pageUrl = url;
|
||||
pageUrl += (pageUrl.indexOf("?") > -1 ? "&" : "?") + "menuId=" + menuId;
|
||||
pageUrl += "&serviceType=" + serviceType;
|
||||
|
||||
parent.leftFrame.location.href = '<c:url value="/leftMenu.do"/>?menuId=' + menuId + '&serviceType=' + serviceType;
|
||||
location.href = pageUrl;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="right_box">
|
||||
<div class="content_top">
|
||||
<ul class="path">
|
||||
<li><a href="#">${rmsMenuPath}</a></li>
|
||||
</ul>
|
||||
</div><!-- end content_top -->
|
||||
<div class="content_middle">
|
||||
<!-- <div class="title">사이트맵</div> -->
|
||||
<div class="sitemap-columns">
|
||||
<%
|
||||
for (SitemapNode category : sitemapTree) {
|
||||
%>
|
||||
<div class="sitemap-column">
|
||||
<div class="sitemap-category">
|
||||
<%
|
||||
printNodeLabel(out, category);
|
||||
%>
|
||||
</div>
|
||||
<ul class="sitemap-tree">
|
||||
<%
|
||||
List<SitemapNode> children = category.getChildren();
|
||||
if (children != null) {
|
||||
for (SitemapNode child : children) {
|
||||
printSitemapNode(out, child);
|
||||
}
|
||||
}
|
||||
%>
|
||||
</ul>
|
||||
</div>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</div>
|
||||
</div><!-- end content_middle -->
|
||||
</div><!-- end right_box -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -531,88 +531,6 @@
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사유 입력 모달 - 확인 시 입력한 사유 문자열을 onConfirm(reason)으로 전달
|
||||
* @param {string} message - 안내 메시지
|
||||
* @param {object} options - (title, confirmText, cancelText, placeholder, required, onConfirm, onCancel)
|
||||
* required 기본 true (빈 사유 차단)
|
||||
*/
|
||||
function showReasonPrompt(message, options) {
|
||||
options = options || {};
|
||||
var title = options.title || '사유 입력';
|
||||
var confirmText = options.confirmText || '확인';
|
||||
var cancelText = options.cancelText || '취소';
|
||||
var placeholder = options.placeholder || '사유를 입력하세요.';
|
||||
var required = options.required !== false;
|
||||
var onConfirm = options.onConfirm || function(){};
|
||||
var onCancel = options.onCancel || function(){};
|
||||
|
||||
// 기존 모달 제거
|
||||
$('#commonReasonModal').remove();
|
||||
|
||||
var iconHtml = getAlertIcon('warning');
|
||||
|
||||
var modalHtml =
|
||||
'<div id="commonReasonModal" class="common-alert-overlay">' +
|
||||
'<div class="common-alert-modal alert-warning">' +
|
||||
'<div class="common-alert-header">' +
|
||||
'<span class="common-alert-icon">' + iconHtml + '</span>' +
|
||||
'<span class="common-alert-title">' + title + '</span>' +
|
||||
'</div>' +
|
||||
'<div class="common-alert-body">' +
|
||||
'<p class="common-alert-message">' + message + '</p>' +
|
||||
'<textarea id="commonReasonInput" maxlength="200" placeholder="' + placeholder + '" style="width:100%;height:80px;margin-top:10px;box-sizing:border-box;font-size:13px;padding:8px;border:1px solid #ddd;border-radius:4px;resize:vertical;"></textarea>' +
|
||||
'<p id="commonReasonError" style="display:none;color:#f44336;font-size:12px;margin:6px 0 0;">사유를 입력해 주세요.</p>' +
|
||||
'</div>' +
|
||||
'<div class="common-alert-footer">' +
|
||||
'<button type="button" class="common-confirm-cancel-btn" id="commonReasonCancelBtn">' + cancelText + '</button>' +
|
||||
'<button type="button" class="common-alert-btn" id="commonReasonOkBtn">' + confirmText + '</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
$('body').append(modalHtml);
|
||||
|
||||
setTimeout(function() {
|
||||
$('#commonReasonModal').addClass('show');
|
||||
$('#commonReasonInput').focus();
|
||||
}, 10);
|
||||
|
||||
// 확인 버튼
|
||||
$('#commonReasonOkBtn').on('click', function() {
|
||||
var reason = $.trim($('#commonReasonInput').val());
|
||||
if (required && reason === '') {
|
||||
$('#commonReasonError').show();
|
||||
$('#commonReasonInput').focus();
|
||||
return;
|
||||
}
|
||||
closeCommonReason(function() { onConfirm(reason); });
|
||||
});
|
||||
|
||||
// 취소 버튼
|
||||
$('#commonReasonCancelBtn').on('click', function() {
|
||||
closeCommonReason(onCancel);
|
||||
});
|
||||
|
||||
// ESC 키로 취소
|
||||
$(document).on('keydown.commonReason', function(e) {
|
||||
if (e.keyCode === 27) {
|
||||
closeCommonReason(onCancel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function closeCommonReason(callback) {
|
||||
$('#commonReasonModal').removeClass('show');
|
||||
setTimeout(function() {
|
||||
$('#commonReasonModal').remove();
|
||||
$(document).off('keydown.commonReason');
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- 공용 Alert 모달 스타일 -->
|
||||
|
||||
@@ -91,10 +91,7 @@
|
||||
data: $('#loginForm').serialize(),
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
if (response.changePassword) {
|
||||
showChangeInitPassword(response);
|
||||
}
|
||||
else if (response.smsAuthRequired) {
|
||||
if (response.smsAuthRequired) {
|
||||
// SMS 인증 필요
|
||||
showSmsAuthModal(response);
|
||||
} else if (response.success) {
|
||||
@@ -111,13 +108,6 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showChangeInitPassword(data) {
|
||||
$('input[name="resetUserId"]').val($('input[name="userId"]').val());
|
||||
$('input[name="resetPassword"]').val($('input[name="password"]').val());
|
||||
$('#changeInitPassword').hide();
|
||||
$('#pwdChgModal').modal('show');
|
||||
}
|
||||
|
||||
// SMS 인증 모달 표시
|
||||
function showSmsAuthModal(data) {
|
||||
@@ -228,39 +218,44 @@
|
||||
clearInterval(resendTimer);
|
||||
$('#smsAuthModal').modal('hide');
|
||||
}
|
||||
|
||||
function checkPwd(){
|
||||
function changePwd(){
|
||||
if ($("input[name=resetUserId]").val() == null || $("input[name=resetUserId]").val().length == 0 ){
|
||||
alert("<%= localeMessage.getString("login.checkid") %>");
|
||||
$("input[name=resetUserId]").trigger("focus");
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
if ($("input[name=resetPassword]").val() == null || $("input[name=resetPassword]").val().trim().length == 0 ){
|
||||
alert("<%= localeMessage.getString("login.checkpwd1") %>");
|
||||
$("input[name=resetPassword]").trigger("focus");
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
if ($("input[name=changePassword]").val() == null || $("input[name=changePassword]").val().trim().length == 0 ){
|
||||
alert("<%= localeMessage.getString("login.checkpwd2") %>");
|
||||
$("input[name=changePassword]").trigger("focus");
|
||||
return false;
|
||||
return ;
|
||||
}
|
||||
if ($("input[name=confirmPassword]").val() == null || $("input[name=confirmPassword]").val().trim().length == 0 ){
|
||||
alert("<%= localeMessage.getString("login.checkpwd3") %>");
|
||||
return false;
|
||||
return ;
|
||||
}
|
||||
if ($("input[name=changePassword]").val() != $("input[name=confirmPassword]").val()){
|
||||
if ($("input[name=confirmPassword]").val() != $("input[name=confirmPassword]").val()){
|
||||
alert("<%= localeMessage.getString("login.checkpwd4") %>");
|
||||
$("input[name=confirmPassword]").trigger("focus");
|
||||
return false;
|
||||
return ;
|
||||
}
|
||||
if ($("input[name=resetUserId]").val() == $("input[name=changePassword]").val()){
|
||||
alert("<%= localeMessage.getString("login.checkpwd5") %>");
|
||||
$("input[name=changePassword]").trigger("focus");
|
||||
return false;
|
||||
return ;
|
||||
}
|
||||
|
||||
return true;
|
||||
//if (idCheck.checked){
|
||||
// setCookie("key",id);
|
||||
//}
|
||||
<%-- $("form").attr("action","<c:url value="/changePassword.do"/>");
|
||||
//$("form").action = "<%=request.getContextPath()%>/changePassword.do";
|
||||
--%>
|
||||
$("form").submit();
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
@@ -276,22 +271,14 @@
|
||||
});
|
||||
$("input[name=changePassword]").keydown(function(event){
|
||||
if ( event.which == 13 ) {
|
||||
$('#modalLoginForm').submit();
|
||||
changePwd();
|
||||
}
|
||||
});
|
||||
$("input[name=confirmPassword]").keydown(function(event){
|
||||
if ( event.which == 13 ) {
|
||||
$('#modalLoginForm').submit();
|
||||
changePwd();
|
||||
}
|
||||
});
|
||||
// Password Change 링크로 직접 열 때만 초기화 (JS에서 modal('show') 호출 시 relatedTarget 없음)
|
||||
$('#pwdChgModal').on('show.bs.modal', function(event) {
|
||||
if (event.relatedTarget) {
|
||||
$('#modalLoginForm')[0].reset();
|
||||
$('#changeInitPassword').show();
|
||||
}
|
||||
});
|
||||
|
||||
$("select[name=serviceType]").change(function(){
|
||||
fncPreMain();
|
||||
});
|
||||
@@ -299,7 +286,9 @@
|
||||
$("#btn_login").click(function(){
|
||||
fncPreMain();
|
||||
});
|
||||
|
||||
$("#changePwd").click(function(){
|
||||
changePwd();
|
||||
});
|
||||
$("#btn_sso_login").click(function(){
|
||||
fncSsoLogin();
|
||||
});
|
||||
@@ -377,7 +366,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 비밀번호 변경 모달 -->
|
||||
|
||||
<div class="modal fade" id="pwdChgModal" tabindex="-1" role="dialog" aria-labelledby="pwdChgModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
@@ -387,15 +376,13 @@
|
||||
<span aria-hidden="true">X</span>
|
||||
</button>
|
||||
</div>
|
||||
<form id="modalLoginForm" action="<c:url value="/changePassword.do"/>" method="post" onsubmit="return checkPwd()" novalidate>
|
||||
<form name="form" id="modalLoginForm" action="<c:url value="/changePassword.do"/>" method="post">
|
||||
<div class="modal-body">
|
||||
<div id="changeInitPassword">
|
||||
<div class="form-group d-flex">
|
||||
<input type="text" name="resetUserId" class="form-control rounded-left" placeholder="User Id" required>
|
||||
</div>
|
||||
<div class="form-group d-flex">
|
||||
<input type="password" name="resetPassword" class="form-control rounded-left" placeholder="<%= localeMessage.getString("login.placeholderCurrentPassword") %>" autocomplete="off" required>
|
||||
</div>
|
||||
<div class="form-group d-flex">
|
||||
<input type="text" name="resetUserId" class="form-control rounded-left" placeholder="User Id" required>
|
||||
</div>
|
||||
<div class="form-group d-flex">
|
||||
<input type="password" name="resetPassword" class="form-control rounded-left" placeholder="<%= localeMessage.getString("login.placeholderCurrentPassword") %>" autocomplete="off" required>
|
||||
</div>
|
||||
<p><%= localeMessage.getString("login.toChangePasswordMessage") %></p>
|
||||
<div class="form-group d-flex">
|
||||
@@ -404,12 +391,9 @@
|
||||
<div class="form-group d-flex">
|
||||
<input type="password" name="confirmPassword" class="form-control rounded-left" placeholder="<%= localeMessage.getString("login.placeholderConfirmationPassword") %>" autocomplete="off" required>
|
||||
</div>
|
||||
<span style="font-size:0.8em; color:red">
|
||||
※ 7글자 이상 & 영문/숫자/특수문자 2종류 이상
|
||||
</span>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" id="changePwd" class="form-control btn btn-primary rounded submit px-3">변경</button>
|
||||
<input type="button" id ="changePwd" class="form-control btn btn-primary rounded submit px-3" value="변경">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
<%@page import="com.eactive.eai.rms.common.util.StringUtils" %>
|
||||
<%@page import="com.eactive.eai.rms.common.datasource.DataSourceType" %>
|
||||
<%@page import="com.eactive.eai.rms.common.datasource.DataSourceTypeManager" %>
|
||||
<%@page import="com.eactive.eai.common.util.ApplicationContextProvider" %>
|
||||
<%@page import="com.eactive.eai.rms.data.entity.man.role.RoleMenuAuthService" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
|
||||
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
||||
@@ -18,12 +16,6 @@
|
||||
<%
|
||||
String serviceKey = SessionManager.getServiceTypeKey(request);
|
||||
String serviceText = DataSourceTypeManager.getDataSourceType(serviceKey).getText();
|
||||
|
||||
final String SITEMAP_MENU_ID = "0510013";
|
||||
RoleMenuAuthService roleMenuAuthService = ApplicationContextProvider.getContext().getBean(RoleMenuAuthService.class);
|
||||
String sitemapMenuAuth = roleMenuAuthService.getRoleList(SessionManager.getUserId(request), SITEMAP_MENU_ID, serviceKey);
|
||||
boolean showSitemapLink = "R".equals(sitemapMenuAuth) || "W".equals(sitemapMenuAuth);
|
||||
|
||||
String roleScreenId = (String) request.getAttribute("roleScreenId");
|
||||
String mainPage = (String) request.getAttribute("mainPage");
|
||||
String menuId = (String) request.getAttribute("menuId");
|
||||
@@ -248,12 +240,6 @@
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="<c:url value="/css/web_ui.css"/>"/>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="<c:url value="/css/theme_${themeColor}.css"/>"/>
|
||||
<style>
|
||||
.topmenu_box .sitemap-link { display: inline-block; width: 80px; height: 80px; line-height: 80px; box-sizing: border-box; font-size: 14px; color: #666; text-align: center; opacity: 0.7; transition: all 0.3s; margin-top: 0px; }
|
||||
.topmenu_box .sitemap-link:hover { opacity: 1; }
|
||||
.topmenu_box .logout-link { line-height: 80px; margin-top:0; }
|
||||
.topmenu_box > ul li:last-child > a:before { display: none; }
|
||||
</style>
|
||||
<script language="javascript" src="<c:url value="/js/jquery-1.12.1.min.js"/>"></script>
|
||||
<script language="javascript" src="<c:url value="/js/prefixfree.min.js"/>"></script>
|
||||
<script language="javascript" src="<c:url value="/js/jquery.cookie.js"/>"></script>
|
||||
@@ -317,11 +303,11 @@
|
||||
}
|
||||
|
||||
//왼쪽메뉴, 메인 페이지 이동
|
||||
function goPage2(page1, page2, page2_id) {
|
||||
function goPage2(page1, page2, page2_id) {
|
||||
parent.leftFrame.location.href = goNavUrl(page1);
|
||||
parent.mainFrame.location.href = goNavUrl(page2);
|
||||
}
|
||||
|
||||
|
||||
var sessionAjax = createAjaxRequest();
|
||||
|
||||
function getAjaxData() {
|
||||
@@ -543,7 +529,6 @@
|
||||
console.log("selectLocaleValue : " + selectLocaleValue);
|
||||
parent.changeLocale($(this).val());
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$(function() {
|
||||
@@ -574,20 +559,13 @@
|
||||
<span style="display:block;font-size:10px;"><%=localeMessage.getString("screen.lastLogin") %> : <%=LastLoginYms%> [ <%=LastLoginIp%> ]</span>
|
||||
<% } %>
|
||||
</a></li>
|
||||
<li style="width:100px; line-height:80px; text-align:center;">
|
||||
<select id="selectLocale" name="locale" style="width:60px; padding: 2px; text-align:center;">
|
||||
<li>
|
||||
<select id="selectLocale" name="locale" style="margin-top: 20px; width:80px">
|
||||
<option value="en">English</option>
|
||||
<option value="ko">한글</option>
|
||||
</select>
|
||||
</li>
|
||||
<% if (showSitemapLink) { %>
|
||||
<li>
|
||||
<a href="<c:url value="/common/acl/sitemap/sitemapMan.view"><c:param name="menuId" value="<%=SITEMAP_MENU_ID%>"/><c:param name="serviceType" value="<%=serviceKey%>"/></c:url>" target="mainFrame" class="sitemap-link">
|
||||
<%= localeMessage.getString("screen.sitemap") %>
|
||||
</a>
|
||||
</li>
|
||||
<% } %>
|
||||
<li onclick="logout()"><a href="#" class="logout-link"><img src="<c:url value="/img/icon_logout.png"/>"
|
||||
<li onclick="logout()"><a href="#" class=""><img src="<c:url value="/img/icon_logout.png"/>"
|
||||
alt=""/><%= localeMessage.getString("screen.logout") %>
|
||||
</a></li>
|
||||
</ul>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
var url = '<c:url value="/onl/admin/authserver/scopeMan.json" />';
|
||||
var url_view = '<c:url value="/onl/admin/authserver/scopeMan.view" />';
|
||||
var api_url_view = '<c:url value="/onl/apim/apigroup/apiGroupMan.view" />';
|
||||
var mapping_url = '<c:url value="/onl/admin/authserver/apiScopeMan.json" />';
|
||||
|
||||
var isDetail = false;
|
||||
function isValid(){
|
||||
@@ -64,9 +65,9 @@ function mappingInfo(key){
|
||||
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url: url,
|
||||
url: mapping_url,
|
||||
dataType: "json",
|
||||
data: {cmd: 'API_LIST', searchScopeId : key},
|
||||
data: {cmd: 'LIST', searchScopeId : key},
|
||||
success: function(json){
|
||||
var mappingData = json.rows;
|
||||
|
||||
@@ -130,6 +131,45 @@ function init(key, callback){
|
||||
}
|
||||
}
|
||||
|
||||
function saveApiGridData(scopeId, returnUrl) {
|
||||
var postData = [];
|
||||
var rows = $("#selectedApiGrid").jqGrid('getRowData');
|
||||
|
||||
$.each(rows, function(index, item) {
|
||||
item.scopeId = scopeId;
|
||||
});
|
||||
|
||||
postData.push({
|
||||
name: "apiList",
|
||||
value: JSON.stringify(rows)
|
||||
});
|
||||
|
||||
postData.push({ name: "cmd" , value:"INSERT_APILIST" });
|
||||
postData.push({ name: "scopeId" , value:scopeId });
|
||||
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url:mapping_url,
|
||||
data: postData,
|
||||
beforeSend: function() {
|
||||
$("[id^='btn_']").prop("disabled", true);
|
||||
$("#btn_modify").text("처리중 . . . . .");
|
||||
},
|
||||
success:function(args){
|
||||
alert("저장 되었습니다.");
|
||||
|
||||
goNav(returnUrl);//LIST로 이동
|
||||
},
|
||||
error:function(e){
|
||||
alert(e.responseText);
|
||||
},
|
||||
complete: function() {
|
||||
$("[id^='btn_']").prop("disabled", false);
|
||||
$("#btn_modify").text("수정");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
var returnUrl = getReturnUrlForReturn();
|
||||
var key ="${param.scopeId}";
|
||||
@@ -142,39 +182,28 @@ $(document).ready(function() {
|
||||
if (!isValid()){
|
||||
return;
|
||||
}
|
||||
var scopeId = $('input[name=scopeId]').val();
|
||||
var postData = $('#ajaxForm').serializeArray();
|
||||
|
||||
var rows = $("#selectedApiGrid").jqGrid('getRowData');
|
||||
$.each(rows, function(index, item) {
|
||||
item.scopeId = scopeId;
|
||||
});
|
||||
postData.push({ name: "apiList" , value: JSON.stringify(rows) });
|
||||
|
||||
if (isDetail){
|
||||
postData.push({ name: "cmd" , value:"UPDATE"});
|
||||
}else{
|
||||
postData.push({ name: "cmd" , value:"INSERT"});
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url:url,
|
||||
data:postData,
|
||||
beforeSend: function() {
|
||||
$("[id^='btn_']").prop("disabled", true);
|
||||
$("#btn_modify").text("처리중 . . . . .");
|
||||
},
|
||||
success:function(args){
|
||||
alert("저장 되었습니다.");
|
||||
goNav(returnUrl);//LIST로 이동
|
||||
alert("SCOPE 정보가 저장 되었습니다. 이어서 API 리스트를 저장합니다.");
|
||||
|
||||
if(!isDetail) { // INSERT 일 경우 ScopeId를 업데이트
|
||||
key = $('input[name=scopeId]').val();
|
||||
}
|
||||
saveApiGridData(key, returnUrl); // API LIST 저장.
|
||||
|
||||
|
||||
},
|
||||
error:function(e){
|
||||
alert(e.responseText);
|
||||
},
|
||||
complete: function() {
|
||||
$("[id^='btn_']").prop("disabled", false);
|
||||
$("#btn_modify").text("수정");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -298,7 +298,6 @@ $(document).ready(function() {
|
||||
url: url,
|
||||
data: postData,
|
||||
success: function(args) {
|
||||
console.log('mod', args);
|
||||
showAlert("<%= localeMessage.getString("common.saveMsg") %>", {
|
||||
type: 'success',
|
||||
title: '저장 완료',
|
||||
|
||||
@@ -71,11 +71,11 @@
|
||||
|
||||
$('#grid').children().remove();
|
||||
|
||||
const itemTypes = ['Field', 'Grid', 'Group', 'Attr', 'Array'];
|
||||
const itemTypes = ['Field', 'Grid', 'Group', 'Attr'];
|
||||
|
||||
columns = [ // for columnData prop
|
||||
{ title: '<%= localeMessage.getString("layoutMan.itemDesc") %>', name: 'loutItemDesc', type: 'text', width:280, resize:true, minWidth:120 },
|
||||
{ title: '<%= localeMessage.getString("layoutMan.itmeEn") %>', name: 'loutItemName', type: 'text', width:280, resize:true, minWidth:120 },
|
||||
{ title: '<%= localeMessage.getString("layoutMan.itemDesc") %>', name: 'loutItemDesc', type: 'text', width:280, resize:true, minWidth:120 },
|
||||
{ title: '<%=localeMessage.getString("standardLayout.itemLevel")%>', name: 'loutItemDepth', type: 'text', width:50 },
|
||||
{ title: '<%= localeMessage.getString("standardLayout.itemType") %>', name: 'loutItemType', type: 'autocomplete', source: itemTypes, width:70 },
|
||||
{ title: '<%= localeMessage.getString("standardLayout.arraySize") %>', name: 'loutItemOccCnt', type: 'text', width:90 },
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
const LAYOUT_ITEM_TYPE_GROUP = "Group";
|
||||
const LAYOUT_ITEM_TYPE_GRID = "Grid";
|
||||
const LAYOUT_ITEM_TYPE_FIELD = "Field";
|
||||
const LAYOUT_ITEM_TYPE_ARRAY = "Array";
|
||||
|
||||
var isDetail = false;
|
||||
|
||||
@@ -551,14 +550,6 @@
|
||||
return data;
|
||||
}
|
||||
|
||||
// 항목 자신이 Array인 경우, 경로/변환명령 끝에 반복 표시 [*]를 추가
|
||||
function addArrayTag(loutItemType, data) {
|
||||
if (loutItemType == LAYOUT_ITEM_TYPE_ARRAY && !data.endsWith("[*]")) {
|
||||
data = data + "[*]";
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
//변환명에 있는 서비스코드와 if서비스 코드 매칭
|
||||
function validation(){
|
||||
if ($('input[name=cnvsnName]').val() == '') {
|
||||
@@ -898,10 +889,10 @@
|
||||
let selectValue = "";
|
||||
let targetValue = "";
|
||||
for ( var i = 0; i < sourceData.length; i++) {
|
||||
if (sourceData[i]['loutItemType'] != "Field" && sourceData[i]['loutItemType'] != "Attr" && sourceData[i]['loutItemType'] != "Array") continue;
|
||||
if (sourceData[i]['loutItemType'] != "Field" && sourceData[i]['loutItemType'] != "Attr") continue;
|
||||
selectValue = (sourceData[i]['LOUTITEMPATH']).substr(sourceData[i]['loutName'].length+1);
|
||||
for (var j = 0; j <targetData.length; j++) {
|
||||
if (targetData[j]['loutItemType'] != "Field" && targetData[j]['loutItemType'] != "Attr" && targetData[j]['loutItemType'] != "Array") continue;
|
||||
if (targetData[j]['loutItemType'] != "Field" && targetData[j]['loutItemType'] != "Attr") continue;
|
||||
targetValue = (targetData[j]['LOUTITEMPATH']).substr(targetData[j]['loutName'].length+1);
|
||||
if (targetValue == selectValue ) {
|
||||
var data = sourceData[i]['LOUTITEMPATH'];
|
||||
@@ -925,8 +916,8 @@
|
||||
//field, ATTR 여부 판단
|
||||
var sourceRow = sourceGrid.getRowData( srcRowId );
|
||||
var targetRow = targetGrid.getRowData( tgtRowId );
|
||||
if ( (sourceRow["loutItemType"] == 'Field' || sourceRow["loutItemType"] == 'Attr' || sourceRow["loutItemType"] == 'Array') &&
|
||||
(targetRow["loutItemType"] == 'Field' || targetRow["loutItemType"] == 'Attr' || targetRow["loutItemType"] == 'Array') ){
|
||||
if ( (sourceRow["loutItemType"] == 'Field' || sourceRow["loutItemType"] == 'Attr') &&
|
||||
(targetRow["loutItemType"] == 'Field' || targetRow["loutItemType"] == 'Attr') ){
|
||||
;
|
||||
}else{
|
||||
alert('<%=localeMessage.getString("transformManDetail.alert3")%>');
|
||||
@@ -945,15 +936,15 @@
|
||||
var targetValue = "";
|
||||
var j=tgtIndex-1-1;
|
||||
for ( var i = srcIndex-1; i < sourceData.length; i++) {
|
||||
if (sourceData[i]['loutItemType'] != LAYOUT_ITEM_TYPE_FIELD && sourceData[i]['loutItemType'] != LAYOUT_ITEM_TYPE_ARRAY) continue;
|
||||
if (sourceData[i]['loutItemType'] != LAYOUT_ITEM_TYPE_FIELD) continue;
|
||||
j++;
|
||||
while (targetData.length -1 >= j && targetData[j]["loutItemType"] != LAYOUT_ITEM_TYPE_FIELD && targetData[j]["loutItemType"] != LAYOUT_ITEM_TYPE_ARRAY){
|
||||
while (targetData.length -1 >= j &&targetData[j]["loutItemType"] != LAYOUT_ITEM_TYPE_FIELD){
|
||||
j++;
|
||||
}
|
||||
if (targetData.length -1 < j) break;
|
||||
var targetRowId = targetData[j]['id'];
|
||||
targetGrid.jqGrid('setCell',targetRowId,'CNVSNCMDNAME',addArrayTag(sourceData[i]['loutItemType'], addGroupTag(srcGroup,sourceData[i]['LOUTITEMPATH'])));
|
||||
targetGrid.jqGrid('setCell',targetRowId,'CNVSNRSULTITEMPATHNAME',addArrayTag(targetData[j]['loutItemType'], addGroupTag(tgtGroup,targetData[j]['LOUTITEMPATH'])));
|
||||
targetGrid.jqGrid('setCell',targetRowId,'CNVSNCMDNAME',addGroupTag(srcGroup,sourceData[i]['LOUTITEMPATH']));
|
||||
targetGrid.jqGrid('setCell',targetRowId,'CNVSNRSULTITEMPATHNAME',addGroupTag(tgtGroup,targetData[j]['LOUTITEMPATH']));
|
||||
targetGrid.jqGrid('setCell',targetRowId,'CNVSNITEMSERNO',targetData[j]['loutItemSerno']);
|
||||
|
||||
const sourceEndpointElementId = sourceGrid.getEndpointElementId(sourceData[i]['id']);
|
||||
@@ -1024,7 +1015,7 @@
|
||||
var targetData = targetGrid.getRowData();
|
||||
var gridData = new Array();
|
||||
for (var i = 0; i <targetData.length; i++) {
|
||||
if ((targetData[i]['loutItemType'] != "Field") && (targetData[i]['loutItemType'] != "Attr") && (targetData[i]['loutItemType'] != "Array")) {
|
||||
if ((targetData[i]['loutItemType'] != "Field") && (targetData[i]['loutItemType'] != "Attr")) {
|
||||
continue;
|
||||
}
|
||||
if (targetData[i]['CNVSNCMDNAME']==null
|
||||
@@ -1167,7 +1158,7 @@
|
||||
function srcformatterFunction(cellvalue,options,rowObject){
|
||||
var rowId = options["rowId"];
|
||||
var loutItemType = rowObject["loutItemType"];
|
||||
if (loutItemType == 'Field' || loutItemType == 'Attr' || loutItemType == 'Array'){
|
||||
if (loutItemType == 'Field' || loutItemType == 'Attr'){
|
||||
return "<div id='div_src_"+rowId+"' name='src_"+rowId+"' style='width:28px;height:17px;background-color: #D12F35; border-color: #ab1717; border-style: solid; border-width: 1px; border-radius: 3px;' />";
|
||||
}else{
|
||||
return "<div id='div_srcgroup_"+rowId+"' name='srcgroup_"+rowId+"' style='width:28px;height:17px;' />";
|
||||
@@ -1179,7 +1170,7 @@
|
||||
function tgtformatterFunction(cellvalue,options,rowObject){
|
||||
var rowId = options["rowId"];
|
||||
var loutItemType = rowObject["loutItemType"];
|
||||
if (loutItemType == 'Field' || loutItemType == 'Attr' || loutItemType == 'Array'){
|
||||
if (loutItemType == 'Field' || loutItemType == 'Attr'){
|
||||
return "<div id='div_tgt_"+rowId+"_base' name='div_tgt_"+rowId+"_base' style='width:30px;height:20px; background-color:gray;' >"
|
||||
+ "<div id='div_tgt_"+rowId+"' name='tgt_"+rowId+"' style='width:28px;height:17px; background-color: #3E7E9C; border-color: #217ca7; border-style: solid; border-width: 1px; border-radius: 3px;' onclick='jqGridOnTargetGridEndpointClick(this)'>"
|
||||
+ "</div></div>";
|
||||
@@ -1678,8 +1669,8 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if ((sourceRow["loutItemType"] != 'Field' && sourceRow["loutItemType"] != 'Attr' && sourceRow["loutItemType"] != 'Array')
|
||||
|| (targetRow["loutItemType"] != 'Field' && targetRow["loutItemType"] != 'Attr' && targetRow["loutItemType"] != 'Array')) {
|
||||
if ((sourceRow["loutItemType"] != 'Field' && sourceRow["loutItemType"] != 'Attr')
|
||||
|| (targetRow["loutItemType"] != 'Field' && targetRow["loutItemType"] != 'Attr')) {
|
||||
alert('<%=localeMessage.getString("transformManDetail.alert3")%>');
|
||||
return ;
|
||||
}
|
||||
@@ -1693,7 +1684,7 @@
|
||||
|
||||
if (targetRow['CNVSNCMDNAME'] == '') {
|
||||
// 변환 명령 값이 한번 설정 되면 변경 되지 않게 함.
|
||||
var cnvsnCmdName = addArrayTag(sourceRow["loutItemType"], addGroupTag(srcGroup,sourceRow["LOUTITEMPATH"]));
|
||||
var cnvsnCmdName = addGroupTag(srcGroup,sourceRow["LOUTITEMPATH"]);
|
||||
// function까지 처리되도록 수정했으나, parameter가 하나인 경우에만 정상처리됨
|
||||
if($('#functionCombo').val() != "") {
|
||||
cnvsnCmdName = $('#functionCombo').val() + "(" + cnvsnCmdName + ")";
|
||||
@@ -1702,7 +1693,7 @@
|
||||
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNCMDNAME', cnvsnCmdName);
|
||||
}
|
||||
|
||||
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNRSULTITEMPATHNAME',addArrayTag(targetRow["loutItemType"], addGroupTag(tgtGroup,targetRow["LOUTITEMPATH"])));
|
||||
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNRSULTITEMPATHNAME',addGroupTag(tgtGroup,targetRow["LOUTITEMPATH"]));
|
||||
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNITEMSERNO',targetRow['loutItemSerno']);
|
||||
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNSRCITEMS', cnvsnSrcItems);
|
||||
targetGrid.jqGrid('setCell',tgtRowId,'ISVALIDMAPPING', true);
|
||||
@@ -1894,8 +1885,8 @@
|
||||
if (loutItemType == LAYOUT_ITEM_TYPE_GRID || loutItemType == LAYOUT_ITEM_TYPE_GROUP) {
|
||||
// group 인 경우
|
||||
items = createGridGroupContextMenuItems(grid, rowId);
|
||||
} else if(loutItemType == LAYOUT_ITEM_TYPE_FIELD || loutItemType == LAYOUT_ITEM_TYPE_ARRAY) {
|
||||
// field, array 인 경우
|
||||
} else if(loutItemType == LAYOUT_ITEM_TYPE_FIELD) {
|
||||
// field 인 경우
|
||||
items = createFieldContextMenuItems(grid, positionElement.attr('id'));
|
||||
} else {
|
||||
return false;
|
||||
@@ -1998,7 +1989,7 @@
|
||||
break;
|
||||
}
|
||||
|
||||
if (loutItemType == LAYOUT_ITEM_TYPE_FIELD || loutItemType == LAYOUT_ITEM_TYPE_ARRAY) {
|
||||
if (loutItemType == LAYOUT_ITEM_TYPE_FIELD) {
|
||||
loutItemPath = loutItemPath.replace(new RegExp("^" + prefix), "");
|
||||
console.debug(grid.getId() + " : loutItemPath : " + loutItemPath);
|
||||
rowData['GROUP_LOUTITEMPATH'] = loutItemPath;
|
||||
|
||||
@@ -131,24 +131,6 @@
|
||||
// var reverseNumber = records - ((page - 1) * rowNum + i);
|
||||
$(this).setCell(rows[i], 'rowNum', number);
|
||||
}
|
||||
|
||||
// 승인 상태별 행 배경색: 요청됨(#fff3cd) / 진행중(#d1ecf1) 강조
|
||||
if (d && d.rows) {
|
||||
for (var j = 0; j < d.rows.length; j++) {
|
||||
var st = d.rows[j].approvalStatus || {};
|
||||
var code = st.code || '';
|
||||
var desc = st.description || '';
|
||||
var bg = '';
|
||||
if (code === 'REQUESTED' || desc === '요청됨') {
|
||||
bg = '#fff3cd';
|
||||
} else if (code === 'PROCESSING' || desc === '진행중') {
|
||||
bg = '#d1ecf1';
|
||||
}
|
||||
if (bg) {
|
||||
$('#grid tr#' + $.jgrid.jqID(d.rows[j].id)).css('background-color', bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
loadError: function(jqXHR, textStatus, errorThrown) {
|
||||
var location = '<%=request.getContextPath()%>/';
|
||||
@@ -194,7 +176,7 @@
|
||||
<div class="title">승인 요청 목록<span class="tooltip">승인 요청을 관리합니다.</span></div>
|
||||
<c:if test="${hardDeleteEnabled}">
|
||||
<div style="background:#fff3cd; border:1px solid #ffc107; padding:8px 15px; margin:5px 0; border-radius:4px; color:#856404;">
|
||||
<strong>[주의]</strong> 삭제 기능은 <strong>개발(dev) 환경에서만</strong> 동작합니다. 선택 삭제 시 승인 요청과 승인자 이력이 DB에서 영구 삭제됩니다.
|
||||
<strong>[주의]</strong> 선택 삭제 시 승인 요청과 승인자 이력이 DB에서 영구 삭제됩니다.
|
||||
</div>
|
||||
</c:if>
|
||||
<form id="ajaxForm" onsubmit="return false;">
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
function formatInquiryStatus(cellvalue, options, rowObject) {
|
||||
if (cellvalue == 'PENDING') {
|
||||
return '<span style="color: red;">문의중</span>';
|
||||
} else if (cellvalue == 'REVIEWING') {
|
||||
return '<span >문의검토중</span>'
|
||||
} else if (cellvalue == 'RESPONDED') {
|
||||
return '<span >답변완료</span>'
|
||||
} else if (cellvalue == 'CLOSED') {
|
||||
@@ -33,17 +31,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function formatVisibility(cellvalue, options, rowObject) {
|
||||
if (cellvalue == 'PRIVATE') {
|
||||
return '<span style="color:#c0392b; font-weight:bold;">비공개</span>';
|
||||
} else if (cellvalue == 'ALL') {
|
||||
return '전체공개';
|
||||
} else if (cellvalue == 'ORG') {
|
||||
return '법인공개';
|
||||
}
|
||||
return cellvalue;
|
||||
}
|
||||
|
||||
function formatFile(cellvalue, options, rowObject) {
|
||||
var iconPath = '${pageContext.request.contextPath}/images/icon_file.png';
|
||||
var icon = rowObject.hasAttachment ? '<img src="' + iconPath + '" alt="File Attached" style="vertical-align: middle; margin-left: 5px; width: 16px; height: 16px;">' : '';
|
||||
@@ -112,14 +99,13 @@
|
||||
mtype: 'POST',
|
||||
url: url,
|
||||
postData : { cmd : 'LIST' },
|
||||
colNames:['No.', 'id', '제목', '법인명', '상태', '공개범위', '작성자', '등록일', '답변자','답변일'],
|
||||
colNames:['No.', 'id', '제목', '법인명', '상태', '작성자', '등록일', '답변자','답변일'],
|
||||
colModel:[
|
||||
{ name : 'rowNum' , align:'center', width:50, sortable:false },
|
||||
{ name : 'id' , align:'center', key:true, hidden:true},
|
||||
{ name : 'inquirySubject' , align:'left' , width:200 , formatter: formatFile},
|
||||
{ name : 'orgName' , align:'center' , width:100 , },
|
||||
{ name : 'inquiryStatus' , align:'center', width:70, formatter: formatInquiryStatus },
|
||||
{ name : 'visibility' , align:'center', width:70, formatter: formatVisibility },
|
||||
{ name : 'inquirer.userName', align:'center', width:70 },
|
||||
{ name : 'createdDate' , align:'center', width:100, formatter: timeStampFormat },
|
||||
{ name : 'responderName' , align:'center', width:70 },
|
||||
@@ -221,7 +207,6 @@
|
||||
<select name="searchInquiryStatus">
|
||||
<option value="">전체</option>
|
||||
<option value="PENDING">문의중</option>
|
||||
<option value="REVIEWING">문의검토중</option>
|
||||
<option value="RESPONDED">답변완료</option>
|
||||
<option value="CLOSED">답변종료</option>
|
||||
</select>
|
||||
|
||||
@@ -79,46 +79,12 @@
|
||||
margin-left: 2px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.reason-modal-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
z-index: 1000;
|
||||
}
|
||||
.reason-modal-box {
|
||||
position: absolute;
|
||||
top: 50%; left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
width: 400px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.reason-modal-box h3 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.reason-modal-box textarea {
|
||||
width: 100%;
|
||||
min-height: 80px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.reason-modal-actions {
|
||||
margin-top: 12px;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
<script language="javascript">
|
||||
var url = '<c:url value="/onl/apim/portalinquiry/portalInquiryMan.json" />';
|
||||
var url_view = '<c:url value="/onl/apim/portalinquiry/portalInquiryMan.view" />';
|
||||
var file_download = '<c:url value="/file/download.do" />';
|
||||
var inquiryStatus = 'PENDING';
|
||||
var originalVisibility = 'ORG';
|
||||
var reasonModalCallback = null;
|
||||
|
||||
function decodeHTMLEntities(text) {
|
||||
var textArea = document.createElement('textarea');
|
||||
@@ -142,9 +108,7 @@
|
||||
|
||||
inquiryStatus = data.inquiryStatus;
|
||||
if (data.inquiryStatus == 'PENDING') {
|
||||
$("#inquiryStatus").text('문의중');
|
||||
} else if (data.inquiryStatus == 'REVIEWING') {
|
||||
$("#inquiryStatus").text('문의검토중');
|
||||
$("#inquiryStatus").text('문의중');
|
||||
} else if (data.inquiryStatus == 'RESPONDED') {
|
||||
$("#inquiryStatus").text('답변완료');
|
||||
} else if (data.inquiryStatus == 'CLOSED') {
|
||||
@@ -158,24 +122,6 @@
|
||||
var decodedContent = decodeHTMLEntities(data.responseDetail);
|
||||
$("#responseDetail").summernote('code', decodedContent || '');
|
||||
|
||||
// 공개범위 / 조회수
|
||||
$('#visibilitySelect').val(data.visibility || 'ORG');
|
||||
originalVisibility = data.visibility || 'ORG';
|
||||
$('#viewCount').text(data.viewCount || 0);
|
||||
|
||||
// 조회수 증가 (sessionStorage dedup — 새로고침 시 중복 증가 억제)
|
||||
var viewedKey = 'inquiry_viewed_' + key;
|
||||
if (!sessionStorage.getItem(viewedKey)) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: {cmd: 'INCREMENT_VIEW', id: key},
|
||||
success: function () {
|
||||
sessionStorage.setItem(viewedKey, 'true');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 댓글 표시
|
||||
listComment(key);
|
||||
|
||||
@@ -201,17 +147,8 @@
|
||||
if (!data || data.length === 0) return;
|
||||
$.each(data, function (i, comment) {
|
||||
var date = comment.createdDate ? timeStampFormat(comment.createdDate) : '';
|
||||
var isPrivate = comment.visibility === 'PRIVATE';
|
||||
var row = $('<div>').addClass('info-row');
|
||||
if (isPrivate) {
|
||||
// 비공개 댓글은 색상으로 구별
|
||||
row.css({'background-color': '#FFF5F5', 'border-radius': '4px', 'padding': '4px'});
|
||||
}
|
||||
var labelDiv = $('<div>').addClass('info-label').css('color', '#555').text(comment.writerName || '');
|
||||
if (isPrivate) {
|
||||
$('<span>').text(' 비공개').css({'color': '#c0392b', 'font-size': '0.85em', 'font-weight': 'bold'}).appendTo(labelDiv);
|
||||
}
|
||||
labelDiv.appendTo(row);
|
||||
$('<div>').addClass('info-label').css('color', '#555').text(comment.writerName || '').appendTo(row);
|
||||
var content = $('<div>').addClass('info-content');
|
||||
$('<div>').css('white-space', 'pre-wrap').text(comment.commentDetail).appendTo(content);
|
||||
var meta = $('<div>').css({'font-size': '0.9em', 'color': '#999', 'margin-top': '2px'});
|
||||
@@ -222,19 +159,6 @@
|
||||
})(comment.id, comment.inquiryId))
|
||||
.appendTo(meta);
|
||||
meta.appendTo(content);
|
||||
|
||||
// 댓글 공개범위 변경 컨트롤 (사유 필수)
|
||||
var visCtrl = $('<div>').css({'margin-top': '4px', 'font-size': '0.85em'});
|
||||
var sel = $('<select>').append('<option value="ALL">공개</option>').append('<option value="PRIVATE">비공개</option>');
|
||||
sel.val(comment.visibility || 'ALL');
|
||||
var reasonInput = $('<input>').attr({'type': 'text', 'placeholder': '변경 사유'}).css({'margin-left': '4px'});
|
||||
var applyBtn = $('<button>').attr('type', 'button').addClass('cssbtn smallBtn2').css({'margin-left': '4px', 'font-size': '0.85em', 'padding': '1px 6px'})
|
||||
.text('공개범위변경').on('click', (function(id, inquiryId, selEl, reasonEl) {
|
||||
return function() { changeCommentVisibility(id, inquiryId, selEl.val(), reasonEl.val()); };
|
||||
})(comment.id, comment.inquiryId, sel, reasonInput));
|
||||
visCtrl.append(sel).append(reasonInput).append(applyBtn);
|
||||
visCtrl.appendTo(content);
|
||||
|
||||
content.appendTo(row);
|
||||
row.appendTo($commentList);
|
||||
});
|
||||
@@ -245,84 +169,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
function openReasonModal(callback) {
|
||||
reasonModalCallback = callback;
|
||||
$('#reasonModalInput').val('');
|
||||
$('#reasonModal').show();
|
||||
$('#reasonModalInput').focus();
|
||||
}
|
||||
|
||||
function closeReasonModal() {
|
||||
$('#reasonModal').hide();
|
||||
reasonModalCallback = null;
|
||||
}
|
||||
|
||||
// 답변(summernote) 내용이 실제로 입력됐는지 확인
|
||||
function hasAnswerContent() {
|
||||
var v = $('#responseDetail').summernote('code');
|
||||
var text = $('<div>').html(v || '').text().replace(/ /g, ' ').trim();
|
||||
return text.length > 0;
|
||||
}
|
||||
|
||||
function saveInquiryAnswer(returnUrl) {
|
||||
var postData = $('#ajaxForm').serializeArray();
|
||||
postData.push({name: "cmd", value: "INSERT"});
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: postData,
|
||||
success: function (json) {
|
||||
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error: function (e) {
|
||||
alert(e.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 게시물 공개범위 변경(사유 필수). 성공 후 답변 내용이 있으면 이어서 저장.
|
||||
function changeInquiryVisibility(newVis, reason, returnUrl, thenSaveAnswer) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: {cmd: 'VISIBILITY', serviceType: 'APIGW', targetType: 'INQUIRY', id: $('#id').val(),
|
||||
visibility: newVis, auditReason: reason},
|
||||
success: function () {
|
||||
originalVisibility = newVis;
|
||||
if (thenSaveAnswer) {
|
||||
saveInquiryAnswer(returnUrl);
|
||||
} else {
|
||||
alert('변경되었습니다.');
|
||||
goNav(returnUrl);
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
alert(e.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function changeCommentVisibility(commentId, inquiryId, visibility, reason) {
|
||||
if (!reason || !reason.trim()) {
|
||||
alert('공개범위 변경 사유를 입력하세요.');
|
||||
return;
|
||||
}
|
||||
if (!confirm('댓글 공개범위를 변경하시겠습니까?')) return;
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: {cmd: 'VISIBILITY', serviceType: 'APIGW', targetType: 'COMMENT', id: commentId, visibility: visibility, auditReason: reason},
|
||||
success: function () {
|
||||
alert('변경되었습니다.');
|
||||
listComment(inquiryId);
|
||||
},
|
||||
error: function (e) {
|
||||
alert(e.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteComment(commentId, inquiryId) {
|
||||
if (inquiryStatus == 'CLOSED') {
|
||||
alert('답변이 종료되어 삭제할 수 없습니다');
|
||||
@@ -362,38 +208,24 @@
|
||||
alert('답변이 종료되어 수정할 수 없습니다');
|
||||
return;
|
||||
}
|
||||
|
||||
var newVis = $('#visibilitySelect').val();
|
||||
var visChanged = (newVis !== originalVisibility);
|
||||
|
||||
if (visChanged) {
|
||||
// 공개범위 변경 감지 → 사유 입력 모달 (답변 내용이 있으면 함께 저장)
|
||||
var saveAnswerToo = hasAnswerContent();
|
||||
openReasonModal(function (reason) {
|
||||
changeInquiryVisibility(newVis, reason, returnUrl, saveAnswerToo);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 공개범위 변경 없음 → 기존 답변 저장
|
||||
if (!checkRequired("ajaxForm")) return;
|
||||
if (!confirm("<%= localeMessage.getString("common.checkSave")%>")) return;
|
||||
saveInquiryAnswer(returnUrl);
|
||||
});
|
||||
|
||||
$("#reasonModalOk").click(function () {
|
||||
var reason = ($('#reasonModalInput').val() || '').trim();
|
||||
if (!reason) {
|
||||
alert('변경 사유를 입력하세요.');
|
||||
return;
|
||||
}
|
||||
var cb = reasonModalCallback;
|
||||
closeReasonModal();
|
||||
if (cb) cb(reason);
|
||||
});
|
||||
var postData = $('#ajaxForm').serializeArray();
|
||||
postData.push({name: "cmd", value: "INSERT"});
|
||||
|
||||
$("#reasonModalCancel").click(function () {
|
||||
closeReasonModal();
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: postData,
|
||||
success: function (json) {
|
||||
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error: function (e) {
|
||||
alert(e.responseText);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#btn_comment").click(function () {
|
||||
@@ -476,22 +308,7 @@
|
||||
<div class="info-label">작성일</div>
|
||||
<div id="createdDate" class="info-content"></div>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<div class="info-label">조회수</div>
|
||||
<div id="viewCount" class="info-content">0</div>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<div class="info-label">공개범위</div>
|
||||
<div class="info-content" style="display:flex; gap:8px; align-items:center;">
|
||||
<select id="visibilitySelect">
|
||||
<option value="ALL">전체공개</option>
|
||||
<option value="ORG">법인공개</option>
|
||||
<option value="PRIVATE">비공개</option>
|
||||
</select>
|
||||
<span style="font-size:0.85em; color:#999;">변경 후 상단 [수정] 버튼을 누르면 사유 입력창이 표시됩니다.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-row" id="attachFileRow" style="display: none;">
|
||||
<div class="info-row" id="attachFileRow" style="display: none;">
|
||||
<div class="info-label">첨부파일</div>
|
||||
<div id="attachFiles" class="info-content"></div>
|
||||
</div>
|
||||
@@ -539,17 +356,5 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 공개범위 변경 사유 입력 모달 -->
|
||||
<div id="reasonModal" class="reason-modal-overlay">
|
||||
<div class="reason-modal-box">
|
||||
<h3>공개범위 변경 사유</h3>
|
||||
<textarea id="reasonModalInput" placeholder="변경 사유를 입력하세요."></textarea>
|
||||
<div class="reason-modal-actions">
|
||||
<button type="button" class="cssbtn" id="reasonModalOk">확인</button>
|
||||
<button type="button" class="cssbtn" id="reasonModalCancel">취소</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -312,9 +312,7 @@ $(document).ready(function() {
|
||||
<div class="content_middle" id="content_middle">
|
||||
<div class="search_wrap">
|
||||
<button type="button" class="cssbtn" id="btn_new" level="W"><i class="material-icons">add</i> <%= localeMessage.getString("button.new") %></button>
|
||||
<c:if test="${hardDeleteEnabled}">
|
||||
<button type="button" class="cssbtn" id="btn_delete_selected" level="W" style="background-color: #dc3545; border-color: #dc3545; color: white;"><i class="material-icons">delete_forever</i> 선택 삭제</button>
|
||||
</c:if>
|
||||
<button type="button" class="cssbtn" id="btn_search" level="R"><i class="material-icons">search</i> <%= localeMessage.getString("button.search") %></button>
|
||||
</div>
|
||||
<%--법인정보관리--%>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
response.setHeader("Expires", "0");
|
||||
|
||||
MonitoringContext monitoringContext = (MonitoringContext)CommonUtil.getBean(request, "monitoringContext");
|
||||
String reverseProxyUrl = monitoringContext.getStringProperty(MonitoringContext.RMS_WEBHOOK_REVERSE_PROXY_URL, "");
|
||||
String reverseProxyUrl = monitoringContext.getStringProperty("djb.reverse_proxy.url", "");
|
||||
%>
|
||||
<%!
|
||||
public String getRequiredLabel(String label) {
|
||||
@@ -138,11 +138,7 @@
|
||||
$("#btn_delete").hide();
|
||||
}
|
||||
|
||||
$("select[name=approvalStatus]").val(portalOrgData.approvalStatus);
|
||||
// 승인상태는 읽기전용(수정 불가) - 값은 그대로 제출되도록 disabled 대신 잠금 처리
|
||||
$("select[name=approvalStatus]")
|
||||
.css({'pointer-events':'none', 'background-color':'#eee'})
|
||||
.attr('tabindex', '-1');
|
||||
$("#approvalStatus").val(portalOrgData.approvalStatus);
|
||||
$("#compRegNo").val(formatCompanyRegNo(portalOrgData.compRegNo));
|
||||
$("#corpRegNo").val(formatCorpRegNo(portalOrgData.corpRegNo));
|
||||
$("#createdDate").inputmask("9999-99-99 99:99:99", {'autoUnmask': true});
|
||||
@@ -484,7 +480,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 저장 확인/사유 입력은 유효성 검사 및 FormData 구성 후 처리 (하단 submit 분기)
|
||||
if (confirm("<%= localeMessage.getString("common.checkSave")%>") !== true)
|
||||
return;
|
||||
|
||||
// FormData 생성 전에 분리된 전화번호 필드 제거
|
||||
$("#scPhonePrefix, #scPhoneMiddle, #scPhoneLast, #orgPhonePrefix, #orgPhoneMiddle, #orgPhoneLast").removeAttr('name');
|
||||
@@ -519,47 +516,23 @@
|
||||
}
|
||||
|
||||
|
||||
// cmd 및 사유(auditReason) 첨부 후 전송
|
||||
function submitOrg(cmd, auditReason) {
|
||||
formData.append("cmd", cmd);
|
||||
// 감사로그(AUDIT_LOG) 발화를 위한 systemCode. 법인/가입자 리포지토리는 고정 EMS 스키마라 스키마 전환 영향 없음
|
||||
formData.append("serviceType", "APIGW");
|
||||
if (auditReason) {
|
||||
formData.append("auditReason", auditReason);
|
||||
// cmd 파라미터 추가
|
||||
formData.append("cmd", isDetail ? "UPDATE" : "INSERT");
|
||||
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url:url,
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success:function(json){
|
||||
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error:function(e){
|
||||
alert(e.responseText);
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url:url,
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success:function(json){
|
||||
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error:function(e){
|
||||
alert(e.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (isDetail) {
|
||||
// 수정: 상태를 REMOVED로 바꾼 경우 삭제(cmd=DELETE)로 감사 기록 + 익명화
|
||||
var targetCmd = ($("#orgStatus").val() === 'REMOVED') ? "DELETE" : "UPDATE";
|
||||
var isRemove = (targetCmd === "DELETE");
|
||||
showReasonPrompt(
|
||||
isRemove ? "해당 법인을 삭제(탈퇴) 처리합니다. 사유를 입력해 주세요." : "법인 정보를 수정합니다. 사유를 입력해 주세요.",
|
||||
{
|
||||
title: isRemove ? "삭제 사유" : "수정 사유",
|
||||
onConfirm: function(reason) { submitOrg(targetCmd, reason); }
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// 신규 등록: 사유 불필요
|
||||
if (confirm("<%= localeMessage.getString("common.checkSave")%>") !== true) return;
|
||||
submitOrg("INSERT", null);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#btn_previous").click(function() {
|
||||
@@ -568,28 +541,25 @@
|
||||
|
||||
$("#btn_delete").click(function(){
|
||||
|
||||
showReasonPrompt("해당 법인을 삭제 처리합니다. 사유를 입력해 주세요.", {
|
||||
title: "삭제 사유",
|
||||
onConfirm: function(reason) {
|
||||
var postData = $('#ajaxForm').serializeArray();
|
||||
postData.push({name: "cmd" , value:"DELETE"});
|
||||
postData.push({name: "serviceType", value: "APIGW"});
|
||||
postData.push({name: "auditReason", value: reason});
|
||||
if(confirm("<%= localeMessage.getString("common.confirmMsg")%>")){
|
||||
var postData = $('#ajaxForm').serializeArray();
|
||||
postData.push({name: "cmd" , value:"DELETE"});
|
||||
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url:url,
|
||||
data:postData,
|
||||
success:function(args){
|
||||
alert("<%= localeMessage.getString("common.deleteMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error:function(e){
|
||||
alert(e.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url:url,
|
||||
data:postData,
|
||||
success:function(args){
|
||||
alert("<%= localeMessage.getString("common.deleteMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error:function(e){
|
||||
alert(e.responseText);
|
||||
}
|
||||
});
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -347,11 +347,9 @@
|
||||
<button type="button" class="cssbtn" id="btn_new" level="W"><i
|
||||
class="material-icons">add</i> <%= localeMessage.getString("button.new") %>
|
||||
</button>
|
||||
<c:if test="${hardDeleteEnabled}">
|
||||
<button type="button" class="cssbtn" id="btn_delete_selected" level="W" style="background-color: #dc3545; border-color: #dc3545; color: white;"><i
|
||||
class="material-icons">delete_forever</i> 선택 삭제
|
||||
</button>
|
||||
</c:if>
|
||||
<button type="button" class="cssbtn" id="btn_search" level="R"><i
|
||||
class="material-icons">search</i> <%= localeMessage.getString("button.search") %>
|
||||
</button>
|
||||
|
||||
@@ -165,10 +165,6 @@
|
||||
$("#userStatus").val(data.userStatus);
|
||||
$("#roleCode").val(data.roleCode).trigger('change');
|
||||
$("#approvalStatus").val(data.approvalStatus);
|
||||
// 승인상태는 읽기전용(수정 불가) - 값은 그대로 제출되도록 disabled 대신 잠금 처리
|
||||
$("#approvalStatus")
|
||||
.css({'pointer-events':'none', 'background-color':'#eee'})
|
||||
.attr('tabindex', '-1');
|
||||
|
||||
// 탈퇴 상태 처리
|
||||
if (originalUserStatus === STATUS.REMOVED) {
|
||||
@@ -492,49 +488,29 @@
|
||||
formData.push({name: 'mobileNumber', value: mobileNumber});
|
||||
}
|
||||
|
||||
// cmd 및 사유(auditReason) 첨부 후 전송
|
||||
function submitUser(cmd, auditReason) {
|
||||
formData.push({ name: 'cmd', value: cmd });
|
||||
// 감사로그(AUDIT_LOG) 발화를 위한 systemCode. 가입자 리포지토리는 고정 EMS 스키마라 스키마 전환 영향 없음
|
||||
formData.push({ name: 'serviceType', value: 'APIGW' });
|
||||
if (auditReason) {
|
||||
formData.push({ name: 'auditReason', value: auditReason });
|
||||
formData.push({
|
||||
name: 'cmd',
|
||||
value: isDetail ? "UPDATE" : "INSERT"
|
||||
});
|
||||
|
||||
if (!confirm("<%= localeMessage.getString("common.checkSave")%>")) return;
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: formData,
|
||||
success: function (json) {
|
||||
if (json.status === "fail") {
|
||||
alert(json.errorMsg || "저장에 실패했습니다.");
|
||||
return;
|
||||
}
|
||||
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error: function (e) {
|
||||
alert(e.responseText);
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: formData,
|
||||
success: function (json) {
|
||||
if (json.status === "fail") {
|
||||
alert(json.errorMsg || "저장에 실패했습니다.");
|
||||
return;
|
||||
}
|
||||
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error: function (e) {
|
||||
alert(e.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (isDetail) {
|
||||
// 수정: 상태를 REMOVED로 바꾼 경우 삭제(cmd=DELETE)로 감사 기록 + 익명화
|
||||
var targetCmd = ($("#userStatus").val() === 'REMOVED') ? "DELETE" : "UPDATE";
|
||||
var isRemove = (targetCmd === "DELETE");
|
||||
showReasonPrompt(
|
||||
isRemove ? "해당 가입자를 삭제(탈퇴) 처리합니다. 사유를 입력해 주세요." : "가입자 정보를 수정합니다. 사유를 입력해 주세요.",
|
||||
{
|
||||
title: isRemove ? "삭제 사유" : "수정 사유",
|
||||
onConfirm: function(reason) { submitUser(targetCmd, reason); }
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// 신규 등록: 사유 불필요
|
||||
if (!confirm("<%= localeMessage.getString("common.checkSave")%>")) return;
|
||||
submitUser("INSERT", null);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#btn_previous").click(function () {
|
||||
@@ -542,26 +518,21 @@
|
||||
});
|
||||
|
||||
$("#btn_delete").click(function () {
|
||||
showReasonPrompt("해당 가입자를 삭제 처리합니다. 사유를 입력해 주세요.", {
|
||||
title: "삭제 사유",
|
||||
onConfirm: function(reason) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: {
|
||||
cmd: "DELETE",
|
||||
id: $('input[name=id]').val(),
|
||||
serviceType: "APIGW",
|
||||
auditReason: reason
|
||||
},
|
||||
success: function () {
|
||||
alert("<%= localeMessage.getString("common.deleteMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error: function (e) {
|
||||
alert(e.responseText);
|
||||
}
|
||||
});
|
||||
if (!confirm("<%= localeMessage.getString("common.confirmMsg")%>")) return;
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: {
|
||||
cmd: "DELETE",
|
||||
id: $('input[name=id]').val()
|
||||
},
|
||||
success: function () {
|
||||
alert("<%= localeMessage.getString("common.deleteMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error: function (e) {
|
||||
alert(e.responseText);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" %>
|
||||
<%@ page import="java.io.*" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
|
||||
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
||||
<%
|
||||
response.setHeader("Pragma", "No-cache");
|
||||
response.setHeader("Cache-Control", "no-cache");
|
||||
response.setHeader("Expires", "0");
|
||||
%>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<jsp:include page="/jsp/common/include/css.jsp"/>
|
||||
<jsp:include page="/jsp/common/include/script.jsp"/>
|
||||
<style>
|
||||
.url-cell { display:inline-block; max-width:380px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; vertical-align:middle; }
|
||||
.succ-y { color:#1a73e8; font-weight:bold; }
|
||||
.succ-n { color:#d93025; font-weight:bold; }
|
||||
</style>
|
||||
<script language="javascript">
|
||||
var url = '<c:url value="/onl/apim/webhook/webhookSendLogMan.json" />';
|
||||
var url_view = '<c:url value="/onl/apim/webhook/webhookSendLogMan.view" />';
|
||||
var combo;
|
||||
|
||||
function escapeHtmlJs(s) { return $('<div>').text(s == null ? '' : s).html(); }
|
||||
function escapeAttr(s) { return escapeHtmlJs(s).replace(/"/g, '"'); }
|
||||
|
||||
function formatTargetUrl(cellvalue, options, rowObject) {
|
||||
var v = cellvalue || '';
|
||||
return '<span class="url-cell" title="' + escapeAttr(v) + '">' + escapeHtmlJs(v) + '</span>';
|
||||
}
|
||||
|
||||
// 이벤트유형 코드 → 모니터링 공통코드(EVENT_TYPE) 코드명
|
||||
function formatEventType(cellvalue, options, rowObject) {
|
||||
if (!combo || !combo.eventTypeList) {
|
||||
return escapeHtmlJs(cellvalue);
|
||||
}
|
||||
for (var i = 0; i < combo.eventTypeList.length; i++) {
|
||||
if (combo.eventTypeList[i].CODE == cellvalue) {
|
||||
return escapeHtmlJs(combo.eventTypeList[i].NAME);
|
||||
}
|
||||
}
|
||||
return escapeHtmlJs(cellvalue);
|
||||
}
|
||||
|
||||
function formatSuccess(cellvalue, options, rowObject) {
|
||||
if (cellvalue === true) return '<span class="succ-y">성공</span>';
|
||||
if (cellvalue === false) return '<span class="succ-n">실패</span>';
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
function init() {
|
||||
|
||||
$("#startDatepicker").datepicker().inputmask("yyyy-mm-dd",{'autoUnmask':true});
|
||||
$("#endDatepicker").datepicker().inputmask("yyyy-mm-dd",{'autoUnmask':true});
|
||||
|
||||
var today = getToday();
|
||||
|
||||
$("input[name=searchStartYYYYMMDD]").val(today.substring(0,6)+"01");
|
||||
$("input[name=searchEndYYYYMMDD]").val(today);
|
||||
$("input[name=searchStartDate]").val(today.substring(0,6)+"01");
|
||||
$("input[name=searchEndDate]").val(today);
|
||||
|
||||
$.ajax({
|
||||
type: "POST", url: url, dataType: "json",
|
||||
data: {cmd: 'LIST_INIT_COMBO'},
|
||||
success: function (json) {
|
||||
combo = json;
|
||||
new makeOptions("CODE", "NAME").setObj($("select[name=searchEventType]"))
|
||||
.setNoValueInclude(true).setNoValue("", "<%=localeMessage.getString("combo.all")%>")
|
||||
.setData(json.eventTypeList).rendering();
|
||||
|
||||
// 뒤로가기 등으로 이전 검색조건 파라미터가 있으면 기본값을 덮어씀
|
||||
putSelectFromParam();
|
||||
|
||||
// 콤보(이벤트유형) 로드 후 그리드 생성 — formatEventType 경합 방지
|
||||
buildGrid();
|
||||
},
|
||||
error: function (e) { alert(e.responseText); }
|
||||
});
|
||||
}
|
||||
|
||||
function buildGrid() {
|
||||
$('#grid').jqGrid({
|
||||
datatype: "json",
|
||||
mtype: 'POST',
|
||||
url: url,
|
||||
postData: getSearchForJqgrid("cmd", "LIST"),
|
||||
colNames: ['id', 'No.', '기관명', '이벤트유형', 'Target URL', 'Proxy URL', 'Status', '성공여부', '발송서버', '발송일시'],
|
||||
colModel: [
|
||||
{name: 'id', align: 'center', key: true, hidden: true},
|
||||
{name: 'rowNum', align: 'center', width: 45, sortable: false},
|
||||
{name: 'orgName', align: 'left', width: 140},
|
||||
{name: 'eventType', align: 'center', width: 120, formatter: formatEventType},
|
||||
{name: 'targetUrl', align: 'left', width: 300, formatter: formatTargetUrl},
|
||||
{name: 'proxyUrl', align: 'left', width: 300, formatter: formatTargetUrl},
|
||||
{name: 'statusCode', align: 'center', width: 60},
|
||||
{name: 'success', align: 'center', width: 70, formatter: formatSuccess},
|
||||
{name: 'sendBy', align: 'center', width: 100},
|
||||
{name: 'sentAt', align: 'center', width: 140}
|
||||
],
|
||||
jsonReader: {repeatitems: false},
|
||||
pager: $('#pager'),
|
||||
page: '${param.page}',
|
||||
rowNum: '${rmsDefaultRowNum}',
|
||||
autoheight: true,
|
||||
height: $("#container").height(),
|
||||
autowidth: true,
|
||||
viewrecords: true,
|
||||
rowList: eval('[${rmsDefaultRowList}]'),
|
||||
ondblClickRow: function (rowId) {
|
||||
var rowData = $(this).getRowData(rowId);
|
||||
var id = rowData['id'];
|
||||
var url2 = url_view + '?cmd=DETAIL';
|
||||
url2 += '&page=' + $(this).getGridParam("page");
|
||||
url2 += '&returnUrl=' + getReturnUrl();
|
||||
url2 += '&menuId=' + '${param.menuId}';
|
||||
url2 += '&id=' + id;
|
||||
url2 += '&' + getSearchUrl();
|
||||
goNav(url2);
|
||||
},
|
||||
loadComplete: function () {
|
||||
var page = $(this).getGridParam('page');
|
||||
var rowNum = $(this).getGridParam('rowNum');
|
||||
var rows = $(this).getDataIDs();
|
||||
var colModel = $(this).getGridParam("colModel");
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var number = ((page - 1) * rowNum + i) + 1;
|
||||
$(this).setCell(rows[i], 'rowNum', number);
|
||||
}
|
||||
// 서버 고정 정렬(등록일시 역순) — 컬럼 정렬 비활성
|
||||
for (var i = 0; i < colModel.length; i++) {
|
||||
$(this).setColProp(colModel[i].name, {sortable: false});
|
||||
}
|
||||
},
|
||||
loadError: function (jqXHR, textStatus, errorThrown) {
|
||||
var location = '<%=request.getContextPath()%>/';
|
||||
comloadError(jqXHR, textStatus, errorThrown, location);
|
||||
}
|
||||
});
|
||||
resizeJqGridWidth('grid', 'content_middle', '1000');
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
init();
|
||||
|
||||
$("#btn_search").click(function () {
|
||||
var start = $("input[name=searchStartYYYYMMDD]").val().replace(/-/gi, "");
|
||||
var end = $("input[name=searchEndYYYYMMDD]").val().replace(/-/gi, "");
|
||||
|
||||
if (start && start > getToday()) {
|
||||
alert("시작일이 오늘 이후입니다. 시작일을 확인해주세요.");
|
||||
$("input[name=searchStartYYYYMMDD]").focus();
|
||||
return false;
|
||||
}
|
||||
if (start && end && start > end) {
|
||||
alert("조회기간 종료일은 시작일보다 커야합니다.");
|
||||
$("input[name=searchEndYYYYMMDD]").focus();
|
||||
return false;
|
||||
}
|
||||
$("input[name=searchStartDate]").val(start);
|
||||
$("input[name=searchEndDate]").val(end);
|
||||
|
||||
var postData = getSearchForJqgrid("cmd", "LIST");
|
||||
$("#grid").setGridParam({url: url, postData: postData, page: 1}).trigger("reloadGrid");
|
||||
});
|
||||
|
||||
$("select[name^=search]").change(function () { $("#btn_search").click(); });
|
||||
$("input[name^=search]").keydown(function (key) {
|
||||
if (key.keyCode == 13) { $("#btn_search").click(); }
|
||||
});
|
||||
|
||||
|
||||
|
||||
buttonControl();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="right_box">
|
||||
<div class="content_top">
|
||||
<ul class="path"><li><a href="#">${rmsMenuPath}</a></li></ul>
|
||||
</div><!-- end content_top -->
|
||||
<div class="content_middle" id="content_middle">
|
||||
<div class="search_wrap">
|
||||
<button type="button" class="cssbtn" id="btn_search" level="R"><i class="material-icons">search</i> <%= localeMessage.getString("button.search") %></button>
|
||||
</div>
|
||||
<div class="title">웹훅 발송 로그<span class="tooltip">외부로 발송된 웹훅 이력을 조회합니다.</span></div>
|
||||
<form id="ajaxForm" onsubmit="return false;">
|
||||
<table class="search_condition" cellspacing=0;>
|
||||
<colgroup>
|
||||
<col style="width:120px;"><col style="width:200px;">
|
||||
<col style="width:120px;"><col style="width:200px;">
|
||||
<col style="width:120px;"><col style="width:200px;">
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>기관명</th>
|
||||
<td><input type="text" name="searchOrgName" autocomplete="off"></td>
|
||||
<th>이벤트유형</th>
|
||||
<td>
|
||||
<div class="select-style">
|
||||
<select name="searchEventType"></select>
|
||||
</div>
|
||||
</td>
|
||||
<th>성공여부</th>
|
||||
<td>
|
||||
<div class="select-style">
|
||||
<select name="searchSuccess">
|
||||
<option value="">전체</option>
|
||||
<option value="Y">성공</option>
|
||||
<option value="N">실패</option>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Target URL</th>
|
||||
<td><input type="text" name="searchTargetUrl" autocomplete="off" style="width:95%;"></td>
|
||||
<th>발송기간</th>
|
||||
<td>
|
||||
<input type="text" name="searchStartYYYYMMDD" id="startDatepicker" readonly="readonly" value="" size="10" style="width:40%; border:1px solid #ebebec;">
|
||||
~
|
||||
<input type="text" name="searchEndYYYYMMDD" value="" id="endDatepicker" size="10" readonly="readonly" style="width:40%; border:1px solid #ebebec;">
|
||||
<input type="hidden" name="searchStartDate" value="">
|
||||
<input type="hidden" name="searchEndDate" value="">
|
||||
</td>
|
||||
<th></th>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
<table id="grid"></table>
|
||||
<div id="pager"></div>
|
||||
</div><!-- end content_middle -->
|
||||
</div><!-- end right_box -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,137 +0,0 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" %>
|
||||
<%@ page import="java.io.*" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
|
||||
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
||||
<%
|
||||
response.setHeader("Pragma", "No-cache");
|
||||
response.setHeader("Cache-Control", "no-cache");
|
||||
response.setHeader("Expires", "0");
|
||||
%>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<jsp:include page="/jsp/common/include/css.jsp"/>
|
||||
<jsp:include page="/jsp/common/include/script.jsp"/>
|
||||
<style>
|
||||
.succ-y { color:#1a73e8; font-weight:bold; }
|
||||
.succ-n { color:#d93025; font-weight:bold; }
|
||||
.pre-wrap { white-space:pre-wrap; word-break:break-all; min-height:60px; line-height:1.5; }
|
||||
</style>
|
||||
<script language="javascript">
|
||||
var url = '<c:url value="/onl/apim/webhook/webhookSendLogMan.json" />';
|
||||
var url_view = '<c:url value="/onl/apim/webhook/webhookSendLogMan.view" />';
|
||||
var key = '${param.id}';
|
||||
|
||||
function escapeHtmlJs(s) { return $('<div>').text(s == null ? '' : s).html(); }
|
||||
|
||||
function detail() {
|
||||
if (!key) return;
|
||||
$.ajax({
|
||||
type: "POST", url: url, dataType: "json",
|
||||
data: {cmd: 'DETAIL', id: key},
|
||||
success: function (data) {
|
||||
$('#id').text(data.id != null ? data.id : '');
|
||||
$('#orgName').text(data.orgName || '');
|
||||
$('#eventType').text(data.eventTypeName || data.eventType || '')
|
||||
.attr('title', data.eventType || '');
|
||||
$('#targetUrl').text(data.targetUrl || '');
|
||||
$('#proxyUrl').text(data.proxyUrl || '');
|
||||
$('#statusCode').text(data.statusCode != null ? data.statusCode : '');
|
||||
$('#retryCount').text(data.retryCount != null ? data.retryCount : '');
|
||||
$('#sendBy').text(data.sendBy || '');
|
||||
$('#sentAt').text(data.sentAt || '');
|
||||
$('#signature').text(data.signature || '');
|
||||
$('#errorMessage').text(data.errorMessage || '');
|
||||
$('#payload').text(data.payload || '');
|
||||
$('#responseBody').text(data.responseBody || '');
|
||||
|
||||
if (data.success === true) {
|
||||
$('#success').html('<span class="succ-y">성공</span>');
|
||||
} else if (data.success === false) {
|
||||
$('#success').html('<span class="succ-n">실패</span>');
|
||||
} else {
|
||||
$('#success').text('');
|
||||
}
|
||||
},
|
||||
error: function (e) { alert(e.responseText); }
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
var returnUrl = getReturnUrlForReturn();
|
||||
|
||||
buttonControl();
|
||||
detail();
|
||||
|
||||
$('#btn_previous').click(function () { goNav(returnUrl); });
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="right_box">
|
||||
<div class="content_top">
|
||||
<ul class="path"><li><a href="#">${rmsMenuPath}</a></li></ul>
|
||||
</div>
|
||||
<div class="content_middle">
|
||||
<div class="search_wrap">
|
||||
<button type="button" class="cssbtn" id="btn_previous" level="R" status="DETAIL,NEW"><i class="material-icons">arrow_back</i> <%= localeMessage.getString("button.previous") %></button>
|
||||
</div>
|
||||
<div class="title" id="title">웹훅 발송 로그 상세</div>
|
||||
<table class="table_row" cellspacing="0">
|
||||
<colgroup>
|
||||
<col style="width:12%"/><col style="width:38%"/>
|
||||
<col style="width:12%"/><col style="width:38%"/>
|
||||
</colgroup>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<td><span id="id"></span></td>
|
||||
<th>기관명</th>
|
||||
<td><span id="orgName"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>이벤트유형</th>
|
||||
<td><span id="eventType"></span></td>
|
||||
<th>Status Code</th>
|
||||
<td><span id="statusCode"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Target URL</th>
|
||||
<td><span id="targetUrl"></span></td>
|
||||
<th>Proxy URL</th>
|
||||
<td><span id="proxyUrl"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>성공여부</th>
|
||||
<td><span id="success"></span></td>
|
||||
<th>재시도횟수</th>
|
||||
<td><span id="retryCount"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>발송서버</th>
|
||||
<td><span id="sendBy"></span></td>
|
||||
<th>발송일시</th>
|
||||
<td><span id="sentAt"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Signature</th>
|
||||
<td colspan="3"><span id="signature"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Payload</th>
|
||||
<td colspan="3"><div id="payload" class="pre-wrap"></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Response Body</th>
|
||||
<td colspan="3"><div id="responseBody" class="pre-wrap"></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>에러 메세지</th>
|
||||
<td colspan="3"><div id="errorMessage" class="pre-wrap"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -525,26 +525,35 @@
|
||||
$("input[name=searchStartDate], input[name=searchEndDate]").inputmask("9999-99-99", { 'autoUnmask': true });
|
||||
$("input[name=searchStartTime], input[name=searchEndTime]").inputmask("99:99", { 'autoUnmask': true });
|
||||
|
||||
// 기본값 설정 (현재 시간(분) 기준 1시간 전 ~ 현재 시간(분))
|
||||
// 기본값 설정 (현재 시간 기준 1시간 전 정각 ~ 현재 정각)
|
||||
var now = new Date();
|
||||
var oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000);
|
||||
var endHour = now.getHours();
|
||||
var startHour = endHour - 1;
|
||||
var startDate, endDate;
|
||||
|
||||
function formatDate(d) {
|
||||
return d.getFullYear() + '-' +
|
||||
String(d.getMonth() + 1).padStart(2, '0') + '-' +
|
||||
String(d.getDate()).padStart(2, '0');
|
||||
}
|
||||
function formatTime(d) {
|
||||
return String(d.getHours()).padStart(2, '0') + ':' + String(d.getMinutes()).padStart(2, '0');
|
||||
if (startHour < 0) {
|
||||
startHour = 23;
|
||||
var yesterday = new Date(now);
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
startDate = yesterday.getFullYear() + '-' +
|
||||
String(yesterday.getMonth() + 1).padStart(2, '0') + '-' +
|
||||
String(yesterday.getDate()).padStart(2, '0');
|
||||
endDate = now.getFullYear() + '-' +
|
||||
String(now.getMonth() + 1).padStart(2, '0') + '-' +
|
||||
String(now.getDate()).padStart(2, '0');
|
||||
} else {
|
||||
var today = getToday();
|
||||
startDate = today;
|
||||
endDate = today;
|
||||
}
|
||||
|
||||
if (!$("input[name=searchStartDate]").val()) {
|
||||
$("input[name=searchStartDate]").val(formatDate(oneHourAgo));
|
||||
$("input[name=searchStartTime]").val(formatTime(oneHourAgo));
|
||||
$("input[name=searchStartDate]").val(startDate);
|
||||
$("input[name=searchStartTime]").val(String(startHour).padStart(2, '0') + ':00');
|
||||
}
|
||||
if (!$("input[name=searchEndDate]").val()) {
|
||||
$("input[name=searchEndDate]").val(formatDate(now));
|
||||
$("input[name=searchEndTime]").val(formatTime(now));
|
||||
$("input[name=searchEndDate]").val(endDate);
|
||||
$("input[name=searchEndTime]").val(String(endHour).padStart(2, '0') + ':00');
|
||||
}
|
||||
|
||||
initCharts();
|
||||
|
||||
@@ -77,10 +77,7 @@
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* iframe 모달(showModal) 콘텐츠 패딩 제거 — iframe 이 다이얼로그 폭을 최대한 사용해 내부 가로스크롤 방지 */
|
||||
.ui-dialog .ui-dialog-content { padding: 0 !important; }
|
||||
|
||||
|
||||
</style>
|
||||
<script language="javascript" >
|
||||
var isDetail = false;
|
||||
@@ -490,7 +487,6 @@
|
||||
}
|
||||
|
||||
if(data.errResponseTransform != null && data.errResponseTransform != '' && data.errTransformYn == 'Y') {
|
||||
$('#toggleTransformYn').bootstrapToggle('on');
|
||||
$('#toggleErrTransformYn').bootstrapToggle('on');
|
||||
$('#rowErrResponseTransform').show();
|
||||
} else {
|
||||
@@ -1015,12 +1011,7 @@
|
||||
window.open(urlAddServiceType(baseUrl + '&menuId=' + encodeURIComponent(getMenuId())), '_blank');
|
||||
} else {
|
||||
// 기본: 모달 + iframe. showModal 이 serviceType/menuId/pop 을 자동 부착.
|
||||
// 콘텐츠 고정폭 1600 + 다이얼로그 chrome(패딩/보더 ~40px) 때문에 iframe 내부폭이 1600 미만이면 가로스크롤 발생.
|
||||
// 뷰포트 내에서 최대한 크게 열어(캡 1720) iframe 내부폭이 1600 이상 확보되게 한다.
|
||||
var vw = $(window).width(), vh = $(window).height();
|
||||
var modalW = Math.min(vw - 12, 1720);
|
||||
var modalH = Math.min(vh - 20, 900);
|
||||
showModal(baseUrl, { title: 'OpenAPI Spec' }, modalW, modalH);
|
||||
showModal(baseUrl, { title: 'OpenAPI Spec' }, 1600, 880);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1545,7 +1536,7 @@
|
||||
<button type="button" class="cssbtn" id="btn_delete" level="W" status="DETAIL"><i class="material-icons">delete</i> <%= localeMessage.getString("button.delete") %></button>
|
||||
<button type="button" class="cssbtn" id="btn_modify" level="R" status="DETAIL,NEW"><i class="material-icons">save</i> <%= localeMessage.getString("button.modify") %></button>
|
||||
<!-- v1: 기존 API 스펙 (모달) — 기능 비교용 복원 -->
|
||||
<button type="button" class="cssbtn" id="btn_api_spec" level="R" status="DETAIL,NEW"><i class="material-icons">description</i> API 스펙(삭제예정)</button>
|
||||
<button type="button" class="cssbtn" id="btn_api_spec" level="R" status="DETAIL,NEW"><i class="material-icons">description</i> API 스펙</button>
|
||||
<!-- v2: 신규 OpenAPI Spec (새 탭) -->
|
||||
<button type="button" class="cssbtn" id="btn_openapi_spec" level="R" status="DETAIL,NEW"><i class="material-icons">api</i> OpenAPI Spec</button>
|
||||
<button type="button" class="cssbtn" id="btn_previous" level="R" status="DETAIL,NEW"><i class="material-icons">arrow_back</i> <%= localeMessage.getString("button.previous") %></button>
|
||||
|
||||
+81
-81
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'java-library'
|
||||
id 'eclipse'
|
||||
id 'eclipse-wtp'
|
||||
id 'eclipse-wtp'
|
||||
id 'idea'
|
||||
id 'war'
|
||||
}
|
||||
@@ -31,11 +31,11 @@ allprojects {
|
||||
project.webAppDirName = 'WebContent'
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(8)
|
||||
}
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(8)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
@@ -45,52 +45,56 @@ sourceSets {
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.encoding = 'UTF-8'
|
||||
options.compilerArgs = ['-parameters']
|
||||
options.generatedSourceOutputDirectory = project.file(generatedJavaDir)
|
||||
options.encoding = 'UTF-8'
|
||||
options.compilerArgs = ['-parameters']
|
||||
options.generatedSourceOutputDirectory = project.file(generatedJavaDir)
|
||||
}
|
||||
|
||||
war {
|
||||
def profile = project.findProperty("profile") ?: "tomcat"
|
||||
|
||||
if (profile == "weblogic") {
|
||||
webXml = file("WebContent/WEB-INF/weblogic-web.xml")
|
||||
exclude 'WEB-INF/web.xml'
|
||||
}
|
||||
|
||||
|
||||
// rootSpec.exclude '**/persistence.xml'
|
||||
exclude '**/context.xml'
|
||||
exclude '**/context-*.xml'
|
||||
archiveFileName = "eapim-admin.war"
|
||||
duplicatesStrategy = DuplicatesStrategy.WARN
|
||||
def profile = project.findProperty("profile") ?: "tomcat"
|
||||
|
||||
if (profile == "weblogic") {
|
||||
webXml = file("WebContent/WEB-INF/weblogic-web.xml")ㅇ
|
||||
exclude 'WEB-INF/web.xml'
|
||||
}
|
||||
|
||||
|
||||
// rootSpec.exclude '**/persistence.xml'
|
||||
exclude '**/context.xml'
|
||||
exclude '**/context-*.xml'
|
||||
archiveFileName = "eapim-admin.war"
|
||||
duplicatesStrategy = DuplicatesStrategy.WARN
|
||||
}
|
||||
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.encoding = 'UTF-8'
|
||||
options.compilerArgs += ['-parameters', "-Xlint:unchecked", "-Xlint:deprecation"]
|
||||
options.encoding = 'UTF-8'
|
||||
options.compilerArgs += ['-parameters', "-Xlint:unchecked", "-Xlint:deprecation"]
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
|
||||
annotationProcessor "org.projectlombok:lombok:1.18.28", "org.projectlombok:lombok-mapstruct-binding:0.2.0", "org.mapstruct:mapstruct-processor:1.5.5.Final"
|
||||
annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jpa", "jakarta.persistence:jakarta.persistence-api:2.2.3", "jakarta.annotation:jakarta.annotation-api:1.3.5"
|
||||
|
||||
|
||||
annotationProcessor "org.projectlombok:lombok:1.18.28",
|
||||
"org.projectlombok:lombok-mapstruct-binding:0.2.0",
|
||||
"org.mapstruct:mapstruct-processor:1.5.5.Final"
|
||||
annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jpa",
|
||||
"jakarta.persistence:jakarta.persistence-api:2.2.3",
|
||||
"jakarta.annotation:jakarta.annotation-api:1.3.5"
|
||||
|
||||
implementation project(':elink-online-core')
|
||||
implementation project(':elink-online-transformer')
|
||||
implementation project(':elink-online-common')
|
||||
implementation project(':elink-online-emsclient')
|
||||
implementation project(':elink-portal-common')
|
||||
//implementation project(':kjb-safedb')
|
||||
//implementation project(":eapim-admin-djb")
|
||||
implementation project(':elink-online-emsclient')
|
||||
implementation project(':elink-portal-common')
|
||||
//implementation project(':kjb-safedb')
|
||||
implementation project(":eapim-admin-djb")
|
||||
|
||||
/* Custom Libs (damo-manager.jar 는 Tomcat lib 가 런타임 제공 → compileOnly, WAR 미포함) */
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'], exclude: ['damo-manager.jar'])
|
||||
compileOnly files('libs/damo-manager.jar')
|
||||
|
||||
//implementation "org.dom4j:dom4j:2.1.3"
|
||||
//implementation "org.dom4j:dom4j:2.1.3"
|
||||
//implementation "com.rabbitmq:amqp-client:3.6.6"
|
||||
|
||||
implementation "commons-primitives:commons-primitives:1.0"
|
||||
@@ -112,10 +116,10 @@ dependencies {
|
||||
|
||||
// https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api
|
||||
compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1'
|
||||
|
||||
|
||||
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.13.1'
|
||||
//implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-xml', version: '2.13.1'
|
||||
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.1'
|
||||
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.1'
|
||||
|
||||
implementation "javax.jms:javax.jms-api:2.0"
|
||||
implementation "org.snmp4j:snmp4j:1.10.1"
|
||||
@@ -182,32 +186,32 @@ dependencies {
|
||||
implementation 'ch.qos.logback:logback-classic:1.2.10'
|
||||
implementation 'ch.qos.logback:logback-access:1.2.10'
|
||||
implementation 'ch.qos.logback:logback-core:1.2.10'
|
||||
|
||||
implementation files("libs/eai-bap-client.jar")
|
||||
|
||||
compileOnly 'javax.xml.bind:jaxb-api:2.3.1'
|
||||
|
||||
//implementation 'org.postgresql:postgresql:42.2.23'
|
||||
|
||||
implementation 'backport-util-concurrent:backport-util-concurrent:3.0'
|
||||
|
||||
implementation ('software.amazon.awssdk:s3:2.20.142') {
|
||||
exclude group: 'org.slf4j', module: 'slf4j-api'
|
||||
exclude group: 'org.slf4j', module: 'logback-classic'
|
||||
}
|
||||
implementation 'software.amazon.awssdk:sso:2.20.142'
|
||||
implementation 'software.amazon.awssdk:sts:2.20.142'
|
||||
|
||||
implementation group: 'commons-net', name: 'commons-net', version: '3.5'
|
||||
implementation files("libs/eai-bap-client.jar")
|
||||
|
||||
// JDK 8 의 rt.jar 에는 org.w3c.dom.ElementTraversal 이 없어 xercesImpl 가 NCDFE 를 일으킴.
|
||||
// xml-apis 1.4.01 에 그 클래스가 포함됨. 직접 의존성으로 묶어 WAR 에 패키징되도록 함.
|
||||
implementation 'xml-apis:xml-apis:1.4.01'
|
||||
compileOnly 'javax.xml.bind:jaxb-api:2.3.1'
|
||||
|
||||
testRuntimeOnly 'com.h2database:h2:2.1.214'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test:2.6.15'
|
||||
//implementation 'org.postgresql:postgresql:42.2.23'
|
||||
|
||||
implementation 'backport-util-concurrent:backport-util-concurrent:3.0'
|
||||
|
||||
implementation ('software.amazon.awssdk:s3:2.20.142') {
|
||||
exclude group: 'org.slf4j', module: 'slf4j-api'
|
||||
exclude group: 'org.slf4j', module: 'logback-classic'
|
||||
}
|
||||
implementation 'software.amazon.awssdk:sso:2.20.142'
|
||||
implementation 'software.amazon.awssdk:sts:2.20.142'
|
||||
|
||||
implementation group: 'commons-net', name: 'commons-net', version: '3.5'
|
||||
|
||||
// JDK 8 의 rt.jar 에는 org.w3c.dom.ElementTraversal 이 없어 xercesImpl 가 NCDFE 를 일으킴.
|
||||
// xml-apis 1.4.01 에 그 클래스가 포함됨. 직접 의존성으로 묶어 WAR 에 패키징되도록 함.
|
||||
implementation 'xml-apis:xml-apis:1.4.01'
|
||||
|
||||
testRuntimeOnly 'com.h2database:h2:2.1.214'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test:2.6.15'
|
||||
}
|
||||
|
||||
test {
|
||||
@@ -215,9 +219,9 @@ test {
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
exclude group: 'log4j', module: 'log4j'
|
||||
exclude group: 'org.apache.activemq'
|
||||
exclude group: 'org.codehaus.jackson'
|
||||
exclude group: 'log4j', module: 'log4j'
|
||||
exclude group: 'org.apache.activemq'
|
||||
exclude group: 'org.codehaus.jackson'
|
||||
resolutionStrategy {
|
||||
// 10 minute cache of dynamic version navigation
|
||||
cacheDynamicVersionsFor 10, 'minutes'
|
||||
@@ -241,29 +245,25 @@ task settingEclipseEncoding {
|
||||
}
|
||||
|
||||
task initDirs() {
|
||||
file(generatedJavaDir).mkdirs()
|
||||
file(generatedJavaDir).mkdirs()
|
||||
}
|
||||
|
||||
eclipse {
|
||||
wtp {
|
||||
component {
|
||||
contextPath = 'monitoring'
|
||||
}
|
||||
}
|
||||
synchronizationTasks settingEclipseEncoding, initDirs
|
||||
jdt {
|
||||
// apt {
|
||||
// // generated 된 패스 경로를 .setting/org.eclipse.jdt.apt.core.prefs 의 org.eclipse.jdt.apt.genSrcDir에 적용한다.
|
||||
// // project > properties > Java Compiler > Annoation Processing 화면에서 확인 가능하다.
|
||||
// genSrcDir = file(generatedJavaDir)
|
||||
// }
|
||||
}
|
||||
project {
|
||||
if (!natures.contains('org.eclipse.buildship.core.gradleprojectnature')) {
|
||||
natures.add('org.eclipse.buildship.core.gradleprojectnature')
|
||||
buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
|
||||
}
|
||||
}
|
||||
wtp {
|
||||
component {
|
||||
contextPath = 'monitoring'
|
||||
}
|
||||
}
|
||||
synchronizationTasks settingEclipseEncoding, initDirs
|
||||
jdt {
|
||||
|
||||
}
|
||||
project {
|
||||
if (!natures.contains('org.eclipse.buildship.core.gradleprojectnature')) {
|
||||
natures.add('org.eclipse.buildship.core.gradleprojectnature')
|
||||
buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ include 'elink-online-common'
|
||||
include 'elink-online-emsclient'
|
||||
include 'elink-portal-common'
|
||||
//include 'kjb-safedb'
|
||||
//include 'eapim-admin-djb'
|
||||
include 'eapim-admin-djb'
|
||||
|
||||
project (':elink-online-core-jpa').projectDir = new File(settingsDir, "../eapim-online/elink-online-core-jpa")
|
||||
project (':elink-online-core').projectDir = new File(settingsDir, "../eapim-online/elink-online-core")
|
||||
@@ -16,4 +16,4 @@ project (':elink-online-common').projectDir = new File(settingsDir, "../eapim-on
|
||||
project (':elink-online-emsclient').projectDir = new File(settingsDir, "../eapim-online/elink-online-emsclient")
|
||||
project (':elink-portal-common').projectDir = new File(settingsDir, "../elink-portal-common")
|
||||
//project (':kjb-safedb').projectDir = new File(settingsDir, "../kjb-safedb")
|
||||
//project (':eapim-admin-djb').projectDir = new File(settingsDir, "../eapim-admin-djb")
|
||||
project (':eapim-admin-djb').projectDir = new File(settingsDir, "../eapim-admin-djb")
|
||||
+1
-3
@@ -41,12 +41,10 @@ public class AuditLogInterceptor implements HandlerInterceptor {
|
||||
|
||||
if (isAuditableUsecase.isAuditable(userId, command, logType, systemCode)) {
|
||||
String parameters = getParametersAsString(request);
|
||||
String message = request.getParameter("auditReason");
|
||||
log
|
||||
.debug("audit log save : logType={}, cmd={}, user={}, parameters={}", logType, command,
|
||||
userId, parameters);
|
||||
saveAuditLogUseCase
|
||||
.log(systemCode, logType, command, remoteAddress, userId, parameters, message);
|
||||
saveAuditLogUseCase.log(systemCode, logType, command, remoteAddress, userId, parameters);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ public class AuditLog {
|
||||
|
||||
private String logTypeText;
|
||||
|
||||
private String message;
|
||||
|
||||
private String parameters;
|
||||
|
||||
private LocalDateTime lastModifiedDate;
|
||||
|
||||
@@ -3,6 +3,6 @@ package com.eactive.eai.rms.common.acl.audit.port.in;
|
||||
public interface SaveAuditLogUseCase {
|
||||
|
||||
public void log(String systemCode, String logType, String command, String remoteAddress, String userId,
|
||||
String parameters, String message);
|
||||
String parameters);
|
||||
|
||||
}
|
||||
|
||||
@@ -59,16 +59,15 @@ class AuditLogService
|
||||
|
||||
@Override
|
||||
public void log(String systemCode, String logType, String command, String remoteAddress, String userId,
|
||||
String parameters, String message) {
|
||||
String parameters) {
|
||||
|
||||
AuditLog auditLog = new AuditLog(systemCode, logType, command, userId, remoteAddress);
|
||||
String auditPointKey = AuditPoint.generateKey(logType, systemCode, command);
|
||||
AuditPoint auditPoint = auditPoints.get(auditPointKey);
|
||||
|
||||
|
||||
auditLog.setLogTypeText(auditPoint.getLogTypeText());
|
||||
auditLog.setLastModifiedDate(LocalDateTime.now());
|
||||
auditLog.setParameters(parameters);
|
||||
auditLog.setMessage(message);
|
||||
|
||||
saveAuditLogPort.save(auditLog);
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.eactive.eai.rms.common.acl.sitemap;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import com.eactive.eai.rms.common.base.BaseAnnotationController;
|
||||
|
||||
@Controller
|
||||
@RequiredArgsConstructor
|
||||
public class SitemapController extends BaseAnnotationController {
|
||||
|
||||
private final SitemapService sitemapService;
|
||||
|
||||
@GetMapping(value = "/common/acl/sitemap/sitemapMan.view")
|
||||
public String view(@RequestParam(value = "serviceType", required = false) String serviceType, Model model) {
|
||||
model.addAttribute("sitemapTree", sitemapService.getSitemapTree(serviceType));
|
||||
return "/common/acl/sitemap/sitemapMan";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.eactive.eai.rms.common.acl.sitemap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.eactive.eai.rms.common.acl.sitemap.ui.SitemapNode;
|
||||
|
||||
public interface SitemapService {
|
||||
|
||||
public List<SitemapNode> getSitemapTree(String serviceType);
|
||||
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package com.eactive.eai.rms.common.acl.sitemap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.eactive.eai.rms.common.acl.sitemap.ui.SitemapNode;
|
||||
import com.eactive.eai.rms.common.base.BaseService;
|
||||
import com.eactive.eai.rms.data.entity.man.menu.Menu;
|
||||
import com.eactive.eai.rms.data.entity.man.menu.MenuService;
|
||||
import com.eactive.eai.rms.data.entity.man.role.RoleMenuAuthService;
|
||||
|
||||
@Service("sitemapService")
|
||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||
public class SitemapServiceImpl extends BaseService implements SitemapService {
|
||||
|
||||
@Autowired
|
||||
private MenuService menuService;
|
||||
|
||||
@Autowired
|
||||
private RoleMenuAuthService roleMenuAuthService;
|
||||
|
||||
public List<SitemapNode> getSitemapTree(String serviceType) {
|
||||
Menu root = menuService.getById("ROOT_DEV");
|
||||
Menu langRoot = findLangRoot(root);
|
||||
List<SitemapNode> tree = new ArrayList<>();
|
||||
if (langRoot == null) {
|
||||
return tree;
|
||||
}
|
||||
|
||||
Set<String> serviceTypeMenuIds = StringUtils.isBlank(serviceType)
|
||||
? null
|
||||
: new HashSet<>(roleMenuAuthService.findMenuIdsByServiceType(serviceType));
|
||||
|
||||
for (Menu menu : sortedChildren(langRoot)) {
|
||||
if (isVisible(menu) && matchesServiceType(menu, serviceTypeMenuIds)) {
|
||||
tree.add(buildNode(menu, serviceTypeMenuIds));
|
||||
}
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
|
||||
// 엔티티의 childMenus는 menuId 기준으로 정렬되어 있어, 실제 메뉴(운영화면 GNB)와 동일하게 sortOrder 기준으로 재정렬한다.
|
||||
private List<Menu> sortedChildren(Menu menu) {
|
||||
List<Menu> children = new ArrayList<>(menu.getChildMenus());
|
||||
children.sort(Comparator.comparing(Menu::getSortOrder, Comparator.nullsLast(Comparator.naturalOrder())));
|
||||
return children;
|
||||
}
|
||||
|
||||
// MenuService.getMenuList()의 GNB 렌더링과 동일하게 "ROOT"(한글)/"ROOT_EN"(영문) 이름의 언어별 루트를 찾는다.
|
||||
private Menu findLangRoot(Menu root) {
|
||||
String lang = LocaleContextHolder.getLocale().getLanguage();
|
||||
String langRootName = (StringUtils.isBlank(lang) || "ko".equalsIgnoreCase(lang))
|
||||
? "ROOT"
|
||||
: "ROOT_" + lang.toUpperCase();
|
||||
|
||||
return root.getChildMenus().stream()
|
||||
.filter(m -> langRootName.equalsIgnoreCase(m.getMenuName()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private SitemapNode buildNode(Menu menu, Set<String> serviceTypeMenuIds) {
|
||||
SitemapNode node = new SitemapNode(menu);
|
||||
for (Menu child : sortedChildren(menu)) {
|
||||
if (isVisible(child) && matchesServiceType(child, serviceTypeMenuIds)) {
|
||||
node.getChildren().add(buildNode(child, serviceTypeMenuIds));
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private boolean isVisible(Menu menu) {
|
||||
return "Y".equalsIgnoreCase(menu.getDisplayYn()) && "Y".equalsIgnoreCase(menu.getUseYn());
|
||||
}
|
||||
|
||||
// serviceType 필터가 없으면 통과. 있으면 자신이나 하위메뉴 중 하나라도 해당 serviceType 권한이 있어야 통과(상위메뉴 누락 방지).
|
||||
private boolean matchesServiceType(Menu menu, Set<String> serviceTypeMenuIds) {
|
||||
if (serviceTypeMenuIds == null) {
|
||||
return true;
|
||||
}
|
||||
if (serviceTypeMenuIds.contains(menu.getMenuId())) {
|
||||
return true;
|
||||
}
|
||||
return menu.getChildMenus().stream().anyMatch(child -> matchesServiceType(child, serviceTypeMenuIds));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.eactive.eai.rms.common.acl.sitemap.ui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.eactive.eai.rms.data.entity.man.menu.Menu;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SitemapNode {
|
||||
|
||||
private String menuId;
|
||||
|
||||
private String menuName;
|
||||
|
||||
private String menuUrl;
|
||||
|
||||
private List<SitemapNode> children = new ArrayList<>();
|
||||
|
||||
public SitemapNode(Menu menu) {
|
||||
this.menuId = menu.getMenuId();
|
||||
this.menuName = menu.getMenuName();
|
||||
this.menuUrl = menu.getMenuUrl();
|
||||
}
|
||||
|
||||
public SitemapNode() {
|
||||
}
|
||||
}
|
||||
@@ -41,8 +41,6 @@ import lombok.RequiredArgsConstructor;
|
||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||
@RequiredArgsConstructor
|
||||
public class UserManService extends BaseService {
|
||||
|
||||
|
||||
|
||||
private final UserInfoService userInfoService;
|
||||
private final UserRoleService userRoleService;
|
||||
@@ -100,11 +98,9 @@ public class UserManService extends BaseService {
|
||||
|
||||
UserInfo userInfo = userUIMapper.toEntity(userUI);
|
||||
userInfo.setRoleidnfiname(CommonConstants.DEPT_DEVELOPER);
|
||||
|
||||
String subfix = monitoringContext.getStringProperty(MonitoringContext.RMS_PASSWORD_INIT_SUBFIX, "@!");
|
||||
|
||||
try {
|
||||
userInfo.setPassword(DamoManager.getInstance().hash(DamoManager.SHA256,userUI.getUserId()+subfix));
|
||||
userInfo.setPassword(DamoManager.getInstance().hash(DamoManager.SHA256,userUI.getUserId()));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error encrypting password", e);
|
||||
}
|
||||
@@ -144,9 +140,8 @@ public class UserManService extends BaseService {
|
||||
}
|
||||
|
||||
public void updatePassword(UserUI userUI) throws Exception {
|
||||
String subfix = monitoringContext.getStringProperty(MonitoringContext.RMS_PASSWORD_INIT_SUBFIX, "@!");
|
||||
UserInfo userInfo = userInfoService.getById(userUI.getUserId());
|
||||
userInfo.setPassword(DamoManager.getInstance().hash(DamoManager.SHA256, userUI.getUserId()+subfix));
|
||||
userInfo.setPassword(DamoManager.getInstance().hash(DamoManager.SHA256, userUI.getUserId()));
|
||||
userUIMapper.updateToEntity(userUI, userInfo);
|
||||
userInfoService.save(userInfo);
|
||||
}
|
||||
|
||||
@@ -258,15 +258,9 @@ public interface MonitoringContext {
|
||||
// 자동 로그아웃 타임아웃 (단위: 분, 기본값: 10)
|
||||
public static final String RMS_AUTO_LOGOUT_TIMEOUT = "rms.auto.logout.timeout";
|
||||
|
||||
// 웹훅
|
||||
public static final String RMS_WEBHOOK_REVERSE_PROXY_URL = "rms.webhook.reverse_proxy.url";
|
||||
public static final String RMS_WEBHOOK_RETRY_COUNT = "rms.webhook.retry_count";
|
||||
public static final String RMS_WEBHOOK_RETRY_TIME = "rms.webhook.retry_time";
|
||||
|
||||
//비밀번호 초기화 접미사
|
||||
public static final String RMS_PASSWORD_INIT_SUBFIX = "rms.password.init.subfix";
|
||||
|
||||
|
||||
// 웹훅 재전송 설정
|
||||
public static final String API_WEBHOOK_RETRY_COUNT = "api.webhook.retry_count";
|
||||
public static final String API_WEBHOOK_RETRY_TIME = "api.webhook.retry_time";
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ import com.eactive.eai.rms.common.util.ContainerUtil;
|
||||
import com.eactive.eai.rms.data.entity.man.monitoringProperty.MonitoringPropertyId;
|
||||
import com.eactive.eai.rms.data.entity.man.monitoringProperty.service.MonitoringPropertyGroupService;
|
||||
import com.eactive.eai.rms.data.entity.man.monitoringProperty.service.MonitoringPropertyService;
|
||||
import com.eactive.eai.rms.ext.djb.common.DjbPropertyHolder;
|
||||
import com.eactive.eai.rms.ext.djb.common.DjbPropertyInjector;
|
||||
import com.eactive.ext.kjb.common.KjbPropertyHolder;
|
||||
import com.eactive.ext.kjb.util.KjbPropertyInjector;
|
||||
|
||||
@Service("monitoringContext")
|
||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||
@@ -45,7 +45,7 @@ class MonitoringContextImpl implements MonitoringContext {
|
||||
|
||||
public void refresh() {
|
||||
init();
|
||||
DjbPropertyHolder.reload();
|
||||
KjbPropertyHolder.reload();
|
||||
}
|
||||
|
||||
public void refresh(String propName) {
|
||||
@@ -85,9 +85,9 @@ class MonitoringContextImpl implements MonitoringContext {
|
||||
|
||||
setPortMapper(monitoringContextDAO.getPortMap());
|
||||
|
||||
// DjbPropertyHolder 초기화
|
||||
DjbPropertyInjector injector = new DjbPropertyInjector(monitoringPropertyService, "Monitoring");
|
||||
DjbPropertyHolder.initialize(injector::inject);
|
||||
// KjbPropertyHolder 초기화
|
||||
KjbPropertyInjector injector = new KjbPropertyInjector(monitoringPropertyService, "Monitoring");
|
||||
KjbPropertyHolder.initialize(injector::inject);
|
||||
|
||||
logger.info("SSO AgentId : " + System.getProperty(EAI_AGENTID));
|
||||
|
||||
|
||||
@@ -45,9 +45,4 @@ public class LoginResponseDto {
|
||||
* 에러 메시지 (로그인 실패 시)
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 초기 비밀번호 변경 필요 여부
|
||||
*/
|
||||
private boolean changePassword;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.servlet.View;
|
||||
|
||||
import com.eactive.eai.common.seed.Seed;
|
||||
import com.eactive.eai.rms.ext.kjb.smsauth.SmsAuthService;
|
||||
import com.eactive.ext.djb.DamoManager;
|
||||
import com.eactive.eai.data.converter.LocalDateTimeFormatters;
|
||||
import com.eactive.eai.rms.common.context.MonitoringContext;
|
||||
@@ -50,7 +51,6 @@ import com.eactive.eai.rms.data.entity.man.user.UserLoginHistoryService;
|
||||
import com.eactive.eai.rms.data.entity.man.user.UserRole;
|
||||
import com.eactive.eai.rms.data.entity.man.user.UserRoleService;
|
||||
import com.eactive.eai.rms.data.entity.man.user.UserServiceTypeService;
|
||||
import com.eactive.eai.rms.ext.djb.smsauth.SmsAuthService;
|
||||
|
||||
@Controller
|
||||
public class MainController implements InterceptorSkipController {
|
||||
@@ -191,19 +191,6 @@ public class MainController implements InterceptorSkipController {
|
||||
.redirectUrl(redirectUrl)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
// 2.1 초기 비밀번호인 경우, 비밀번호 변경해야 함
|
||||
String subfix = monitoringContext.getStringProperty(MonitoringContext.RMS_PASSWORD_INIT_SUBFIX, "@!");
|
||||
if (userInfo.getPassword().equals(DamoManager.getInstance().hash(DamoManager.SHA256, userInfo.getUserid()+subfix))
|
||||
|| userInfo.getPassword().equals(DamoManager.getInstance().hash(DamoManager.SHA256, userInfo.getUserid()))) {
|
||||
return LoginResponseDto.builder()
|
||||
.success(false)
|
||||
.changePassword(true)
|
||||
.errorMessage("비밀번호 변경후 사용가능합니다.")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
// 3. SMS 인증 필요 여부 체크
|
||||
SmsAuthService smsAuthService = getSmsAuthService();
|
||||
@@ -771,9 +758,6 @@ public class MainController implements InterceptorSkipController {
|
||||
String changePassword, String confirmPassword,
|
||||
String resetUserId, String resetPassword) {
|
||||
HttpSession session = request.getSession();
|
||||
// AJAX 로그인 인증 후 초기비밀번호 변경 경로에서 세션에 부분 로그인 상태가 남아
|
||||
// root emergency.jsp가 main.do로 잘못 리다이렉트하는 것을 방지
|
||||
session.removeAttribute(CommonConstants.LOGIN);
|
||||
|
||||
try {
|
||||
|
||||
@@ -831,8 +815,6 @@ public class MainController implements InterceptorSkipController {
|
||||
.getString("login.pwdchanged"));
|
||||
session.setAttribute(RESULT_MSG, localeMessage
|
||||
.getString("login.pwdchanged"));
|
||||
logger.debug("\n\n\n\n===================" + localeMessage
|
||||
.getString("login.pwdchanged"));
|
||||
return REDIRECT_LOGIN_URL;
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -51,17 +51,4 @@ public class RoleMenuAuthService extends AbstractEMSDataSerivce<RoleMenuAuth, Ro
|
||||
.fetch();
|
||||
}
|
||||
|
||||
public List<String> findMenuIdsByServiceType(String serviceType) {
|
||||
|
||||
QRoleMenuAuth qRoleMenuAuth = QRoleMenuAuth.roleMenuAuth;
|
||||
|
||||
return getJPAQueryFactory()
|
||||
.select(qRoleMenuAuth.id.menuId)
|
||||
.distinct()
|
||||
.from(qRoleMenuAuth)
|
||||
.where(qRoleMenuAuth.id.serviceType.eq(serviceType))
|
||||
.setHint(QueryHints.CACHEABLE, true)
|
||||
.fetch();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-12
@@ -14,8 +14,6 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Service
|
||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||
public class MessageRequestService
|
||||
@@ -55,16 +53,6 @@ public class MessageRequestService
|
||||
return repository.findAll(predicate, fixed);
|
||||
}
|
||||
|
||||
/** 특정 일자에 SMS/KAKAO 로 발송 요청된 건수 (UMS 일련번호 채번용). */
|
||||
public long countSmsKakaoRequestsOnDate(LocalDate date) {
|
||||
QMessageRequest q = QMessageRequest.messageRequest;
|
||||
BooleanBuilder predicate = new BooleanBuilder();
|
||||
predicate.and(q.messageType.in("SMS", "KAKAO"));
|
||||
predicate.and(q.requestDate.goe(date.atStartOfDay()));
|
||||
predicate.and(q.requestDate.loe(date.atTime(23, 59, 59)));
|
||||
return repository.count(predicate);
|
||||
}
|
||||
|
||||
/** PENDING 상태인 건만 FAILED 로 전환한다. */
|
||||
public void updateStatusToFailedIfPending(String id) {
|
||||
MessageRequest entity = getById(id);
|
||||
|
||||
@@ -26,12 +26,9 @@ public class WebhookSendLog {
|
||||
)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "TARGET_URL", length = 500)
|
||||
@Column(name = "TARGET_URL", nullable = false, length = 500)
|
||||
private String targetUrl;
|
||||
|
||||
@Column(name = "PROXY_URL", length = 500)
|
||||
private String proxyUrl;
|
||||
|
||||
@Column(name = "EVENT_TYPE", length = 100)
|
||||
private String eventType;
|
||||
|
||||
@@ -69,9 +66,6 @@ public class WebhookSendLog {
|
||||
@Column(name = "SENT_AT")
|
||||
private LocalDateTime sentAt;
|
||||
|
||||
@Column(name = "SEND_BY", length = 100)
|
||||
private String sendBy;
|
||||
|
||||
/* Boolean 편의 메서드 */
|
||||
public void setSuccess(Boolean success) {
|
||||
this.success = (success != null && success) ? "Y" : "N";
|
||||
|
||||
@@ -126,15 +126,6 @@ public class EAILogRepositoryImpl implements EAILogRepository {
|
||||
query.where(qeaiLog.eaisvcname.containsIgnoreCase(eaiLogSearch.getSearchEaiSvcName()));
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(eaiLogSearch.getSearchEaiSvcDesc())) {
|
||||
QEAIMessageEntity qeaiMessageEntity = QEAIMessageEntity.eAIMessageEntity;
|
||||
JPAQuery<String> subQuery = new JPAQueryFactory(em)
|
||||
.select(qeaiMessageEntity.eaisvcname)
|
||||
.from(qeaiMessageEntity)
|
||||
.where(qeaiMessageEntity.eaisvcdesc.containsIgnoreCase(eaiLogSearch.getSearchEaiSvcDesc()));
|
||||
query.where(qeaiLog.eaisvcname.in(subQuery));
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(eaiLogSearch.getSearchKeyMgtMsgCtnt())) {
|
||||
query.where(qeaiLog.keymgtmsgctnt.contains(eaiLogSearch.getSearchKeyMgtMsgCtnt()));
|
||||
}
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
package com.eactive.eai.rms.ext.djb.common;
|
||||
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
@Data
|
||||
public class DjbProperty {
|
||||
|
||||
// SMS 2차 인증
|
||||
|
||||
@DjbPropertyValue(
|
||||
key = "djb.sms_auth.enabled",
|
||||
defaultValue = "true",
|
||||
description = "SMS 2차 인증 사용 여부. true 시 휴대폰번호 없는 사용자는 ID/PW 로그인 불가")
|
||||
private boolean smsAuthEnabled = false;
|
||||
|
||||
@DjbPropertyValue(
|
||||
key = "djb.sms_auth.mode",
|
||||
defaultValue = "real",
|
||||
description = "인증번호 생성 모드: real(랜덤), hhmm00(현재시각+00), fixed(고정값)")
|
||||
@Pattern(regexp = "^(real|hhmm00|fixed)$", message = "djb.sms_auth.mode는 real, hhmm00, fixed 중 하나여야 합니다.")
|
||||
private String smsAuthMode = "real";
|
||||
|
||||
@DjbPropertyValue(
|
||||
key = "djb.sms_auth.fixed_value",
|
||||
defaultValue = "654321",
|
||||
description = "mode가 fixed일 때 사용할 고정 인증번호 (6자리 숫자)")
|
||||
@Pattern(regexp = "^\\d{6}$", message = "djb.sms_auth.fixed_value는 6자리 숫자여야 합니다.")
|
||||
private String smsAuthFixedValue = "654321";
|
||||
|
||||
|
||||
@DjbPropertyValue(
|
||||
key = "djb.api.allow_ip_list",
|
||||
description = "API 접근 허용 IP 목록 (콤마(,)로 구분된 IP들, 예: 192.168.0.1, 192.168.1.*,127.*.*.*",
|
||||
defaultValue = "10.15.106.*, 10.14.8.*, 10.15.8.*, 192.168.240.*, 127.0.0.1, 192.168.132.*, 192.168.131.*"
|
||||
)
|
||||
private String apiAllowIpList = "10.15.106.*, 10.14.8.*, 10.15.8.*, 192.168.240.*, 127.0.0.1, 192.168.132.*, 192.168.131.*";
|
||||
|
||||
@DjbPropertyValue(
|
||||
key = "djb.api_gw_metric.page_size",
|
||||
description = "API GW Metric 조회시 페이지 크기 설정 (Integer, 0 = 무한, 기본값 10000)",
|
||||
defaultValue = "10000"
|
||||
)
|
||||
private Integer apiGwMetricPageSize = 10000;
|
||||
|
||||
|
||||
|
||||
public String toJsonString(boolean isPretty) {
|
||||
return isPretty
|
||||
? new GsonBuilder().setPrettyPrinting().create().toJson(this)
|
||||
: new Gson().toJson(this);
|
||||
}
|
||||
|
||||
|
||||
// 기본 프로퍼티 목록을 콘솔로 출력 (가이드용)
|
||||
public static void main(String[] args) {
|
||||
System.out.println("| Key | Default Value | Description |");
|
||||
System.out.println("|-----|---------------|-------------|");
|
||||
|
||||
for (java.lang.reflect.Field field : DjbProperty.class.getDeclaredFields()) {
|
||||
DjbPropertyValue annotation = field.getAnnotation(DjbPropertyValue.class);
|
||||
if (annotation != null) {
|
||||
String key = annotation.key();
|
||||
String defaultValue = annotation.defaultValue();
|
||||
String description = annotation.description();
|
||||
System.out.printf("| %s | %s | %s |%n", key, defaultValue, description);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
package com.eactive.eai.rms.ext.djb.common;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* DjbProperty 싱글톤 홀더.
|
||||
*
|
||||
* <p>모든 곳에서 {@code DjbPropertyHolder.get()}으로 현재 DjbProperty에 접근합니다.
|
||||
* eapim-admin에서 초기화 시 {@code initialize()}를 호출하고,
|
||||
* MonitoringContext.refresh() 시 {@code reload()}를 호출하여 값을 갱신합니다.</p>
|
||||
*
|
||||
* <p>사용 예시:</p>
|
||||
* <pre>
|
||||
* // 값 접근
|
||||
* String url = DjbPropertyHolder.get().getUmsHostUrl();
|
||||
*
|
||||
* // 초기화 (eapim-admin에서)
|
||||
* DjbPropertyInjector injector = new DjbPropertyInjector(service, "Monitoring");
|
||||
* DjbPropertyHolder.initialize(injector::inject);
|
||||
*
|
||||
* // reload (MonitoringContext.refresh() 시)
|
||||
* DjbPropertyHolder.reload();
|
||||
*
|
||||
* // 테스트용
|
||||
* DjbPropertyHolder.setForTest(mockProperty);
|
||||
* </pre>
|
||||
*/
|
||||
@Slf4j
|
||||
public class DjbPropertyHolder {
|
||||
|
||||
private static volatile DjbProperty instance = new DjbProperty();
|
||||
private static volatile Function<DjbProperty, DjbProperty> injector;
|
||||
|
||||
private DjbPropertyHolder() {
|
||||
// 유틸리티 클래스
|
||||
}
|
||||
|
||||
/**
|
||||
* 현재 DjbProperty 인스턴스를 반환합니다.
|
||||
*/
|
||||
public static DjbProperty get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 초기화 함수를 등록하고 최초 로딩을 수행합니다.
|
||||
* eapim-admin 부팅 시 MonitoringContextImpl.init()에서 호출됩니다.
|
||||
*
|
||||
* @param injectorFn DjbProperty를 DB에서 로딩하는 함수 (DjbPropertyInjector::inject)
|
||||
*/
|
||||
public static void initialize(Function<DjbProperty, DjbProperty> injectorFn) {
|
||||
injector = injectorFn;
|
||||
reload();
|
||||
log.info("DjbPropertyHolder 초기화 완료");
|
||||
}
|
||||
|
||||
/**
|
||||
* DB에서 프로퍼티를 다시 로딩합니다.
|
||||
* MonitoringContext.refresh() 호출 시 함께 호출됩니다.
|
||||
*/
|
||||
public static void reload() {
|
||||
if (injector != null) {
|
||||
try {
|
||||
instance = injector.apply(new DjbProperty());
|
||||
log.info("DjbProperty reload 완료");
|
||||
} catch (Exception e) {
|
||||
log.error("DjbProperty reload 실패: {}", e.getMessage(), e);
|
||||
}
|
||||
} else {
|
||||
log.debug("DjbPropertyHolder: injector가 설정되지 않음 (테스트 환경일 수 있음)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트용 - 직접 인스턴스를 설정합니다.
|
||||
*/
|
||||
public static void setForTest(DjbProperty testProperty) {
|
||||
instance = testProperty;
|
||||
log.debug("DjbProperty 테스트 인스턴스 설정");
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트용 - 기본값으로 초기화합니다.
|
||||
*/
|
||||
public static void resetForTest() {
|
||||
instance = new DjbProperty();
|
||||
injector = null;
|
||||
log.debug("DjbPropertyHolder 테스트 초기화");
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.eactive.eai.rms.ext.djb.common;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DjbPropertyValue {
|
||||
String key();
|
||||
String defaultValue() default "";
|
||||
String description() default "";
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.SecureRandom;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -19,10 +18,8 @@ import org.springframework.stereotype.Service;
|
||||
import com.eactive.apim.portal.common.util.PhoneNumberUtil;
|
||||
import com.eactive.apim.portal.portalproperty.service.PortalPropertyService;
|
||||
import com.eactive.apim.portal.template.entity.MessageRequest;
|
||||
import com.eactive.eai.common.util.StringUtil;
|
||||
import com.eactive.eai.common.util.SystemUtil;
|
||||
import com.eactive.eai.rms.data.entity.man.monitoringProperty.service.MonitoringPropertyService;
|
||||
import com.eactive.eai.rms.data.entity.onl.apim.messagerequest.MessageRequestService;
|
||||
import com.eactive.eai.rms.ext.djb.ums.vo.EmailDataVO;
|
||||
import com.eactive.eai.rms.ext.djb.ums.vo.SmsDataVO;
|
||||
import com.eactive.eai.rms.ext.djb.ums.vo.StdHeadVO;
|
||||
@@ -42,15 +39,12 @@ public class UmsService {
|
||||
private static final String SYS_DVCD = "API"; //시스템코드
|
||||
private static final String BZWK_DVCD = "99"; //업무구분코드
|
||||
private static final String SUB_BZWK_CD = "9019"; //세부구분코드
|
||||
private static final String TEAM_DVCD = "00"; //팀구분코드 TODO: 변경해야함
|
||||
|
||||
|
||||
private final MonitoringPropertyService propertyService;
|
||||
private final MessageRequestService messageRequestService;
|
||||
|
||||
public UmsService(MonitoringPropertyService propertyService, MessageRequestService messageRequestService) {
|
||||
public UmsService(MonitoringPropertyService propertyService) {
|
||||
this.propertyService = propertyService;
|
||||
this.messageRequestService = messageRequestService;
|
||||
}
|
||||
|
||||
public boolean send(MessageRequest messageRequest) throws Exception {
|
||||
@@ -174,16 +168,17 @@ public class UmsService {
|
||||
|
||||
// 스윙챗 알림 데이터
|
||||
SwingDataVO swiDataVO = new SwingDataVO();
|
||||
swiDataVO.setNotiCode("CNO_FEP_APIM_0002"); //0001:긴급, 0002:중요
|
||||
swiDataVO.setNotiCode("CNO_FEP_HMP_0002");
|
||||
swiDataVO.setNotiTitle("알림");
|
||||
swiDataVO.setNotiContent(messageRequest.getMessage());
|
||||
|
||||
// 스윙챗 알림 데이터
|
||||
List<SwingReceiverDataVO> swiReDataVOList = new ArrayList<SwingReceiverDataVO>();
|
||||
SwingReceiverDataVO receiver = new SwingReceiverDataVO();
|
||||
receiver.setType("PSN");
|
||||
receiver.setType("");
|
||||
receiver.setCompanyCode("CB");
|
||||
receiver.setCode(messageRequest.getMessengerId());
|
||||
receiver.setCode(messageRequest.getMessengerId());
|
||||
receiver.setPrdNm("");
|
||||
swiReDataVOList.add(receiver);
|
||||
|
||||
swiDataVO.setReceiverInfo(swiReDataVOList);
|
||||
@@ -205,22 +200,22 @@ public class UmsService {
|
||||
// Sms 데이터
|
||||
SmsDataVO dataVO = new SmsDataVO();
|
||||
dataVO.setSnd_dman_dt(jsonData[0]);
|
||||
dataVO.setSnd_dman_id(this.getSndDmanId(messageRequest.getMessageType()));
|
||||
dataVO.setSnd_dman_id("");
|
||||
dataVO.setSnd_dvcd("EAI");
|
||||
dataVO.setMsg_titl(StringUtil.chunkString(messageRequest.getSubject(), 40, false)); // MS949 40byte 초과시 절단
|
||||
dataVO.setMsg_titl("");
|
||||
dataVO.setMsg_ctnt(messageRequest.getMessage());
|
||||
dataVO.setRecvr_no(PhoneNumberUtil.digitsOnly(messageRequest.getPhone()));
|
||||
dataVO.setSndn_no("15880079"); //발신번호
|
||||
dataVO.setSnd_empno("APIM"); //요청자
|
||||
dataVO.setSnd_emp_dprm_cd("132"); //요청부서코드
|
||||
dataVO.setSnd_empno(""); //요청자
|
||||
dataVO.setSnd_emp_dprm_cd(""); //요청부서코드
|
||||
if ("SMS".equals(messageRequest.getMessageType())) {
|
||||
dataVO.setLtrs_snd_tycd("1"); // 1:SMS 2:LMS/MMS
|
||||
dataVO.setMsg_snd_tycd("0000"); // 알림톡 메세지 종류 0000:SMS, 1000:LMS, 1008:알림톡, ....
|
||||
} else if ("KAKAO".equals(messageRequest.getMessageType())) {
|
||||
dataVO.setLtrs_snd_tycd("2"); // 1:SMS 2:LMS/MMS
|
||||
dataVO.setMsg_snd_tycd("1008"); // 알림톡 메세지 종류 0000:SMS, 1000:LMS, 1008:알림톡, ....
|
||||
dataVO.setAlmtk_snd_prfl_key(propertyService.getPropertyValue("Monitoring", "djb.ums.sms.almtk_snd_prtl_key", "")); // 플러스친구아이디
|
||||
dataVO.setAlmtk_tmplt_cd(BZWK_DVCD + TEAM_DVCD + SUB_BZWK_CD + "001"); // 템플릿코드
|
||||
dataVO.setAlmtk_snd_prfl_key(""); // 플러스친구아이디
|
||||
dataVO.setAlmtk_tmplt_cd(""); // 템플릿코드
|
||||
dataVO.setAlmtk_err_ltrs_snd_yn("Y"); // 오류자문자발송여부
|
||||
dataVO.setAlmtk_btn_trnm_tycd("2"); // 카카오버튼전송방식 1-format string 2-JSON 3-XML
|
||||
}
|
||||
@@ -248,26 +243,26 @@ public class UmsService {
|
||||
|
||||
// 이메일 데이터
|
||||
EmailDataVO dataVO = new EmailDataVO();
|
||||
dataVO.setUms_evnt_id(""); // TODO: UMS이벤트ID(필수)
|
||||
dataVO.setUms_evnt_id(""); // UMS이벤트ID(필수)
|
||||
dataVO.setSnd_dman_dt(jsonData[0]);
|
||||
dataVO.setSnd_dman_id("");
|
||||
dataVO.setSnd_dman_sno("1");
|
||||
dataVO.setEmail_titl(messageRequest.getSubject()); // 메일제목
|
||||
dataVO.setCstno(""); // TODO: 고객번호(필수)
|
||||
dataVO.setSendr_emaddr(""); // TODO: 발신자 이메일
|
||||
dataVO.setSendr_nm(""); // TODO: 발신자 이름
|
||||
dataVO.setSndbk_emaddr(""); // TODO: 리턴 이메일
|
||||
dataVO.setCstno(""); // 고객번호(필수)
|
||||
dataVO.setSendr_emaddr(""); // 발신자 이메일
|
||||
dataVO.setSendr_nm(""); // 발신자 이름
|
||||
dataVO.setSndbk_emaddr(""); // 리턴 이메일
|
||||
dataVO.setRecvr_emaddr(messageRequest.getEmail()); // 수신자 이메일(필수)
|
||||
dataVO.setRecvr_nm(messageRequest.getUsername()); // 수신자명(필수)
|
||||
dataVO.setTmplt_mpng_info(messageRequest.getMessage()); // 탬플릿매핑정보
|
||||
dataVO.setTmplt_mpng_rptt_info(""); // 탬플릿매핑반복정보
|
||||
dataVO.setSnd_empno("APIM"); // 발신자ID(필수)
|
||||
dataVO.setSnd_emp_dprm_cd("132"); // 발신자부서코드(필수)
|
||||
dataVO.setSnd_empno(""); // 발신자ID(필수)
|
||||
dataVO.setSnd_emp_dprm_cd(""); // 발신자부서코드(필수)
|
||||
dataVO.setBzwk_cd(BZWK_DVCD); // 업무구분코드
|
||||
dataVO.setSub_bzwk_cd(SUB_BZWK_CD); // 업무세부코드
|
||||
dataVO.setSys_dvcd(SYS_DVCD);
|
||||
dataVO.setTx_dt(jsonData[0]); // 거래일자
|
||||
dataVO.setTx_tktm(jsonData[1].substring(0,6)); // 거래시간
|
||||
dataVO.setTx_dt(jsonData[0]); //거래일자
|
||||
dataVO.setTx_tktm(jsonData[1].substring(0,6)); //거래시간
|
||||
|
||||
List<EmailDataVO> dataList = new ArrayList<EmailDataVO>();
|
||||
dataList.add(dataVO);
|
||||
@@ -339,24 +334,4 @@ public class UmsService {
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private String getSndDmanId(String messageType) {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
|
||||
String yyyymmdd = sdf.format(new Date());
|
||||
|
||||
String uuid = SYS_DVCD + BZWK_DVCD + SUB_BZWK_CD + yyyymmdd + "O" ;
|
||||
|
||||
if ("SMS".equals(messageType)) {
|
||||
uuid += "S";
|
||||
} else if ("LMS".equals(messageType)) {
|
||||
uuid += "L";
|
||||
} else if ("KAKAO".equals(messageType)) {
|
||||
uuid += "K";
|
||||
}
|
||||
|
||||
long seq = messageRequestService.countSmsKakaoRequestsOnDate(LocalDate.now()) + 1;
|
||||
uuid += String.format("%014d", seq);
|
||||
|
||||
return uuid;
|
||||
}
|
||||
}
|
||||
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
package com.eactive.eai.rms.ext.djb.webhook.controller;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.SortDefault;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
||||
import com.eactive.eai.rms.common.base.BaseAnnotationController;
|
||||
import com.eactive.eai.rms.common.combo.ComboService;
|
||||
import com.eactive.eai.rms.common.vo.GridResponse;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.dto.WebhookSendLogUI;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.dto.WebhookSendLogUISearch;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.service.WebhookSendLogManService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 웹훅 발송 로그(PTL_WEBHOOK_SEND_LOG) 조회 화면 컨트롤러.
|
||||
*
|
||||
* <p>조회 전용 (등록/수정/삭제 없음)</p>
|
||||
*/
|
||||
@Controller
|
||||
@RequiredArgsConstructor
|
||||
public class WebhookSendLogManController extends BaseAnnotationController {
|
||||
|
||||
private final WebhookSendLogManService webhookSendLogManService;
|
||||
private final ComboService comboService;
|
||||
|
||||
@GetMapping(value = "/onl/apim/webhook/webhookSendLogMan.view")
|
||||
public void view() {
|
||||
// 목록 view
|
||||
}
|
||||
|
||||
@GetMapping(value = "/onl/apim/webhook/webhookSendLogMan.view", params = "cmd=DETAIL")
|
||||
public String detailView() {
|
||||
return "/onl/apim/webhook/webhookSendLogManDetail";
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/apim/webhook/webhookSendLogMan.json", params = "cmd=LIST")
|
||||
public ResponseEntity<GridResponse<WebhookSendLogUI>> selectList(
|
||||
@SortDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable,
|
||||
WebhookSendLogUISearch search) {
|
||||
Page<WebhookSendLogUI> page = webhookSendLogManService.selectList(pageable, search);
|
||||
return ResponseEntity.ok(new GridResponse<>(page));
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/apim/webhook/webhookSendLogMan.json", params = "cmd=LIST_INIT_COMBO")
|
||||
public ResponseEntity<Map<String, Object>> initCombo() {
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
resultMap.put("eventTypeList", comboService.getMonitoringCodeSortedBySeq(WebhookSendLogManService.CODE_GROUP_EVENT_TYPE));
|
||||
return ResponseEntity.ok(resultMap);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/apim/webhook/webhookSendLogMan.json", params = "cmd=DETAIL")
|
||||
public ResponseEntity<WebhookSendLogUI> selectDetail(Long id) {
|
||||
return ResponseEntity.ok(webhookSendLogManService.selectDetail(id));
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.eactive.eai.rms.ext.djb.webhook.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 웹훅 발송 로그(PTL_WEBHOOK_SEND_LOG) 화면 응답 DTO.
|
||||
*
|
||||
* <p>목록에서는 일부 항목만 사용하고, 상세에서는 전체 항목을 사용한다.
|
||||
* 날짜는 yyyyMMdd HH:mm:ss 형식 문자열로 제공한다.</p>
|
||||
*/
|
||||
@Data
|
||||
public class WebhookSendLogUI {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String orgId;
|
||||
private String orgName;
|
||||
|
||||
private String eventType;
|
||||
/** 모니터링 공통코드(EVENT_TYPE) 코드명. 상세 조회에서만 채워진다(목록은 화면에서 콤보로 변환). */
|
||||
private String eventTypeName;
|
||||
private String targetUrl;
|
||||
private String proxyUrl;
|
||||
|
||||
private String payload;
|
||||
private String signature;
|
||||
|
||||
private Integer statusCode;
|
||||
private String responseBody;
|
||||
|
||||
private Boolean success;
|
||||
private String sendBy;
|
||||
private String errorMessage;
|
||||
private Integer retryCount;
|
||||
|
||||
/* 등록/발송 시간 — yyyyMMdd HH:mm:ss */
|
||||
private String createdAt;
|
||||
private String sentAt;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.eactive.eai.rms.ext.djb.webhook.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class WebhookSendLogUISearch {
|
||||
|
||||
/* 기관명 (ptl_org.org_name, LIKE 검색) */
|
||||
private String searchOrgName;
|
||||
|
||||
/* 이벤트 유형 (모니터링 공통코드 EVENT_TYPE, 콤보 선택 값과 정확히 일치) */
|
||||
private String searchEventType;
|
||||
|
||||
/* 수신 URL (LIKE 검색) */
|
||||
private String searchTargetUrl;
|
||||
|
||||
/* 성공여부 (Y/N, 공백=전체) */
|
||||
private String searchSuccess;
|
||||
|
||||
/* 발송일시 기간 검색 (yyyyMMdd, 8자리 — userLoginHistoryMan.jsp 기간검색 스타일) */
|
||||
private String searchStartDate;
|
||||
private String searchEndDate;
|
||||
}
|
||||
@@ -8,9 +8,7 @@ import lombok.Setter;
|
||||
public class WebhookSendRequest {
|
||||
private String orgId;
|
||||
private String targetUrl;
|
||||
private String proxyUrl;
|
||||
private String eventType;
|
||||
private String secret;
|
||||
private String reverseProxyPath;
|
||||
private Object data;
|
||||
}
|
||||
+2
-2
@@ -4,17 +4,17 @@ package com.eactive.eai.rms.ext.djb.webhook.repository;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.eactive.eai.data.jpa.BaseRepository;
|
||||
import com.eactive.eai.rms.data.EMSDataSource;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.WebhookSendLog;
|
||||
|
||||
@Repository
|
||||
@EMSDataSource
|
||||
public interface WebhookSendLogRepository extends BaseRepository<WebhookSendLog, Long> {
|
||||
public interface WebhookSendLogRepository extends JpaRepository<WebhookSendLog, Long> {
|
||||
|
||||
// 오라클 CHAR(1) Y/N 기준 조회
|
||||
@Query("SELECT l FROM WebhookSendLog l " +
|
||||
|
||||
-174
@@ -1,174 +0,0 @@
|
||||
package com.eactive.eai.rms.ext.djb.webhook.service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.eactive.apim.portal.monitoringcode.entity.MonitoringCode;
|
||||
import com.eactive.apim.portal.monitoringcode.entity.MonitoringCodeId;
|
||||
import com.eactive.apim.portal.portalorg.entity.QPortalOrg;
|
||||
import com.eactive.eai.rms.common.base.BaseService;
|
||||
import com.eactive.eai.rms.common.util.StringUtils;
|
||||
import com.eactive.eai.rms.data.entity.man.monitoringCode.repository.MonitoringCodeRepository;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.QWebhookSendLog;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.WebhookSendLog;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.dto.WebhookSendLogUI;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.dto.WebhookSendLogUISearch;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.repository.WebhookSendLogRepository;
|
||||
import com.eactive.eai.rms.onl.common.exception.BizException;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 웹훅 발송 로그(PTL_WEBHOOK_SEND_LOG) 조회 화면 서비스.
|
||||
*
|
||||
* <p>조회 전용. orgId 는 엔티티 연관관계가 아닌 단순 컬럼이므로,
|
||||
* 기관명은 QueryDSL 로 ptl_org 를 별도 조회하여 매핑한다.</p>
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||
public class WebhookSendLogManService extends BaseService {
|
||||
|
||||
/** 모니터링 공통코드(tseairm28) 상의 웹훅 이벤트유형 코드 그룹. */
|
||||
public static final String CODE_GROUP_EVENT_TYPE = "EVENT_TYPE";
|
||||
|
||||
private static final DateTimeFormatter FMT_DATETIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
private static final DateTimeFormatter FMT_YYYYMMDD = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
|
||||
private final WebhookSendLogRepository webhookSendLogRepository;
|
||||
private final MonitoringCodeRepository monitoringCodeRepository;
|
||||
|
||||
@PersistenceContext(unitName = "entityManagerFactoryForEMS")
|
||||
private EntityManager entityManager;
|
||||
|
||||
public Page<WebhookSendLogUI> selectList(Pageable pageable, WebhookSendLogUISearch search) {
|
||||
QWebhookSendLog log = QWebhookSendLog.webhookSendLog;
|
||||
BooleanBuilder predicate = new BooleanBuilder();
|
||||
|
||||
if (StringUtils.isNotBlank(search.getSearchOrgName())) {
|
||||
List<String> orgIds = findOrgIdsByName(search.getSearchOrgName());
|
||||
if (orgIds.isEmpty()) {
|
||||
// 일치하는 기관이 없으면 쿼리를 실행할 필요 없이 빈 결과를 바로 반환한다.
|
||||
// (QueryDSL의 where false 는 이 프로젝트의 Hibernate HQL 파서에서 지원하지 않음)
|
||||
return Page.empty(pageable);
|
||||
}
|
||||
predicate.and(log.orgId.in(orgIds));
|
||||
}
|
||||
if (StringUtils.isNotBlank(search.getSearchEventType())) {
|
||||
predicate.and(log.eventType.eq(search.getSearchEventType()));
|
||||
}
|
||||
if (StringUtils.isNotBlank(search.getSearchTargetUrl())) {
|
||||
predicate.and(log.targetUrl.containsIgnoreCase(search.getSearchTargetUrl()));
|
||||
}
|
||||
if (StringUtils.isNotBlank(search.getSearchSuccess())) {
|
||||
predicate.and(log.success.eq(search.getSearchSuccess()));
|
||||
}
|
||||
if (StringUtils.isNotBlank(search.getSearchStartDate())) {
|
||||
predicate.and(log.sentAt.goe(parseYYYYMMDD(search.getSearchStartDate()).atStartOfDay()));
|
||||
}
|
||||
if (StringUtils.isNotBlank(search.getSearchEndDate())) {
|
||||
predicate.and(log.sentAt.loe(parseYYYYMMDD(search.getSearchEndDate()).atTime(23, 59, 59)));
|
||||
}
|
||||
|
||||
Page<WebhookSendLog> page = webhookSendLogRepository.findAll(predicate, pageable);
|
||||
|
||||
Map<String, String> orgNameMap = findOrgNames(page.getContent());
|
||||
// 목록의 이벤트유형 코드명은 화면에서 콤보(LIST_INIT_COMBO) 기준으로 변환하므로 서버에서는 조회하지 않는다(N+1 방지).
|
||||
return page.map(e -> convertToUI(e, orgNameMap.get(e.getOrgId()), null));
|
||||
}
|
||||
|
||||
public WebhookSendLogUI selectDetail(Long id) {
|
||||
WebhookSendLog entity = webhookSendLogRepository.findById(id)
|
||||
.orElseThrow(() -> new BizException("존재하지 않는 웹훅 발송 로그입니다."));
|
||||
|
||||
Map<String, String> orgNameMap = findOrgNames(Collections.singletonList(entity));
|
||||
String eventTypeName = resolveEventTypeName(entity.getEventType());
|
||||
return convertToUI(entity, orgNameMap.get(entity.getOrgId()), eventTypeName);
|
||||
}
|
||||
|
||||
private static LocalDate parseYYYYMMDD(String yyyyMMdd) {
|
||||
return LocalDate.parse(yyyyMMdd, FMT_YYYYMMDD);
|
||||
}
|
||||
|
||||
/** 모니터링 공통코드(EVENT_TYPE)에서 코드명을 조회한다. 코드가 없으면 원본 코드를 그대로 반환한다. */
|
||||
private String resolveEventTypeName(String eventType) {
|
||||
if (StringUtils.isBlank(eventType)) {
|
||||
return eventType;
|
||||
}
|
||||
return monitoringCodeRepository.findById(new MonitoringCodeId(CODE_GROUP_EVENT_TYPE, eventType))
|
||||
.map(MonitoringCode::getCodeName)
|
||||
.orElse(eventType);
|
||||
}
|
||||
|
||||
/** 기관명 LIKE 검색으로 매칭되는 orgId 목록. */
|
||||
private List<String> findOrgIdsByName(String orgName) {
|
||||
QPortalOrg org = QPortalOrg.portalOrg;
|
||||
return new JPAQueryFactory(entityManager)
|
||||
.select(org.id)
|
||||
.from(org)
|
||||
.where(org.orgName.containsIgnoreCase(orgName))
|
||||
.fetch();
|
||||
}
|
||||
|
||||
/** 목록/상세에 필요한 orgId → orgName 매핑 (일괄 조회로 N+1 방지). */
|
||||
private Map<String, String> findOrgNames(List<WebhookSendLog> logs) {
|
||||
Set<String> orgIds = logs.stream()
|
||||
.map(WebhookSendLog::getOrgId)
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.collect(Collectors.toSet());
|
||||
if (orgIds.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
QPortalOrg org = QPortalOrg.portalOrg;
|
||||
return new JPAQueryFactory(entityManager)
|
||||
.select(org.id, org.orgName)
|
||||
.from(org)
|
||||
.where(org.id.in(orgIds))
|
||||
.fetch()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(t -> t.get(org.id), t -> t.get(org.orgName)));
|
||||
}
|
||||
|
||||
private WebhookSendLogUI convertToUI(WebhookSendLog e, String orgName, String eventTypeName) {
|
||||
WebhookSendLogUI ui = new WebhookSendLogUI();
|
||||
ui.setId(e.getId());
|
||||
ui.setOrgId(e.getOrgId());
|
||||
ui.setOrgName(orgName);
|
||||
ui.setEventType(e.getEventType());
|
||||
ui.setEventTypeName(eventTypeName);
|
||||
ui.setTargetUrl(e.getTargetUrl());
|
||||
ui.setProxyUrl(e.getProxyUrl());
|
||||
ui.setPayload(e.getPayload());
|
||||
ui.setSignature(e.getSignature());
|
||||
ui.setStatusCode(e.getStatusCode());
|
||||
ui.setResponseBody(e.getResponseBody());
|
||||
ui.setSuccess(e.getSuccess());
|
||||
ui.setSendBy(e.getSendBy());
|
||||
ui.setErrorMessage(e.getErrorMessage());
|
||||
ui.setRetryCount(e.getRetryCount());
|
||||
ui.setCreatedAt(fmt(e.getCreatedAt(), FMT_DATETIME));
|
||||
ui.setSentAt(fmt(e.getSentAt(), FMT_DATETIME));
|
||||
return ui;
|
||||
}
|
||||
|
||||
private static String fmt(LocalDateTime t, DateTimeFormatter f) {
|
||||
return t == null ? "" : t.format(f);
|
||||
}
|
||||
}
|
||||
@@ -22,9 +22,7 @@ import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.eactive.apim.portal.portalorg.entity.QPortalOrg;
|
||||
import com.eactive.eai.rms.common.context.MonitoringContext;
|
||||
import com.eactive.eai.rms.common.util.ContainerUtil;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.QWebhookReq;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.QWebhookReqApi;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.QWebhookReqEvent;
|
||||
@@ -62,21 +60,17 @@ public class WebhookService {
|
||||
QWebhookReq req = QWebhookReq.webhookReq;
|
||||
QWebhookReqEvent evt = QWebhookReqEvent.webhookReqEvent;
|
||||
QWebhookReqApi api = QWebhookReqApi.webhookReqApi;
|
||||
QPortalOrg org = QPortalOrg.portalOrg;
|
||||
|
||||
String reverseProxyUrl = monitoringContext.getProperty(MonitoringContext.RMS_WEBHOOK_REVERSE_PROXY_URL);
|
||||
|
||||
List<Tuple> tuples = new JPAQueryFactory(entityManager)
|
||||
.select(req.orgId, req.targetUrl, req.secret, org.reverseProxyPath, api.id.apiId)
|
||||
.select(req.orgId, req.targetUrl, req.secret, api.id.apiId)
|
||||
.from(req)
|
||||
.join(evt).on(req.id.eq(evt.id.webhookReqId))
|
||||
.join(api).on(req.id.eq(api.id.webhookReqId))
|
||||
.join(org).on(req.orgId.eq(org.id))
|
||||
.where(evt.id.eventType.eq(event)
|
||||
.and(api.id.apiId.in(apiIds)))
|
||||
.fetch();
|
||||
|
||||
// orgId + targetUrl + secret 기준으로 그룹핑, apiIds를 data(List)로 집계
|
||||
// orgId + targetUrl + secret 기준으로 그룹핑, apiId를 data(List)로 집계
|
||||
Map<String, WebhookSendRequest> resultMap = new LinkedHashMap<>();
|
||||
for (Tuple t : tuples) {
|
||||
String key = t.get(req.orgId) + "|" + t.get(req.targetUrl);
|
||||
@@ -84,7 +78,6 @@ public class WebhookService {
|
||||
WebhookSendRequest wr = new WebhookSendRequest();
|
||||
wr.setOrgId(t.get(req.orgId));
|
||||
wr.setTargetUrl(t.get(req.targetUrl));
|
||||
wr.setProxyUrl(this.getProxyUrl(reverseProxyUrl, t.get(org.reverseProxyPath), t.get(req.targetUrl)));
|
||||
wr.setSecret(t.get(req.secret));
|
||||
wr.setEventType(event);
|
||||
wr.setData(new ArrayList<String>());
|
||||
@@ -95,46 +88,6 @@ public class WebhookService {
|
||||
|
||||
return new ArrayList<>(resultMap.values());
|
||||
}
|
||||
|
||||
//reverse proxy 서버로 발송하기 위한 url 만든다
|
||||
private String getProxyUrl(String proxyUrl, String path, String targetUrl) {
|
||||
String base = stripTrailingSlash(proxyUrl);
|
||||
String normalizedPath = stripSlashes(path);
|
||||
// scheme://host[:port] 부분만 제거하고 이후 path/query/fragment는 그대로 유지
|
||||
String targetPath = targetUrl.replaceFirst("^[a-zA-Z][a-zA-Z0-9+.-]*://[^/]+", "");
|
||||
|
||||
StringBuilder url = new StringBuilder(base);
|
||||
if (!normalizedPath.isEmpty()) {
|
||||
url.append('/').append(normalizedPath);
|
||||
}
|
||||
url.append(targetPath);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
private String stripTrailingSlash(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
int end = value.length();
|
||||
while (end > 0 && value.charAt(end - 1) == '/') {
|
||||
end--;
|
||||
}
|
||||
return value.substring(0, end);
|
||||
}
|
||||
|
||||
private String stripSlashes(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
String result = value.trim();
|
||||
while (result.startsWith("/")) {
|
||||
result = result.substring(1);
|
||||
}
|
||||
while (result.endsWith("/")) {
|
||||
result = result.substring(0, result.length() - 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 웹훅 발송 메인 메서드
|
||||
@@ -143,7 +96,6 @@ public class WebhookService {
|
||||
public void send(WebhookSendRequest req) {
|
||||
|
||||
String targetUrl = req.getTargetUrl();
|
||||
String proxyUrl = req.getProxyUrl();
|
||||
String secret = req.getSecret();
|
||||
String eventType = req.getEventType();
|
||||
Object data = req.getData();
|
||||
@@ -151,9 +103,7 @@ public class WebhookService {
|
||||
WebhookSendLog sendLog = new WebhookSendLog();
|
||||
sendLog.setOrgId(req.getOrgId());
|
||||
sendLog.setTargetUrl(targetUrl);
|
||||
sendLog.setProxyUrl(proxyUrl);
|
||||
sendLog.setEventType(eventType);
|
||||
sendLog.setSendBy(ContainerUtil.getInstanceName());
|
||||
|
||||
try {
|
||||
// 1. Payload 생성
|
||||
@@ -173,11 +123,11 @@ public class WebhookService {
|
||||
headers.set("X-Webhook-Timestamp", String.valueOf(webhookPayload.getTimestamp()));
|
||||
|
||||
// 4. 발송 (재시도 포함)
|
||||
int retryCount = monitoringContext.getIntProperty(MonitoringContext.RMS_WEBHOOK_RETRY_COUNT, DEFAULT_RETRY_COUNT);
|
||||
int retryTime = monitoringContext.getIntProperty(MonitoringContext.RMS_WEBHOOK_RETRY_TIME, DEFAULT_RETRY_TIME);
|
||||
int retryCount = monitoringContext.getIntProperty(MonitoringContext.API_WEBHOOK_RETRY_COUNT, DEFAULT_RETRY_COUNT);
|
||||
int retryTime = monitoringContext.getIntProperty(MonitoringContext.API_WEBHOOK_RETRY_TIME, DEFAULT_RETRY_TIME);
|
||||
sendLog.setSentAt(LocalDateTime.now());
|
||||
HttpEntity<String> httpRequest = new HttpEntity<>(payloadJson, headers);
|
||||
ResponseEntity<String> response = sendWithRetry(proxyUrl, httpRequest, sendLog, retryCount, retryTime);
|
||||
ResponseEntity<String> response = sendWithRetry(targetUrl, httpRequest, sendLog, retryCount, retryTime);
|
||||
|
||||
// 5. 성공 로그
|
||||
sendLog.setStatusCode(response.getStatusCode().value());
|
||||
@@ -185,7 +135,7 @@ public class WebhookService {
|
||||
sendLog.setSuccess(response.getStatusCode().is2xxSuccessful());
|
||||
|
||||
log.info("[Webhook] 발송 성공 - eventType: {}, url: {}, status: {}, retryCount: {}",
|
||||
eventType, proxyUrl, response.getStatusCode(), sendLog.getRetryCount());
|
||||
eventType, targetUrl, response.getStatusCode(), sendLog.getRetryCount());
|
||||
|
||||
} catch (HttpClientErrorException | HttpServerErrorException e) {
|
||||
sendLog.setStatusCode(e.getStatusCode().value());
|
||||
@@ -193,13 +143,13 @@ public class WebhookService {
|
||||
sendLog.setSuccess(false);
|
||||
sendLog.setErrorMessage(e.getMessage());
|
||||
log.error("[Webhook] HTTP 오류 - eventType: {}, url: {}, status: {}",
|
||||
eventType, proxyUrl, e.getStatusCode());
|
||||
eventType, targetUrl, e.getStatusCode());
|
||||
|
||||
} catch (Exception e) {
|
||||
sendLog.setSuccess(false);
|
||||
sendLog.setErrorMessage(e.getMessage());
|
||||
log.error("[Webhook] 발송 실패 - eventType: {}, url: {}, error: {}",
|
||||
eventType, proxyUrl, e.getMessage());
|
||||
eventType, targetUrl, e.getMessage());
|
||||
}
|
||||
|
||||
sendLogRepository.save(sendLog);
|
||||
@@ -211,25 +161,24 @@ public class WebhookService {
|
||||
/**
|
||||
* 재시도 포함 HTTP 발송
|
||||
* - 4xx: 클라이언트 오류이므로 즉시 throw (재시도 불필요)
|
||||
* - 5xx / 네트워크 오류: 최대 RETRY_COUNT회까지 선형 증가 backoff 재시도 (1s → 2s → 3s → 4s → 5s)
|
||||
* - 5xx / 네트워크 오류: 최대 RETRY_COUNT회까지 exponential backoff 재시도 (1s → 2s → 4s)
|
||||
*/
|
||||
private ResponseEntity<String> sendWithRetry(String proxyUrl, HttpEntity<String> request, WebhookSendLog sendLog, int retryCount, int retryTime) throws Exception {
|
||||
private ResponseEntity<String> sendWithRetry(String targetUrl, HttpEntity<String> request, WebhookSendLog sendLog, int retryCount, int retryTime) throws Exception {
|
||||
Exception lastException = null;
|
||||
for (int attempt = 0; attempt <= retryCount; attempt++) {
|
||||
try {
|
||||
if (attempt > 0) {
|
||||
long delayMs = (long) retryTime * attempt;
|
||||
log.info("[Webhook] 재시도 {}/{} - url: {}, delay: {}ms", attempt, retryCount, proxyUrl, delayMs);
|
||||
sendLog.setRetryCount(attempt);
|
||||
long delayMs = retryTime * (1L << (attempt - 1));
|
||||
log.info("[Webhook] 재시도 {}/{} - url: {}, delay: {}ms", attempt, retryCount, targetUrl, delayMs);
|
||||
Thread.sleep(delayMs);
|
||||
sendLog.setRetryCount(attempt);
|
||||
}
|
||||
return restTemplate.postForEntity(proxyUrl, request, String.class);
|
||||
return restTemplate.postForEntity(targetUrl, request, String.class);
|
||||
} catch (HttpClientErrorException e) {
|
||||
//throw e; // 4xx는 재시도 불필요
|
||||
lastException = e; //TODO: 재시도 테스트
|
||||
throw e; // 4xx는 재시도 불필요
|
||||
} catch (Exception e) {
|
||||
lastException = e;
|
||||
log.warn("[Webhook] 발송 실패 (attempt {}/{}) - url: {}, error: {}", attempt, retryCount, proxyUrl, e.getMessage());
|
||||
log.warn("[Webhook] 발송 실패 (attempt {}/{}) - url: {}, error: {}", attempt, retryCount, targetUrl, e.getMessage());
|
||||
}
|
||||
}
|
||||
throw lastException;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.eactive.eai.rms.ext.djb.smsauth;
|
||||
package com.eactive.eai.rms.ext.kjb.smsauth;
|
||||
|
||||
import com.eactive.apim.portal.user.entity.UserInfo;
|
||||
import com.eactive.eai.rms.common.interceptor.InterceptorSkipController;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.eactive.eai.rms.ext.djb.smsauth;
|
||||
package com.eactive.eai.rms.ext.kjb.smsauth;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
+12
-8
@@ -1,4 +1,4 @@
|
||||
package com.eactive.eai.rms.ext.djb.smsauth;
|
||||
package com.eactive.eai.rms.ext.kjb.smsauth;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.time.LocalDateTime;
|
||||
@@ -13,9 +13,11 @@ import org.springframework.stereotype.Service;
|
||||
import com.eactive.apim.portal.template.entity.MessageCode;
|
||||
import com.eactive.apim.portal.user.entity.UserInfo;
|
||||
import com.eactive.eai.rms.common.login.LoginVo;
|
||||
import com.eactive.eai.rms.ext.djb.common.DjbProperty;
|
||||
import com.eactive.eai.rms.ext.djb.common.DjbPropertyHolder;
|
||||
import com.eactive.eai.rms.ext.djb.ums.UmsManager;
|
||||
import com.eactive.ext.kjb.common.KjbProperty;
|
||||
import com.eactive.ext.kjb.common.KjbPropertyHolder;
|
||||
import com.eactive.ext.kjb.common.KjbUmsException;
|
||||
import com.eactive.ext.kjb.ums.KjbUmsService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -44,11 +46,13 @@ public class SmsAuthService {
|
||||
|
||||
private final UmsManager ums;
|
||||
|
||||
private static DjbProperty getProperty() {
|
||||
return DjbPropertyHolder.get();
|
||||
private static KjbProperty getProperty() {
|
||||
return KjbPropertyHolder.get();
|
||||
}
|
||||
|
||||
|
||||
private KjbUmsService getUmsService() {
|
||||
return KjbUmsService.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* SMS 인증이 필요한지 확인
|
||||
@@ -82,7 +86,7 @@ public class SmsAuthService {
|
||||
* 인증번호 생성
|
||||
*/
|
||||
public String generateAuthCode() {
|
||||
DjbProperty prop = getProperty();
|
||||
KjbProperty prop = getProperty();
|
||||
String mode = prop.getSmsAuthMode();
|
||||
|
||||
if (MODE_FIXED.equalsIgnoreCase(mode)) {
|
||||
@@ -109,7 +113,7 @@ public class SmsAuthService {
|
||||
HashMap<String,Object> params = new HashMap<String, Object>();
|
||||
params.put("authNumber", authCode);
|
||||
params.put("userName", userInfo.getUsername());
|
||||
|
||||
log.debug("\n\n\nDDDDDDDDD" + userInfo.toString());
|
||||
ums.send(userInfo, MessageCode.ADMIN_VERIFICATION_MOBILEPHONE, params);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
@@ -14,9 +14,9 @@ import com.eactive.eai.rms.data.entity.man.user.UserRoleId;
|
||||
import com.eactive.eai.rms.data.entity.man.user.UserRoleService;
|
||||
import com.eactive.eai.rms.data.entity.man.user.UserServiceTypeService;
|
||||
import com.eactive.eai.rms.onl.apim.masking.MaskingUtils;
|
||||
//import com.eactive.ext.kjb.common.KjbProperty;
|
||||
//import com.eactive.ext.kjb.common.KjbPropertyHolder;
|
||||
//import com.eactive.ext.kjb.sso.KjbSsoModule;
|
||||
import com.eactive.ext.kjb.common.KjbProperty;
|
||||
import com.eactive.ext.kjb.common.KjbPropertyHolder;
|
||||
import com.eactive.ext.kjb.sso.KjbSsoModule;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Controller;
|
||||
@@ -52,108 +52,108 @@ public class SsoController implements InterceptorSkipController {
|
||||
this.mainController = mainController;
|
||||
}
|
||||
|
||||
// private KjbSsoModule getSsoModule() {
|
||||
// return KjbSsoModule.getInstance();
|
||||
// }
|
||||
//
|
||||
// private KjbProperty getProperty() {
|
||||
// return KjbPropertyHolder.get();
|
||||
// }
|
||||
private KjbSsoModule getSsoModule() {
|
||||
return KjbSsoModule.getInstance();
|
||||
}
|
||||
|
||||
// @RequestMapping(value = "/sso/login.do")
|
||||
// public String login(HttpServletRequest req, HttpServletResponse res,
|
||||
// @RequestParam(name = "UURL", required = false) String uurl) throws Exception {
|
||||
// HttpSession session = req.getSession();
|
||||
// String ssoId = getSsoModule().getSsoId(req);
|
||||
//
|
||||
// log.debug("ssoId : {}", ssoId);
|
||||
// log.debug("uurl : {}", uurl);
|
||||
//
|
||||
// // 디버깅용 쿠키 목록 출력
|
||||
// if (log.isDebugEnabled()) {
|
||||
// Cookie[] cookies = req.getCookies();
|
||||
// if (cookies == null || cookies.length == 0) {
|
||||
// log.debug("No cookies");
|
||||
// } else {
|
||||
// for (Cookie c : cookies) {
|
||||
// log.debug("Cookie[{}] : Domain={}, Path={}",
|
||||
// c.getName(), c.getDomain(), c.getPath());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (StringUtils.isEmpty(uurl)) {
|
||||
// uurl = getSsoModule().getAscpUrl();
|
||||
// log.debug("UURL is empty, set to ASCP URL");
|
||||
// log.debug("uurl : {}", uurl);
|
||||
// }
|
||||
//
|
||||
// if (ssoId == null) {
|
||||
// getSsoModule().goLoginPage(res, uurl);
|
||||
// return null;
|
||||
// } else {
|
||||
// // EAM 세션 검증
|
||||
// String retCode = getSsoModule().getEamSessionCheck(req, res);
|
||||
// log.debug("retCode : {}", retCode);
|
||||
//
|
||||
// log.debug("Property - sso.ignore_validation = {}", getProperty().isSsoIgnoreValidation());
|
||||
// if (!getProperty().isSsoIgnoreValidation() && !"0".equalsIgnoreCase(retCode)) {
|
||||
// // SSO 검증 실패 시 에러 메시지 설정 및 로그인 페이지로 이동
|
||||
// log.warn("SSO 검증 실패 - retCode: {}, ssoId: {}", retCode, ssoId);
|
||||
// session.setAttribute("resultMsg", "SSO 로그인을 실패 하였습니다. (오류코드: " + retCode + ") 다른 로그인 방식을 시도 하세요");
|
||||
// return "redirect:/loginForm.do";
|
||||
// }
|
||||
//
|
||||
// if (StringUtils.isEmpty(ssoId)) {
|
||||
// session.setAttribute("resultMsg", "SSO 인증 정보를 획득하지 못했습니다.");
|
||||
// return "redirect:/loginForm.do";
|
||||
// }
|
||||
//
|
||||
// if (getProperty().isSsoSyncInfo()) {
|
||||
// // 기본 정보
|
||||
// Properties info = getSsoModule().getUserInfos(ssoId);
|
||||
// // 확장 정보
|
||||
// Properties extendedInfo = getSsoModule().getUserExFields(ssoId);
|
||||
//
|
||||
// // 필수 필드 검증
|
||||
// try {
|
||||
// validateRequiredFields(info, extendedInfo);
|
||||
// } catch (IllegalStateException e) {
|
||||
// log.warn("SSO 필수 필드 검증 실패: {}", e.getMessage());
|
||||
// session.setAttribute("resultMsg", e.getMessage());
|
||||
// return "redirect:/loginForm.do";
|
||||
// }
|
||||
//
|
||||
// // 사용자 정보 로깅 (개인정보 마스킹 처리)
|
||||
// String userId = info.getProperty("USERID");
|
||||
// String name = info.getProperty("NAME");
|
||||
// String email = info.getProperty("EMAIL");
|
||||
// String cellPhoneNo = extendedInfo != null ? extendedInfo.getProperty("CELLPHONENO") : null;
|
||||
//
|
||||
// log.info("SSO 로그인 시도 - userId: {}", userId);
|
||||
// log.debug("SSO 사용자 정보 - userId: {}, name: {}, phone: {}, email: {}",
|
||||
// userId,
|
||||
// MaskingUtils.maskName(name),
|
||||
// MaskingUtils.maskPhoneNumber(cellPhoneNo),
|
||||
// MaskingUtils.maskEmailId(email));
|
||||
//
|
||||
// // 사용자 생성 또는 업데이트
|
||||
// UserInfo userInfo = findOrCreateUser(info, extendedInfo);
|
||||
//
|
||||
// // 로그인 세션 설정 (MainController 위임)
|
||||
// log.info("SSO 로그인 성공 - userId: {}", userId);
|
||||
// return mainController.setupSsoLoginSession(req, userInfo);
|
||||
// } else {
|
||||
// // 동기화 비활성화 모드: 기존 사용자는 업데이트 없이, 신규 사용자는 최소 정보로 생성
|
||||
// log.info("SSO 동기화 비활성화 모드로 로그인 처리 - ssoId: {}", ssoId);
|
||||
//
|
||||
// UserInfo userInfo = findOrCreateUserWithoutSync(ssoId);
|
||||
//
|
||||
// log.info("SSO 로그인 성공 (동기화 비활성화 모드) - userId: {}", ssoId);
|
||||
// return mainController.setupSsoLoginSession(req, userInfo);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
private KjbProperty getProperty() {
|
||||
return KjbPropertyHolder.get();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/sso/login.do")
|
||||
public String login(HttpServletRequest req, HttpServletResponse res,
|
||||
@RequestParam(name = "UURL", required = false) String uurl) throws Exception {
|
||||
HttpSession session = req.getSession();
|
||||
String ssoId = getSsoModule().getSsoId(req);
|
||||
|
||||
log.debug("ssoId : {}", ssoId);
|
||||
log.debug("uurl : {}", uurl);
|
||||
|
||||
// 디버깅용 쿠키 목록 출력
|
||||
if (log.isDebugEnabled()) {
|
||||
Cookie[] cookies = req.getCookies();
|
||||
if (cookies == null || cookies.length == 0) {
|
||||
log.debug("No cookies");
|
||||
} else {
|
||||
for (Cookie c : cookies) {
|
||||
log.debug("Cookie[{}] : Domain={}, Path={}",
|
||||
c.getName(), c.getDomain(), c.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(uurl)) {
|
||||
uurl = getSsoModule().getAscpUrl();
|
||||
log.debug("UURL is empty, set to ASCP URL");
|
||||
log.debug("uurl : {}", uurl);
|
||||
}
|
||||
|
||||
if (ssoId == null) {
|
||||
getSsoModule().goLoginPage(res, uurl);
|
||||
return null;
|
||||
} else {
|
||||
// EAM 세션 검증
|
||||
String retCode = getSsoModule().getEamSessionCheck(req, res);
|
||||
log.debug("retCode : {}", retCode);
|
||||
|
||||
log.debug("Property - sso.ignore_validation = {}", getProperty().isSsoIgnoreValidation());
|
||||
if (!getProperty().isSsoIgnoreValidation() && !"0".equalsIgnoreCase(retCode)) {
|
||||
// SSO 검증 실패 시 에러 메시지 설정 및 로그인 페이지로 이동
|
||||
log.warn("SSO 검증 실패 - retCode: {}, ssoId: {}", retCode, ssoId);
|
||||
session.setAttribute("resultMsg", "SSO 로그인을 실패 하였습니다. (오류코드: " + retCode + ") 다른 로그인 방식을 시도 하세요");
|
||||
return "redirect:/loginForm.do";
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(ssoId)) {
|
||||
session.setAttribute("resultMsg", "SSO 인증 정보를 획득하지 못했습니다.");
|
||||
return "redirect:/loginForm.do";
|
||||
}
|
||||
|
||||
if (getProperty().isSsoSyncInfo()) {
|
||||
// 기본 정보
|
||||
Properties info = getSsoModule().getUserInfos(ssoId);
|
||||
// 확장 정보
|
||||
Properties extendedInfo = getSsoModule().getUserExFields(ssoId);
|
||||
|
||||
// 필수 필드 검증
|
||||
try {
|
||||
validateRequiredFields(info, extendedInfo);
|
||||
} catch (IllegalStateException e) {
|
||||
log.warn("SSO 필수 필드 검증 실패: {}", e.getMessage());
|
||||
session.setAttribute("resultMsg", e.getMessage());
|
||||
return "redirect:/loginForm.do";
|
||||
}
|
||||
|
||||
// 사용자 정보 로깅 (개인정보 마스킹 처리)
|
||||
String userId = info.getProperty("USERID");
|
||||
String name = info.getProperty("NAME");
|
||||
String email = info.getProperty("EMAIL");
|
||||
String cellPhoneNo = extendedInfo != null ? extendedInfo.getProperty("CELLPHONENO") : null;
|
||||
|
||||
log.info("SSO 로그인 시도 - userId: {}", userId);
|
||||
log.debug("SSO 사용자 정보 - userId: {}, name: {}, phone: {}, email: {}",
|
||||
userId,
|
||||
MaskingUtils.maskName(name),
|
||||
MaskingUtils.maskPhoneNumber(cellPhoneNo),
|
||||
MaskingUtils.maskEmailId(email));
|
||||
|
||||
// 사용자 생성 또는 업데이트
|
||||
UserInfo userInfo = findOrCreateUser(info, extendedInfo);
|
||||
|
||||
// 로그인 세션 설정 (MainController 위임)
|
||||
log.info("SSO 로그인 성공 - userId: {}", userId);
|
||||
return mainController.setupSsoLoginSession(req, userInfo);
|
||||
} else {
|
||||
// 동기화 비활성화 모드: 기존 사용자는 업데이트 없이, 신규 사용자는 최소 정보로 생성
|
||||
log.info("SSO 동기화 비활성화 모드로 로그인 처리 - ssoId: {}", ssoId);
|
||||
|
||||
UserInfo userInfo = findOrCreateUserWithoutSync(ssoId);
|
||||
|
||||
log.info("SSO 로그인 성공 (동기화 비활성화 모드) - userId: {}", ssoId);
|
||||
return mainController.setupSsoLoginSession(req, userInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 필수 필드 검증
|
||||
|
||||
@@ -26,7 +26,6 @@ import com.eactive.eai.rms.onl.apim.portalorg.PortalOrgManService;
|
||||
import com.eactive.eai.rms.onl.apim.portaluser.PortalUserManService;
|
||||
import com.eactive.eai.rms.onl.apim.portaluser.PortalUserUI;
|
||||
import com.eactive.eai.rms.common.acl.user.ui.UserUI;
|
||||
import com.eactive.eai.common.util.SystemUtil;
|
||||
import com.eactive.eai.rms.onl.common.exception.BizException;
|
||||
import com.eactive.eai.rms.onl.transaction.apim.ApiInterfaceService;
|
||||
import com.eactive.eai.rms.onl.transaction.apim.mapping.ApiSpecUIMapper;
|
||||
@@ -360,10 +359,6 @@ public class PortalApprovalManService extends BaseService {
|
||||
}
|
||||
|
||||
public boolean isHardDeleteEnabled() {
|
||||
// 승인 요청 완전삭제는 dev(개발) 환경에서만 허용
|
||||
if (!SystemUtil.isDevServer()) {
|
||||
return false;
|
||||
}
|
||||
Map<String, String> properties = portalPropertyService.getPortalPropertiesAsMap(PORTAL_PROPERTY_GROUP);
|
||||
return Boolean.parseBoolean(properties.getOrDefault(HARD_DELETE_FLAG_KEY, "false"));
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
package com.eactive.eai.rms.onl.apim.authserver;
|
||||
|
||||
import com.eactive.eai.agent.command.CommonCommand;
|
||||
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
|
||||
import com.eactive.eai.rms.common.datasource.DataSourceType;
|
||||
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
|
||||
import com.eactive.eai.rms.onl.apim.common.BaseRestController;
|
||||
import com.eactive.eai.rms.onl.common.service.AgentUtilService;
|
||||
import com.eactive.eai.rms.onl.manage.authserver.client.ClientManService;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
/**
|
||||
* 포털 등 내부 시스템이 호출하는 인증서버(GW) 클라이언트 제어용 내부 API.
|
||||
*
|
||||
* <p>{@link BaseRestController} 를 상속하여 ① 세션 인증을 skip(InterceptorSkipController)하고
|
||||
* ② {@code IpWhitelistInterceptor} 를 통해 {@code kjb.api.allow_ip_list} 기준 IP 화이트리스트
|
||||
* 인증을 적용받는다. (호출 측 포털 서버 IP를 반드시 허용목록에 등록해야 함)</p>
|
||||
*
|
||||
* @see com.eactive.eai.rms.common.interceptor.IpWhitelistInterceptor
|
||||
*/
|
||||
@Controller
|
||||
public class ClientBlockApiController extends BaseRestController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ClientBlockApiController.class);
|
||||
|
||||
private final ClientManService clientManService;
|
||||
|
||||
@Qualifier("onlAgentUtilService")
|
||||
@Autowired
|
||||
private AgentUtilService agentUtilService;
|
||||
|
||||
@Autowired
|
||||
public ClientBlockApiController(ClientManService clientManService) {
|
||||
this.clientManService = clientManService;
|
||||
}
|
||||
|
||||
/**
|
||||
* clientId 의 GW 인증 클라이언트를 차단(TSEAIAU01.appstatus = '0')한 뒤,
|
||||
* 승인 경로와 동일하게 GW 인증서버로 RELOAD_CLIENT 명령을 broadcast 하여 캐시를 갱신한다.
|
||||
*
|
||||
* @param clientId 차단할 클라이언트 ID
|
||||
* @return 처리 결과 JSON ({@code {"success":true,"clientId":...}} 또는 {@code {"success":false,"msg":...}})
|
||||
*/
|
||||
@RequestMapping(value = "/onl/admin/authserver/clientBlock.json", method = RequestMethod.POST, produces = JSON_CONTENT_TYPE)
|
||||
@ResponseBody
|
||||
public String blockClient(@RequestParam String clientId) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
// TSEAIAU01(ClientEntity)은 APIGW 데이터소스에 있으므로 라우팅을 먼저 설정한다.
|
||||
DataSourceType type = DataSourceTypeManager.getDataSourceType("APIGW");
|
||||
DataSourceContextHolder.setDataSourceType(type);
|
||||
|
||||
// 상태 차단 (appstatus = '0')
|
||||
clientManService.blockClient(clientId);
|
||||
|
||||
// GW 인증서버 캐시 리로드 (승인 경로 PortalAppApprovalListener 와 동일)
|
||||
CommonCommand.builder()
|
||||
.name(CommonCommand.RELOAD_CLIENT_COMMAND)
|
||||
.args(clientId)
|
||||
.build().broadcast(agentUtilService);
|
||||
|
||||
logger.warn("GW client 차단(appstatus=0)+리로드 완료 - clientId={}", clientId);
|
||||
result.put("success", true);
|
||||
result.put("clientId", clientId);
|
||||
} catch (Exception e) {
|
||||
logger.error("GW client 차단 실패 - clientId={}", clientId, e);
|
||||
result.put("success", false);
|
||||
result.put("msg", e.getMessage());
|
||||
}
|
||||
return toJson(result);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,5 @@
|
||||
package com.eactive.eai.rms.onl.apim.obp;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.eactive.apim.portal.apprequest.entity.AppRequest;
|
||||
import com.eactive.apim.portal.apprequest.repository.AppRequestRepository;
|
||||
import com.eactive.apim.portal.obp.entity.ObpGwMetric;
|
||||
@@ -28,7 +10,18 @@ import com.eactive.eai.rms.common.util.CommonUtil;
|
||||
import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricJpaDAO;
|
||||
import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricService;
|
||||
import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricVO;
|
||||
import com.eactive.eai.rms.ext.djb.common.DjbPropertyHolder;
|
||||
import com.eactive.ext.kjb.common.KjbPropertyHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* ObpGwMetric Man Service - 비즈니스 로직
|
||||
@@ -335,7 +328,7 @@ public class ObpGwMetricManService extends BaseService {
|
||||
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.MONITORING));
|
||||
|
||||
// KjbProperty에서 pageSize 읽기
|
||||
Integer pageSize = DjbPropertyHolder.get().getApiGwMetricPageSize();
|
||||
Integer pageSize = KjbPropertyHolder.get().getApiGwMetricPageSize();
|
||||
if (pageSize == null) {
|
||||
pageSize = 10000; // 기본값 (null 안전 처리)
|
||||
}
|
||||
|
||||
@@ -37,7 +37,4 @@ public class PortalInquiryCommentUI {
|
||||
@DateTimeFormat(pattern = "yyyyMMddHHmmss")
|
||||
private LocalDateTime lastModifiedDate;
|
||||
|
||||
/** 공개범위(ALL=공개/PRIVATE=비공개). */
|
||||
private String visibility;
|
||||
|
||||
}
|
||||
|
||||
-13
@@ -92,17 +92,4 @@ public class PortalInquiryManController extends BaseAnnotationController {
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
// 공개범위 변경 — 감사 로그는 AuditLogInterceptor 가 자동 기록(auditpoints.dat 등록, auditReason 파라미터)
|
||||
@PostMapping(value = "/onl/apim/portalinquiry/portalInquiryMan.json", params = "cmd=VISIBILITY")
|
||||
public ResponseEntity<String> updateVisibility(String targetType, String id, String visibility, String auditReason) {
|
||||
portalInquiryManService.updateVisibility(targetType, id, visibility, auditReason);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/apim/portalinquiry/portalInquiryMan.json", params = "cmd=INCREMENT_VIEW")
|
||||
public ResponseEntity<Void> incrementView(String id) {
|
||||
portalInquiryManService.incrementViewCount(id);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-51
@@ -7,7 +7,6 @@ import com.eactive.apim.portal.portaluser.entity.PortalUserEnums;
|
||||
import com.eactive.apim.portal.portaluser.repository.PortalUserRepository;
|
||||
import com.eactive.apim.portal.qna.entity.Inquiry;
|
||||
import com.eactive.apim.portal.qna.entity.InquiryComment;
|
||||
import com.eactive.apim.portal.qna.entity.VisibilityScope;
|
||||
import com.eactive.apim.portal.user.entity.UserInfo;
|
||||
import com.eactive.eai.rms.common.base.BaseService;
|
||||
import com.eactive.eai.rms.common.exception.IntegrationException;
|
||||
@@ -42,10 +41,8 @@ public class PortalInquiryManService extends BaseService {
|
||||
private final FileService fileService;
|
||||
|
||||
public static final String PENDING = "PENDING";
|
||||
public static final String REVIEWING = "REVIEWING";
|
||||
public static final String RESPONDED = "RESPONDED";
|
||||
public static final String CLOSED = "CLOSED";
|
||||
public static final String TARGET_COMMENT = "COMMENT";
|
||||
|
||||
|
||||
public PortalInquiryManService(PortalInquiryService portalInquiryService,
|
||||
@@ -119,19 +116,12 @@ public class PortalInquiryManService extends BaseService {
|
||||
|
||||
public PortalInquiryUI selectDetail(String id) {
|
||||
Inquiry inquiry = portalInquiryService.getById(id);
|
||||
|
||||
// 답변 대기중 상태에서 상세 조회 시 검토중 상태로 변경
|
||||
if (PENDING.equals(inquiry.getInquiryStatus())) {
|
||||
inquiry.setInquiryStatus(REVIEWING);
|
||||
portalInquiryService.save(inquiry);
|
||||
}
|
||||
|
||||
PortalInquiryUI portalInquiryUI = portalInquiryUIMapper.toVo(inquiry);
|
||||
|
||||
// 문의자 정보 마스킹처리 _ 이름, 이메일, 로그인id, 핸드폰번호
|
||||
//if (portalInquiryUI.getInquirer() != null) {
|
||||
// maskPortalInquiryUI(portalInquiryUI);
|
||||
//}
|
||||
if (portalInquiryUI.getInquirer() != null) {
|
||||
maskPortalInquiryUI(portalInquiryUI);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(inquiry.getAttachFile())) {
|
||||
try {
|
||||
@@ -169,7 +159,7 @@ public class PortalInquiryManService extends BaseService {
|
||||
Inquiry inquiry = portalInquiryService.getById(portalInquiryUI.getId());
|
||||
validateNotClosed(inquiry);
|
||||
// 답변 대기중 상태일 경우만 답변완료로 상태 변경
|
||||
if(inquiry.getInquiryStatus().equals(PENDING) || inquiry.getInquiryStatus().equals(REVIEWING)) {
|
||||
if(inquiry.getInquiryStatus().equals(PENDING)) {
|
||||
inquiry.setInquiryStatus(RESPONDED);
|
||||
}
|
||||
|
||||
@@ -237,41 +227,4 @@ public class PortalInquiryManService extends BaseService {
|
||||
}
|
||||
}
|
||||
|
||||
/** 조회수 증가 (JSP sessionStorage dedup 통과 시 호출). 관리자는 공개범위 무관 전체 접근. */
|
||||
public void incrementViewCount(String id) {
|
||||
Inquiry inquiry = portalInquiryService.getById(id);
|
||||
inquiry.increaseViewCount();
|
||||
portalInquiryService.save(inquiry);
|
||||
}
|
||||
|
||||
/**
|
||||
* 게시물/댓글 공개범위 변경. 사유(reason) 필수.
|
||||
* 변경 이력은 eapim-admin 공통 감사 로그(AuditLogInterceptor)가 자동 기록한다
|
||||
* (auditpoints.dat 의 PortalInquiryManController_..._VISIBILITY, serviceType=APIGW, auditReason 파라미터).
|
||||
*
|
||||
* @param targetType INQUIRY 또는 COMMENT
|
||||
* @param id 대상 게시물/댓글 ID
|
||||
* @param newVisibility 변경할 공개범위(ALL/ORG/PRIVATE)
|
||||
* @param reason 변경 사유(필수)
|
||||
*/
|
||||
public void updateVisibility(String targetType, String id, String newVisibility, String reason) {
|
||||
if (StringUtils.isBlank(reason)) {
|
||||
throw new IntegrationException("공개범위 변경 사유를 입력해주세요.");
|
||||
}
|
||||
VisibilityScope newScope = VisibilityScope.fromString(newVisibility, null);
|
||||
if (newScope == null) {
|
||||
throw new IntegrationException("유효하지 않은 공개범위입니다.");
|
||||
}
|
||||
|
||||
if (TARGET_COMMENT.equalsIgnoreCase(targetType)) {
|
||||
InquiryComment comment = portalInquiryCommentService.getById(id);
|
||||
comment.setVisibility(newScope);
|
||||
portalInquiryCommentService.save(comment);
|
||||
} else {
|
||||
Inquiry inquiry = portalInquiryService.getById(id);
|
||||
inquiry.setVisibility(newScope);
|
||||
portalInquiryService.save(inquiry);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -57,10 +57,4 @@ public class PortalInquiryUI {
|
||||
private String orgName;
|
||||
|
||||
private int commentCount;
|
||||
|
||||
/** 공개범위(ALL/ORG/PRIVATE). */
|
||||
private String visibility;
|
||||
|
||||
/** 조회수. */
|
||||
private long viewCount;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.springframework.data.web.SortDefault;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@@ -38,8 +37,8 @@ public class PortalOrgManController extends BaseAnnotationController {
|
||||
private final ComboService comboService;
|
||||
|
||||
@GetMapping(value = "/onl/apim/portalorg/portalOrgMan.view")
|
||||
public void view(Model model) {
|
||||
model.addAttribute("hardDeleteEnabled", portalOrgManService.isHardDeleteEnabled());
|
||||
public void view() {
|
||||
// view
|
||||
}
|
||||
|
||||
@GetMapping(value = "/onl/apim/portalorg/portalOrgMan.view", params = "cmd=DETAIL")
|
||||
|
||||
@@ -18,7 +18,6 @@ import com.eactive.eai.rms.onl.apim.masking.MaskingUtils;
|
||||
import com.eactive.eai.rms.onl.apim.portaluser.PortalUserCorpManagerUI;
|
||||
import com.eactive.eai.rms.onl.apim.portaluser.PortalUserCorpManagerUIMapper;
|
||||
import com.eactive.eai.rms.onl.common.exception.BizException;
|
||||
import com.eactive.apim.portal.portalproperty.service.PortalPropertyService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -45,27 +44,15 @@ import java.util.Optional;
|
||||
@Slf4j
|
||||
public class PortalOrgManService extends BaseService {
|
||||
|
||||
/** PortalProperty 그룹명 */
|
||||
private static final String PORTAL_PROPERTY_GROUP = "Portal";
|
||||
/** 법인 완전삭제(hard delete) 허용 프로퍼티 키 (true:허용, 기본 false) */
|
||||
private static final String HARD_DELETE_FLAG_KEY = "org.hard-delete.enabled";
|
||||
|
||||
private final PortalOrgService portalOrgService;
|
||||
private final PortalOrgUIMapper portalOrgUIMapper;
|
||||
private final PortalUserService portalUserService;
|
||||
private final PortalUserCorpManagerUIMapper portalUserCorpManagerUIMapper;
|
||||
private final FileService fileService;
|
||||
private final PortalPropertyService portalPropertyService;
|
||||
|
||||
@PersistenceContext(unitName = "entityManagerFactoryForEMS")
|
||||
private EntityManager entityManager;
|
||||
|
||||
/** 법인 목록 '선택 삭제'(완전삭제) 버튼 노출 여부 */
|
||||
public boolean isHardDeleteEnabled() {
|
||||
Map<String, String> properties = portalPropertyService.getPortalPropertiesAsMap(PORTAL_PROPERTY_GROUP);
|
||||
return Boolean.parseBoolean(properties.getOrDefault(HARD_DELETE_FLAG_KEY, "false"));
|
||||
}
|
||||
|
||||
public Page<PortalOrgUI> selectList(Pageable pageable, PortalOrgUISearch portalOrgUISearch) {
|
||||
Page<PortalOrg> portalOrg = portalOrgService.findAll(pageable, portalOrgUISearch);
|
||||
return portalOrg.map(entity -> convertToUIWithMaskOption(entity, true));
|
||||
|
||||
@@ -13,7 +13,6 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.SortDefault;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
||||
@@ -33,8 +32,8 @@ public class PortalUserManController extends BaseAnnotationController {
|
||||
private final ComboService comboService;
|
||||
|
||||
@GetMapping(value = "/onl/apim/portaluser/portalUserMan.view")
|
||||
public void view(Model model) {
|
||||
model.addAttribute("hardDeleteEnabled", portalUserManService.isHardDeleteEnabled());
|
||||
public void view() {
|
||||
// view
|
||||
}
|
||||
|
||||
@GetMapping(value = "/onl/apim/portaluser/portalUserMan.view", params = "cmd=DETAIL")
|
||||
|
||||
@@ -46,8 +46,6 @@ public class PortalUserManService extends BaseService {
|
||||
private static final String PORTAL_PROPERTY_GROUP = "Portal";
|
||||
/** 사용자 별 휴대폰 번호 중복 허용 프로퍼티 키 (true:허용, false:허용안함, 기본 false) */
|
||||
private static final String PROP_MOBILE_DUPLICATE_ALLOW = "user.mobile.duplicate.allow";
|
||||
/** 가입자 완전삭제(hard delete) 허용 프로퍼티 키 (true:허용, 기본 false) */
|
||||
private static final String HARD_DELETE_FLAG_KEY = "user.hard-delete.enabled";
|
||||
|
||||
private final PortalUserService portalUserService;
|
||||
private final PortalUserUIMapper portalUserUIMapper;
|
||||
@@ -62,11 +60,6 @@ public class PortalUserManService extends BaseService {
|
||||
private final PortalInquiryService portalInquiryService;
|
||||
private final PortalPropertyService portalPropertyService;
|
||||
|
||||
/** 가입자 목록 '선택 삭제'(완전삭제) 버튼 노출 여부 */
|
||||
public boolean isHardDeleteEnabled() {
|
||||
Map<String, String> properties = portalPropertyService.getPortalPropertiesAsMap(PORTAL_PROPERTY_GROUP);
|
||||
return Boolean.parseBoolean(properties.getOrDefault(HARD_DELETE_FLAG_KEY, "false"));
|
||||
}
|
||||
|
||||
public Page<PortalUserUI> selectList(Pageable pageable, PortalUserUISearch portalUserUISearch) {
|
||||
Page<PortalUser> portalUser = portalUserService.findAll(pageable, portalUserUISearch);
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package com.eactive.eai.rms.onl.apim.service;
|
||||
|
||||
import com.eactive.eai.util.IpUtil;
|
||||
import com.eactive.ext.kjb.common.KjbPropertyHolder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.eactive.eai.rms.ext.djb.common.DjbPropertyHolder;
|
||||
import com.eactive.eai.util.IpUtil;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* IP 화이트리스트 인증 서비스
|
||||
*
|
||||
@@ -115,7 +113,7 @@ public class IpAuthenticationService {
|
||||
*/
|
||||
private String loadWhitelistFromDb() {
|
||||
try {
|
||||
String whitelist = DjbPropertyHolder.get().getApiAllowIpList();
|
||||
String whitelist = KjbPropertyHolder.get().getApiAllowIpList();
|
||||
if (StringUtils.isBlank(whitelist)) {
|
||||
log.warn("IP whitelist property is empty");
|
||||
return "";
|
||||
|
||||
@@ -103,18 +103,6 @@ public class ClientManService extends OnlBaseService {
|
||||
clientEntityService.deleteById(clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인증 클라이언트를 차단합니다. (appstatus = '0')
|
||||
* 삭제하지 않고 상태만 차단으로 변경합니다.
|
||||
*
|
||||
* @param clientId 차단할 클라이언트 ID
|
||||
*/
|
||||
public void blockClient(String clientId) {
|
||||
ClientEntity clientEntity = clientEntityService.getById(clientId);
|
||||
clientEntity.setAppstatus("0"); // 0: 차단, 1: 정상
|
||||
clientEntityService.save(clientEntity);
|
||||
}
|
||||
|
||||
|
||||
public List<String> findAll() {
|
||||
List<ClientEntity> clientList = clientEntityService.findAll();
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.eactive.eai.rms.onl.manage.authserver.scope;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -10,29 +8,21 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import com.eactive.eai.agent.authserver.ReloadApiScopeCommand;
|
||||
import com.eactive.eai.agent.command.CommonCommand;
|
||||
import com.eactive.eai.rms.common.base.OnlBaseAnnotationController;
|
||||
import com.eactive.eai.rms.common.vo.GridResponse;
|
||||
import com.eactive.eai.rms.data.entity.onl.authserver.ScopeSearch;
|
||||
import com.eactive.eai.rms.data.entity.onl.eaimsg.ApiScopeSearch;
|
||||
import com.eactive.eai.rms.onl.common.exception.BizException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
@Controller
|
||||
public class ScopeController extends OnlBaseAnnotationController {
|
||||
|
||||
private ScopeManService scopeManService;
|
||||
|
||||
private ApiScopeManService apiScopeManService;
|
||||
|
||||
@Autowired
|
||||
public ScopeController(ScopeManService scopeManService, ApiScopeManService apiScopeManService) {
|
||||
public ScopeController(ScopeManService scopeManService) {
|
||||
this.scopeManService = scopeManService;
|
||||
this.apiScopeManService = apiScopeManService;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/onl/admin/authserver/scopeMan.view")
|
||||
@@ -51,12 +41,6 @@ public class ScopeController extends OnlBaseAnnotationController {
|
||||
return ResponseEntity.ok(new GridResponse<>(page));
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/admin/authserver/scopeMan.json", params = "cmd=API_LIST")
|
||||
public ResponseEntity<GridResponse<ApiScopeUI>> selectApiList(Pageable pageable, ApiScopeSearch apiScopeSearch) {
|
||||
Page<ApiScopeUI> page = apiScopeManService.selectApiScopeRelationsList(pageable, apiScopeSearch);
|
||||
return ResponseEntity.ok(new GridResponse<>(page));
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/admin/authserver/scopeMan.json", params = "cmd=DETAIL")
|
||||
public ResponseEntity<ScopeUI> selectDetail(String scopeId) {
|
||||
ScopeUI scopeUI = scopeManService.selectDetail(scopeId);
|
||||
@@ -64,16 +48,14 @@ public class ScopeController extends OnlBaseAnnotationController {
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/admin/authserver/scopeMan.json", params = "cmd=INSERT")
|
||||
public ResponseEntity<Void> insert(ScopeUI scopeUI, @RequestParam(value = "apiList", required = false) String apiListJson) {
|
||||
public ResponseEntity<Void> insert(ScopeUI scopeUI) {
|
||||
scopeManService.insert(scopeUI);
|
||||
saveApiScopeRelations(scopeUI.getScopeId(), apiListJson);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/admin/authserver/scopeMan.json", params = "cmd=UPDATE")
|
||||
public ResponseEntity<Void> update(ScopeUI scopeUI, @RequestParam(value = "apiList", required = false) String apiListJson) {
|
||||
public ResponseEntity<Void> update(ScopeUI scopeUI) {
|
||||
scopeManService.update(scopeUI);
|
||||
saveApiScopeRelations(scopeUI.getScopeId(), apiListJson);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@@ -87,29 +69,8 @@ public class ScopeController extends OnlBaseAnnotationController {
|
||||
.args(new String[] {ReloadApiScopeCommand.COMMAND_TYPE_SCOPE, "", scopeId})
|
||||
.build()
|
||||
.broadcast(agentUtilService);
|
||||
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
private void saveApiScopeRelations(String scopeId, String apiListJson) {
|
||||
if (apiListJson == null || apiListJson.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<ApiScopeUI> apiScopeList;
|
||||
try {
|
||||
apiScopeList = new ObjectMapper().readValue(apiListJson, new TypeReference<List<ApiScopeUI>>() {});
|
||||
} catch (Exception e) {
|
||||
throw new BizException("데이터 변환 중 오류가 발생했습니다.");
|
||||
}
|
||||
|
||||
scopeManService.updateApiScopeRelations(apiScopeList, scopeId);
|
||||
|
||||
CommonCommand.builder()
|
||||
.name(CommonCommand.RELOAD_API_SCOPE_COMMAND)
|
||||
.args(new String[] {ReloadApiScopeCommand.COMMAND_TYPE_SCOPE, "", scopeId})
|
||||
.build()
|
||||
.broadcast(agentUtilService);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.eactive.eai.rms.onl.manage.authserver.scope;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -23,20 +21,17 @@ public class ScopeManService extends OnlBaseService {
|
||||
private ScopeInfoService scopeInfoService;
|
||||
|
||||
private ScopeEntityService scopeEntityService;
|
||||
|
||||
|
||||
private ScopeUIMapper scopeUIMapper;
|
||||
|
||||
private ApiScopeUIMapper apiScopeUIMapper;
|
||||
|
||||
private LocaleMessage localeMessage;
|
||||
|
||||
|
||||
@Autowired
|
||||
public ScopeManService(ScopeInfoService scopeInfoService, ScopeEntityService scopeEntityService,
|
||||
ScopeUIMapper scopeUIMapper, ApiScopeUIMapper apiScopeUIMapper, LocaleMessage localeMessage ) {
|
||||
public ScopeManService(ScopeInfoService scopeInfoService, ScopeEntityService scopeEntityService,
|
||||
ScopeUIMapper scopeUIMapper, LocaleMessage localeMessage ) {
|
||||
this.scopeInfoService = scopeInfoService;
|
||||
this.scopeEntityService = scopeEntityService;
|
||||
this.scopeUIMapper = scopeUIMapper;
|
||||
this.apiScopeUIMapper = apiScopeUIMapper;
|
||||
this.localeMessage = localeMessage;
|
||||
}
|
||||
|
||||
@@ -70,23 +65,5 @@ public class ScopeManService extends OnlBaseService {
|
||||
public void deleteApiScopeRelationsByScopeId(String scopeId) {
|
||||
scopeEntityService.deleteByIdScopeId(scopeId);
|
||||
}
|
||||
|
||||
public void updateApiScopeRelations(List<ApiScopeUI> apiScopeList, String scopeId) {
|
||||
if (scopeId == null || scopeId.isEmpty()) {
|
||||
throw new BizException("ScopeId 가 존재하지 않습니다.");
|
||||
}
|
||||
|
||||
// ScopeId 기준 전체 삭제 후 LIST 기준으로 재저장.
|
||||
scopeEntityService.deleteByIdScopeId(scopeId);
|
||||
|
||||
if (apiScopeList == null || apiScopeList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ApiScopeUI ui : apiScopeList) {
|
||||
ui.setScopeId(scopeId);
|
||||
scopeEntityService.save(apiScopeUIMapper.toEntity(ui));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+10
-12
@@ -19,9 +19,7 @@ import com.eactive.eai.agent.command.CommonCommand;
|
||||
import com.eactive.eai.rms.common.base.OnlBaseAnnotationController;
|
||||
import com.eactive.eai.rms.common.combo.ComboService;
|
||||
import com.eactive.eai.rms.common.combo.ComboVo;
|
||||
import com.eactive.eai.rms.common.util.CommonUtil;
|
||||
import com.eactive.eai.rms.common.vo.GridResponse;
|
||||
import com.eactive.eai.rms.common.vo.SimpleResponse;
|
||||
|
||||
@Controller
|
||||
public class InflowClientControlManController extends OnlBaseAnnotationController {
|
||||
@@ -57,22 +55,22 @@ public class InflowClientControlManController extends OnlBaseAnnotationControlle
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/onl/admin/inflow/inflowClientControlMan.json", params = "cmd=UPDATE")
|
||||
public ResponseEntity<SimpleResponse> save(HttpServletRequest request, HttpServletResponse response, InflowControlManUI ui)
|
||||
public String save(HttpServletRequest request, HttpServletResponse response, InflowControlManUI ui)
|
||||
throws Exception {
|
||||
service.mergeClient(ui);
|
||||
CommonCommand command = new CommonCommand("com.eactive.eai.agent.inflow.ReloadInflowClientControlCommand", ui.getName());
|
||||
HashMap<String, Object> returnMap = agentUtilService.broadcast(command);
|
||||
SimpleResponse simpleResponse = SimpleResponse.of(CommonUtil.getMapString(returnMap, true));
|
||||
return ResponseEntity.ok(simpleResponse);
|
||||
CommonCommand command = new CommonCommand("com.eactive.eai.agent.inflow.ReloadInflowClientControlCommand",
|
||||
ui.getName());
|
||||
agentUtilService.broadcast(command);
|
||||
return null;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/onl/admin/inflow/inflowClientControlMan.json", params = "cmd=DELETE")
|
||||
public ResponseEntity<SimpleResponse> delete(HttpServletRequest request, HttpServletResponse response, String name) throws Exception {
|
||||
public String delete(HttpServletRequest request, HttpServletResponse response, String name) throws Exception {
|
||||
service.deleteClient(name);
|
||||
CommonCommand command = new CommonCommand("com.eactive.eai.agent.inflow.RemoveInflowClientControlCommand", name);
|
||||
HashMap<String, Object> returnMap = agentUtilService.broadcast(command);
|
||||
SimpleResponse simpleResponse = SimpleResponse.of(CommonUtil.getMapString(returnMap, true));
|
||||
return ResponseEntity.ok(simpleResponse);
|
||||
CommonCommand command = new CommonCommand("com.eactive.eai.agent.inflow.RemoveInflowClientControlCommand",
|
||||
name);
|
||||
agentUtilService.broadcast(command);
|
||||
return null;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/onl/admin/inflow/inflowClientControlMan.json", params = "cmd=LIST_INIT_COMBO")
|
||||
|
||||
-9
@@ -72,9 +72,6 @@ public class InflowControlManService extends BaseService {
|
||||
} else {
|
||||
entity = mapper.toEntity(ui);
|
||||
}
|
||||
if (entity.getThreshold() == null || StringUtils.isEmpty(entity.getThresholdtimeunit())) {
|
||||
entity.setThreshold(0);
|
||||
}
|
||||
service.save(entity);
|
||||
}
|
||||
|
||||
@@ -105,9 +102,6 @@ public class InflowControlManService extends BaseService {
|
||||
} else {
|
||||
entity = mapper.toEntity(ui);
|
||||
}
|
||||
if (entity.getThreshold() == null || StringUtils.isEmpty(entity.getThresholdtimeunit())) {
|
||||
entity.setThreshold(0);
|
||||
}
|
||||
service.save(entity);
|
||||
}
|
||||
|
||||
@@ -139,9 +133,6 @@ public class InflowControlManService extends BaseService {
|
||||
} else {
|
||||
entity = mapper.toEntity(ui);
|
||||
}
|
||||
if (entity.getThreshold() == null || StringUtils.isEmpty(entity.getThresholdtimeunit())) {
|
||||
entity.setThreshold(0);
|
||||
}
|
||||
service.save(entity);
|
||||
}
|
||||
|
||||
|
||||
@@ -352,7 +352,7 @@ public class LayoutManService extends OnlBaseService {
|
||||
}
|
||||
|
||||
if (max == 0 && min == 0) {
|
||||
if ("GRID".equalsIgnoreCase(loutItemType) || "ARRAY".equalsIgnoreCase(loutItemType)) {
|
||||
if ("GRID".equalsIgnoreCase(loutItemType)) {
|
||||
min = 1;
|
||||
max = -1;
|
||||
} else {
|
||||
@@ -371,8 +371,7 @@ public class LayoutManService extends OnlBaseService {
|
||||
}
|
||||
|
||||
private String determineOccurNoItem(LayoutItemUI layoutItemUI, String loutItemType) {
|
||||
if (("GRID".equalsIgnoreCase(loutItemType) || "ARRAY".equalsIgnoreCase(loutItemType))
|
||||
&& NumberUtils.toInt(layoutItemUI.getLoutItemOccCnt()) == 0) {
|
||||
if ("GRID".equalsIgnoreCase(loutItemType) && NumberUtils.toInt(layoutItemUI.getLoutItemOccCnt()) == 0) {
|
||||
return "*";
|
||||
}
|
||||
return String.valueOf(layoutItemUI.getLoutItemOccCnt());
|
||||
@@ -386,8 +385,6 @@ public class LayoutManService extends OnlBaseService {
|
||||
node = Item.NODE_GROUP;
|
||||
} else if ("ATTR".equalsIgnoreCase(el.getLoutItemType())) {
|
||||
node = Item.NODE_ATTR;
|
||||
} else if ("ARRAY".equalsIgnoreCase(el.getLoutItemType())) {
|
||||
node = Item.NODE_FIELD;
|
||||
} else {
|
||||
node = Item.NODE_FIELD;
|
||||
}
|
||||
|
||||
+6
-26
@@ -71,33 +71,13 @@ public interface LayoutItemUIMapper extends GenericMapper<LayoutItemUI, LayoutIt
|
||||
itemType = isGridCondition ? "GRID" : "GROUP";
|
||||
|
||||
// isGridCondition이 참이고, 참조 정보2가 비어 있는 경우, itemLoopCount 설정
|
||||
if (isGridCondition && StringUtils.isBlank(item.getLoutitemrefinfo2())) {
|
||||
if ("*".equals(item.getLoutitemoccurptrndstcd())) {
|
||||
// 반복횟수로 '*'(무제한)이 저장된 경우, 화면 그리드에도 '*'을 그대로 표시
|
||||
itemLoopCount = "*";
|
||||
} else if (NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd())
|
||||
&& Integer.parseInt(item.getLoutitemoccurptrndstcd()) > -1) {
|
||||
itemLoopCount = item.getLoutitemoccurptrndstcd();
|
||||
}
|
||||
}
|
||||
} else if (ItemNodeType.FIELD.getNumber() == item.getLoutitemnodeptrnidname()) {
|
||||
// 아이템 발생 포인터 명이 '*'이거나 숫자로 생성 가능한 경우
|
||||
boolean isArrayCondition = "*".equals(item.getLoutitemoccurptrndstcd()) || NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd());
|
||||
// itemType을 ARRAY 또는 FIELD 로 설정
|
||||
itemType = isArrayCondition ? "ARRAY" : "FIELD";
|
||||
|
||||
// isArrayCondition이 참이고, 참조 정보2가 비어 있는 경우, itemLoopCount 설정
|
||||
if (isArrayCondition && StringUtils.isBlank(item.getLoutitemrefinfo2())) {
|
||||
if ("*".equals(item.getLoutitemoccurptrndstcd())) {
|
||||
// 반복횟수로 '*'(무제한)이 저장된 경우, 화면 그리드에도 '*'을 그대로 표시
|
||||
itemLoopCount = "*";
|
||||
} else if (NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd())
|
||||
&& Integer.parseInt(item.getLoutitemoccurptrndstcd()) > -1) {
|
||||
itemLoopCount = item.getLoutitemoccurptrndstcd();
|
||||
}
|
||||
if (isGridCondition && StringUtils.isBlank(item.getLoutitemrefinfo2())
|
||||
&& NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd())
|
||||
&& Integer.parseInt(item.getLoutitemoccurptrndstcd()) > -1 ) {
|
||||
itemLoopCount = item.getLoutitemoccurptrndstcd();
|
||||
}
|
||||
} else {
|
||||
// 아이템 노드 타입이 GROUP/FIELD가 아닌 경우, 해당 노드 타입으로 itemType 설정
|
||||
// 아이템 노드 타입이 GROUP이 아닌 경우, 해당 노드 타입으로 itemType 설정
|
||||
itemType = ItemNodeType.fromNumber(item.getLoutitemnodeptrnidname()).toString();
|
||||
}
|
||||
|
||||
@@ -105,7 +85,7 @@ public interface LayoutItemUIMapper extends GenericMapper<LayoutItemUI, LayoutIt
|
||||
|
||||
itemUi.setLoutItemType(itemType);
|
||||
|
||||
if (!"*".equals(itemLoopCount) && NumberUtils.toInt(itemLoopCount) == 0) {
|
||||
if(NumberUtils.toInt(itemLoopCount) == 0){
|
||||
itemLoopCount = "";
|
||||
}
|
||||
itemUi.setLoutItemOccCnt(itemLoopCount);
|
||||
|
||||
+5
-25
@@ -71,30 +71,10 @@ public interface LayoutPopupUIMapper extends GenericMapper<LayoutPopupUI, Layout
|
||||
itemType = isGridCondition ? "GRID" : "GROUP";
|
||||
|
||||
// isGridCondition이 참이고, 참조 정보2가 비어 있는 경우, itemLoopCount 설정
|
||||
if (isGridCondition && StringUtils.isBlank(item.getLoutitemrefinfo2())) {
|
||||
if ("*".equals(item.getLoutitemoccurptrndstcd())) {
|
||||
// 반복횟수로 '*'(무제한)이 저장된 경우, 화면 그리드에도 '*'을 그대로 표시
|
||||
itemLoopCount = "*";
|
||||
} else if (NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd())
|
||||
&& Integer.parseInt(item.getLoutitemoccurptrndstcd()) > -1) {
|
||||
itemLoopCount = item.getLoutitemoccurptrndstcd();
|
||||
}
|
||||
}
|
||||
} else if (ItemNodeType.FIELD.getNumber() == item.getLoutitemnodeptrnidname()) {
|
||||
// 아이템 발생 포인터 명이 '*'이거나 숫자로 생성 가능한 경우
|
||||
boolean isArrayCondition = "*".equals(item.getLoutitemoccurptrndstcd()) || NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd());
|
||||
// itemType을 ARRAY 또는 FIELD 로 설정
|
||||
itemType = isArrayCondition ? "ARRAY" : "FIELD";
|
||||
|
||||
// isArrayCondition이 참이고, 참조 정보2가 비어 있는 경우, itemLoopCount 설정
|
||||
if (isArrayCondition && StringUtils.isBlank(item.getLoutitemrefinfo2())) {
|
||||
if ("*".equals(item.getLoutitemoccurptrndstcd())) {
|
||||
// 반복횟수로 '*'(무제한)이 저장된 경우, 화면 그리드에도 '*'을 그대로 표시
|
||||
itemLoopCount = "*";
|
||||
} else if (NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd())
|
||||
&& Integer.parseInt(item.getLoutitemoccurptrndstcd()) > -1) {
|
||||
itemLoopCount = item.getLoutitemoccurptrndstcd();
|
||||
}
|
||||
if (isGridCondition && StringUtils.isBlank(item.getLoutitemrefinfo2())
|
||||
&& NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd())
|
||||
&& Integer.parseInt(item.getLoutitemoccurptrndstcd()) > -1 ) {
|
||||
itemLoopCount = item.getLoutitemoccurptrndstcd();
|
||||
}
|
||||
} else {
|
||||
// 아이템 노드 타입이 GROUP이 아닌 경우, 해당 노드 타입으로 itemType 설정
|
||||
@@ -105,7 +85,7 @@ public interface LayoutPopupUIMapper extends GenericMapper<LayoutPopupUI, Layout
|
||||
|
||||
popupUI.setLoutItemType(itemType);
|
||||
|
||||
if (!"*".equals(itemLoopCount) && NumberUtils.toInt(itemLoopCount) == 0) {
|
||||
if(NumberUtils.toInt(itemLoopCount) == 0){
|
||||
itemLoopCount = "";
|
||||
}
|
||||
popupUI.setLoutItemOccCnt(itemLoopCount);
|
||||
|
||||
@@ -555,7 +555,7 @@ public class ApiInterfaceService extends OnlBaseService {
|
||||
restOption.setStandardCommonFields(standardCommonFields);
|
||||
return objectMapper.writeValueAsString(restOption);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("표준전문 공통부 생성을 실패했습니다", e);
|
||||
throw new RuntimeException("Failed to create standard common option", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1117,14 +1117,13 @@ public class ApiInterfaceService extends OnlBaseService {
|
||||
String replacementBetweenUnderscores = newApiInterfaceId;
|
||||
|
||||
// 정규 표현식 패턴: 첫 번째 언더바 전의 단어와 두 번째 언더바 사이의 단어를 찾기 위한 패턴
|
||||
// (서비스ID 등에 '-'가 포함될 수 있으므로 \w+ 대신 [^_]+ 사용 - transform 치환 로직과 동일)
|
||||
String regex = "(^[^_]+)|(?<=_)[^_]+(?=_)";
|
||||
String regex = "(^[^_]+)|(?<=_)\\w+(?=_)";
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(loutName);
|
||||
|
||||
// 첫 번째 매칭된 부분(언더바 전의 단어)과 두 번째 매칭된 부분(언더바 사이의 단어)을 대체
|
||||
String updatedString = matcher.replaceFirst(replacementBeforeUnderscore); // 첫 번째 매칭된 부분 대체
|
||||
updatedString = updatedString.replaceFirst("(?<=_)[^_]+(?=_)", replacementBetweenUnderscores); // 두 번째 매칭된 부분 대체
|
||||
updatedString = updatedString.replaceFirst("(?<=_)\\w+(?=_)", replacementBetweenUnderscores); // 두 번째 매칭된 부분 대체
|
||||
|
||||
layoutUI.setLoutName(updatedString);
|
||||
|
||||
|
||||
@@ -448,24 +448,14 @@ public class ApiSpecManService {
|
||||
// 헤더/바디 분리
|
||||
RequestComponents components = separateHeaderAndBody(requestLayout.getLayoutItems());
|
||||
|
||||
boolean bodyRequired = isRequestBodyRequired(httpMethod);
|
||||
|
||||
// 헤더 파라미터 + (POST/PUT 이 아니면) 요청 바디 항목을 쿼리스트링 파라미터로 함께 담는다.
|
||||
boolean hasHeader = !components.headerItems.isEmpty();
|
||||
boolean queryFromBody = !bodyRequired && !components.bodyItems.isEmpty();
|
||||
if (hasHeader || queryFromBody) {
|
||||
// 헤더 파라미터 처리
|
||||
if (!components.headerItems.isEmpty()) {
|
||||
ArrayNode parameters = operation.putArray("parameters");
|
||||
if (hasHeader) {
|
||||
generateHeaderParameters(parameters, components.headerItems);
|
||||
}
|
||||
// GET/DELETE 등 바디 미사용 메소드: 요청 레이아웃 바디 항목 → 쿼리 파라미터(in=query)
|
||||
if (queryFromBody) {
|
||||
generateQueryParameters(parameters, components.bodyItems);
|
||||
}
|
||||
generateHeaderParameters(parameters, components.headerItems);
|
||||
}
|
||||
|
||||
// Body 처리 (POST, PUT 메소드인 경우)
|
||||
if (bodyRequired) {
|
||||
if (isRequestBodyRequired(httpMethod)) {
|
||||
ObjectNode requestBody = operation.putObject("requestBody");
|
||||
requestBody.put("required", true);
|
||||
ObjectNode content = requestBody.putObject("content");
|
||||
@@ -571,35 +561,6 @@ public class ApiSpecManService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET/DELETE 등 바디 미사용 메소드: 요청 레이아웃 바디 항목을 쿼리스트링 파라미터(in=query)로 매핑.
|
||||
* 스칼라 FIELD 만 대상(GROUP/GRID 중첩 객체·배열은 쿼리스트링에 부적합하여 제외), root(serno 0)는 스킵.
|
||||
*/
|
||||
private void generateQueryParameters(ArrayNode parameters, List<LayoutItemUI> bodyItems) {
|
||||
for (LayoutItemUI item : bodyItems) {
|
||||
if (item.getLoutItemSerno() != null && item.getLoutItemSerno() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (!"FIELD".equalsIgnoreCase(item.getLoutItemType())) {
|
||||
continue;
|
||||
}
|
||||
ObjectNode parameter = parameters.addObject();
|
||||
parameter.put("name", item.getLoutItemName());
|
||||
parameter.put("in", "query");
|
||||
if (StringUtils.isNotEmpty(item.getLoutItemDesc())) {
|
||||
parameter.put("description", item.getLoutItemDesc());
|
||||
}
|
||||
parameter.put("required", false); // 기본값 false, 필요시 사용자가 변경
|
||||
|
||||
ObjectNode schema = parameter.putObject("schema");
|
||||
schema.put("type", mapSwaggerType(item.getLoutItemDataType()));
|
||||
int length = item.getLoutItemLength();
|
||||
if (length > 0) {
|
||||
schema.put("maxLength", length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateResponseHeaders(ObjectNode headers, List<LayoutItemUI> headerItems) {
|
||||
for (LayoutItemUI item : headerItems) {
|
||||
if ("FIELD".equalsIgnoreCase(item.getLoutItemType())) {
|
||||
|
||||
+22
-17
@@ -1,8 +1,10 @@
|
||||
package com.eactive.eai.rms.ext.djb.common;
|
||||
package com.eactive.ext.kjb.util;
|
||||
|
||||
import com.eactive.eai.rms.data.entity.man.monitoringProperty.MonitoringProperty;
|
||||
import com.eactive.eai.rms.data.entity.man.monitoringProperty.MonitoringPropertyId;
|
||||
import com.eactive.eai.rms.data.entity.man.monitoringProperty.service.MonitoringPropertyService;
|
||||
import com.eactive.ext.kjb.common.KjbProperty;
|
||||
import com.eactive.ext.kjb.common.KjbPropertyValue;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@@ -10,49 +12,52 @@ import java.lang.reflect.Field;
|
||||
import java.util.Optional;
|
||||
|
||||
@Slf4j
|
||||
public class DjbPropertyInjector {
|
||||
public class KjbPropertyInjector {
|
||||
private final MonitoringPropertyService monitoringPropertyService;
|
||||
private final String groupId;
|
||||
|
||||
|
||||
public DjbPropertyInjector(MonitoringPropertyService monitoringPropertyService, String groupId) {
|
||||
public KjbPropertyInjector(MonitoringPropertyService monitoringPropertyService, String groupId) {
|
||||
this.monitoringPropertyService = monitoringPropertyService;
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
/**
|
||||
* DjbProperty의 URL 값들이 설정되어 있는지 확인
|
||||
* @param property 검사할 DjbProperty 객체
|
||||
* KjbProperty의 URL 값들이 설정되어 있는지 확인
|
||||
* @param property 검사할 KjbProperty 객체
|
||||
* @return URL 값들이 모두 설정되어 있으면 true
|
||||
*/
|
||||
public boolean isUrlConfigured(DjbProperty property) {
|
||||
public boolean isUrlConfigured(KjbProperty property) {
|
||||
if (property == null) return false;
|
||||
|
||||
return StringUtils.isNotEmpty(property.getApiAllowIpList());
|
||||
// 주요 URL 값들 중 하나라도 설정되어 있으면 true
|
||||
return StringUtils.isNotEmpty(property.getEaiBatchUrl())
|
||||
|| StringUtils.isNotEmpty(property.getUmsHostUrl())
|
||||
|| StringUtils.isNotEmpty(property.getObpUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* URL 값이 비어있을 경우 DB에서 재로딩 시도
|
||||
* @param property 기존 DjbProperty 객체
|
||||
* @return 재로딩된 DjbProperty 객체 (재로딩 실패 시 기존 객체 반환)
|
||||
* @param property 기존 KjbProperty 객체
|
||||
* @return 재로딩된 KjbProperty 객체 (재로딩 실패 시 기존 객체 반환)
|
||||
*/
|
||||
public DjbProperty reloadIfUrlEmpty(DjbProperty property) {
|
||||
public KjbProperty reloadIfUrlEmpty(KjbProperty property) {
|
||||
if (property == null) {
|
||||
return inject(new DjbProperty());
|
||||
return inject(new KjbProperty());
|
||||
}
|
||||
|
||||
if (!isUrlConfigured(property)) {
|
||||
log.info("DjbProperty URL 값이 비어있어 DB에서 재로딩 시도");
|
||||
log.info("KjbProperty URL 값이 비어있어 DB에서 재로딩 시도");
|
||||
try {
|
||||
DjbProperty reloaded = inject(new DjbProperty());
|
||||
KjbProperty reloaded = inject(new KjbProperty());
|
||||
if (isUrlConfigured(reloaded)) {
|
||||
log.info("DjbProperty 재로딩 성공");
|
||||
log.info("KjbProperty 재로딩 성공");
|
||||
return reloaded;
|
||||
} else {
|
||||
log.warn("DjbProperty 재로딩 후에도 URL 값이 비어있음");
|
||||
log.warn("KjbProperty 재로딩 후에도 URL 값이 비어있음");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("DjbProperty 재로딩 실패: {}", e.getMessage(), e);
|
||||
log.error("KjbProperty 재로딩 실패: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +68,7 @@ public class DjbPropertyInjector {
|
||||
Class<?> clazz = property.getClass();
|
||||
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
DjbPropertyValue anno = field.getAnnotation(DjbPropertyValue.class);
|
||||
KjbPropertyValue anno = field.getAnnotation(KjbPropertyValue.class);
|
||||
|
||||
if (anno != null) {
|
||||
String key = anno.key();
|
||||
@@ -2490,7 +2490,6 @@ deployResourceSearchMan.deleteBtn=delete
|
||||
|
||||
auditLogMan.command = Command
|
||||
auditLogMan.logMsg = Message
|
||||
auditLogMan.message = Reason
|
||||
auditLogMan.logSeqNo = Number
|
||||
auditLogMan.logSubMsg = Sub Message
|
||||
auditLogMan.logType.access = ACCESS
|
||||
|
||||
@@ -1674,7 +1674,6 @@ screen.lastLogin = Last LoginTime
|
||||
screen.logout = Logout
|
||||
screen.logoutMsg = Are you sure you want to log out of EMS System?
|
||||
screen.title = EAI Monitoring System
|
||||
screen.sitemap = Sitemap
|
||||
|
||||
search.period = Inquiry Period
|
||||
|
||||
|
||||
@@ -202,7 +202,6 @@ apiScpMan.title = API-SCOPE \uB9F5\uD551
|
||||
|
||||
auditLogMan.command = Command
|
||||
auditLogMan.logMsg = \uBA54\uC2DC\uC9C0
|
||||
auditLogMan.message = \uC0AC\uC720
|
||||
auditLogMan.logSeqNo = \uBC88\uD638
|
||||
auditLogMan.logSubMsg = \uC11C\uBE0C \uBA54\uC2DC\uC9C0
|
||||
auditLogMan.logType.access = \uC811\uC18D
|
||||
@@ -1771,7 +1770,6 @@ screen.lastLogin = \uB9C8\uC9C0\uB9C9 \uB85C\uADF8\uC778
|
||||
screen.logout = \uB85C\uADF8\uC544\uC6C3
|
||||
screen.logoutMsg = EMS Monitoring System \uC5D0\uC11C \uB85C\uADF8\uC544\uC6C3 \uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C ?
|
||||
screen.title = \uC778\uD130\uD398\uC774\uC2A4 \uD1B5\uD569\uBAA8\uB2C8\uD130\uB9C1
|
||||
screen.sitemap = \uC0AC\uC774\uD2B8\uB9F5
|
||||
|
||||
search.period = \uC870\uD68C\uAE30\uAC04
|
||||
|
||||
|
||||
Reference in New Issue
Block a user