Merge branch 'dev' into test
This commit is contained in:
@@ -0,0 +1,74 @@
|
|||||||
|
CREATE TABLE "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"
|
||||||
|
(
|
||||||
|
"ID" BIGINT NOT NULL,
|
||||||
|
"TRACE_ID" VARCHAR(64) DEFAULT NULL,
|
||||||
|
"API_CODE" VARCHAR(128) DEFAULT NULL,
|
||||||
|
"API_VERSION" VARCHAR(32) DEFAULT NULL,
|
||||||
|
"REQUEST_METHOD" VARCHAR(16) DEFAULT NULL,
|
||||||
|
"REQUEST_PATH" VARCHAR(512) DEFAULT NULL,
|
||||||
|
"REQUEST_QUERY" TEXT,
|
||||||
|
"REQUEST_HEADERS" TEXT,
|
||||||
|
"REQUEST_BODY" TEXT,
|
||||||
|
"RESPONSE_STATUS" INT DEFAULT NULL,
|
||||||
|
"RESPONSE_MESSAGE" VARCHAR(500) DEFAULT NULL,
|
||||||
|
"RESPONSE_BODY" TEXT,
|
||||||
|
"STATUS" SMALLINT DEFAULT 3 NOT NULL,
|
||||||
|
"ERROR_CODE" VARCHAR(100) DEFAULT NULL,
|
||||||
|
"ERROR_MESSAGE" VARCHAR(1000) DEFAULT NULL,
|
||||||
|
"EXCEPTION_STACK" TEXT,
|
||||||
|
"CLIENT_IP" VARCHAR(64) DEFAULT NULL,
|
||||||
|
"USER_AGENT" VARCHAR(512) DEFAULT NULL,
|
||||||
|
"DURATION" BIGINT DEFAULT NULL,
|
||||||
|
"REQUEST_TIME" DATETIME(6) DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||||
|
"RESPONSE_TIME" DATETIME(6) DEFAULT NULL,
|
||||||
|
"STEP_RESULTS" TEXT,
|
||||||
|
"EXTRA" TEXT,
|
||||||
|
"CREATOR" VARCHAR(64) DEFAULT '' NOT NULL,
|
||||||
|
"CREATE_TIME" DATETIME(6) DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||||
|
"UPDATER" VARCHAR(64) DEFAULT '' NOT NULL,
|
||||||
|
"UPDATE_TIME" DATETIME(6) DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||||
|
"DELETED" BIT DEFAULT '0' NOT NULL,
|
||||||
|
"TENANT_ID" BIGINT DEFAULT 0 NOT NULL,
|
||||||
|
NOT CLUSTER PRIMARY KEY("ID")) STORAGE(ON "MAIN", CLUSTERBTR) ;
|
||||||
|
|
||||||
|
COMMENT ON TABLE "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG IS 'Databus API 访问日志表';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."API_CODE" IS 'API 编码';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."API_VERSION" IS 'API 版本';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."CLIENT_IP" IS '客户端 IP';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."CREATE_TIME" IS '创建时间';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."CREATOR" IS '创建者';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."DELETED" IS '是否删除';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."DURATION" IS '请求耗时(毫秒)';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."ERROR_CODE" IS '业务错误码';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."ERROR_MESSAGE" IS '错误信息';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."EXCEPTION_STACK" IS '异常堆栈';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."EXTRA" IS '额外调试信息(JSON 字符串)';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."ID" IS '日志主键';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."REQUEST_BODY" IS '请求体(JSON 字符串)';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."REQUEST_HEADERS" IS '请求头(JSON 字符串)';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."REQUEST_METHOD" IS '请求方法';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."REQUEST_PATH" IS '请求路径';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."REQUEST_QUERY" IS '请求查询参数(JSON 字符串)';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."REQUEST_TIME" IS '请求时间';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."RESPONSE_BODY" IS '响应体(JSON 字符串)';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."RESPONSE_MESSAGE" IS '响应提示信息';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."RESPONSE_STATUS" IS '响应 HTTP 状态码';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."RESPONSE_TIME" IS '响应时间';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."STATUS" IS '访问状态:0-成功 1-客户端错误 2-服务端错误 3-未知';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."STEP_RESULTS" IS '执行步骤结果(JSON 字符串)';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."TENANT_ID" IS '租户编号';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."TRACE_ID" IS '追踪 ID';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."UPDATER" IS '更新者';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."UPDATE_TIME" IS '更新时间';
|
||||||
|
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."USER_AGENT" IS 'User-Agent';
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_TRACE" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("TRACE_ID" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
|
||||||
|
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_CODE" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("API_CODE" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
|
||||||
|
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_METHOD" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("REQUEST_METHOD" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
|
||||||
|
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_STATUS" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("STATUS" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
|
||||||
|
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_RESP_STATUS" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("RESPONSE_STATUS" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
|
||||||
|
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_REQUEST_TIME" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("REQUEST_TIME" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
|
||||||
|
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_CLIENT_IP" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("CLIENT_IP" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
|
||||||
|
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_TENANT" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("TENANT_ID" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
|
||||||
|
|
||||||
|
|||||||
@@ -182,8 +182,10 @@ public class BusinessDeptHandleUtil {
|
|||||||
if (loginUser != null) {
|
if (loginUser != null) {
|
||||||
loginUser.setVisitCompanyId(Long.valueOf(info.getCompanyId()));
|
loginUser.setVisitCompanyId(Long.valueOf(info.getCompanyId()));
|
||||||
loginUser.setVisitCompanyName(info.getCompanyName());
|
loginUser.setVisitCompanyName(info.getCompanyName());
|
||||||
|
loginUser.setVisitCompanyCode(info.getCompanyName());
|
||||||
loginUser.setVisitDeptId(Long.valueOf(info.getDeptId()));
|
loginUser.setVisitDeptId(Long.valueOf(info.getDeptId()));
|
||||||
loginUser.setVisitDeptName(info.getDeptName());
|
loginUser.setVisitDeptName(info.getDeptName());
|
||||||
|
loginUser.setVisitDeptCode(info.getDeptName());
|
||||||
}
|
}
|
||||||
request.setAttribute(WebFrameworkUtils.HEADER_VISIT_COMPANY_ID, info.getCompanyId());
|
request.setAttribute(WebFrameworkUtils.HEADER_VISIT_COMPANY_ID, info.getCompanyId());
|
||||||
if (info.getCompanyName() != null) {
|
if (info.getCompanyName() != null) {
|
||||||
|
|||||||
@@ -73,9 +73,11 @@ public class LoginUser {
|
|||||||
|
|
||||||
private Long visitCompanyId;
|
private Long visitCompanyId;
|
||||||
private String visitCompanyName;
|
private String visitCompanyName;
|
||||||
|
private String visitCompanyCode;
|
||||||
|
|
||||||
private Long visitDeptId;
|
private Long visitDeptId;
|
||||||
private String visitDeptName;
|
private String visitDeptName;
|
||||||
|
private String visitDeptCode;
|
||||||
|
|
||||||
public void setContext(String key, Object value) {
|
public void setContext(String key, Object value) {
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
<springProperty scope="context" name="zt.info.base-package" source="zt.info.base-package"/>
|
<springProperty scope="context" name="zt.info.base-package" source="zt.info.base-package"/>
|
||||||
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
|
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
|
||||||
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread [%tid]) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread [%tid]) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
||||||
|
<!--应用名称-->
|
||||||
|
<springProperty scope="context" name="spring.application.name" source="spring.application.name"/>
|
||||||
|
<!-- 日志输出路径 -->
|
||||||
|
<property name="LOG_DIR" value="${user.home}/logs/${spring.application.name}"/>
|
||||||
|
|
||||||
<!-- 控制台 Appender -->
|
<!-- 控制台 Appender -->
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
@@ -56,11 +60,29 @@
|
|||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
|
<!-- ERROR 级别日志 -->
|
||||||
|
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_DIR}-error.log</file>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>ERROR</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_DIR}-error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<maxHistory>30</maxHistory> <!-- 保留30天的日志 -->
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
<!--logback的日志级别 FATAL > ERROR > WARN > INFO > DEBUG-->
|
<!--logback的日志级别 FATAL > ERROR > WARN > INFO > DEBUG-->
|
||||||
<!-- 本地环境 -->
|
<!-- 本地环境 -->
|
||||||
<springProfile name="local,dev">
|
<springProfile name="local,dev">
|
||||||
<root level="WARN">
|
<root level="WARN">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="ERROR"/>
|
||||||
<appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
|
<appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
|
||||||
<appender-ref ref="ASYNC"/> <!-- 本地环境下,如果不想打印日志,可以注释掉本行 -->
|
<appender-ref ref="ASYNC"/> <!-- 本地环境下,如果不想打印日志,可以注释掉本行 -->
|
||||||
</root>
|
</root>
|
||||||
@@ -70,6 +92,7 @@
|
|||||||
<springProfile name="dev,test,stage,prod,default">
|
<springProfile name="dev,test,stage,prod,default">
|
||||||
<root level="INFO">
|
<root level="INFO">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="ERROR"/>
|
||||||
<appender-ref ref="ASYNC"/>
|
<appender-ref ref="ASYNC"/>
|
||||||
<appender-ref ref="GRPC"/>
|
<appender-ref ref="GRPC"/>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
<springProperty scope="context" name="zt.info.base-package" source="zt.info.base-package"/>
|
<springProperty scope="context" name="zt.info.base-package" source="zt.info.base-package"/>
|
||||||
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
|
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
|
||||||
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread [%tid]) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread [%tid]) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
||||||
|
<!--应用名称-->
|
||||||
|
<springProperty scope="context" name="spring.application.name" source="spring.application.name"/>
|
||||||
|
<!-- 日志输出路径 -->
|
||||||
|
<property name="LOG_DIR" value="${user.home}/logs/${spring.application.name}"/>
|
||||||
|
|
||||||
<!-- 控制台 Appender -->
|
<!-- 控制台 Appender -->
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
@@ -56,11 +60,29 @@
|
|||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
|
<!-- ERROR 级别日志 -->
|
||||||
|
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_DIR}-error.log</file>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>ERROR</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_DIR}-error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<maxHistory>30</maxHistory> <!-- 保留30天的日志 -->
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
<!--logback的日志级别 FATAL > ERROR > WARN > INFO > DEBUG-->
|
<!--logback的日志级别 FATAL > ERROR > WARN > INFO > DEBUG-->
|
||||||
<!-- 本地环境 -->
|
<!-- 本地环境 -->
|
||||||
<springProfile name="local,dev">
|
<springProfile name="local,dev">
|
||||||
<root level="WARN">
|
<root level="WARN">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="ERROR"/>
|
||||||
<appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
|
<appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
|
||||||
<appender-ref ref="ASYNC"/> <!-- 本地环境下,如果不想打印日志,可以注释掉本行 -->
|
<appender-ref ref="ASYNC"/> <!-- 本地环境下,如果不想打印日志,可以注释掉本行 -->
|
||||||
</root>
|
</root>
|
||||||
@@ -75,6 +97,7 @@
|
|||||||
<springProfile name="dev,test,stage,prod,default">
|
<springProfile name="dev,test,stage,prod,default">
|
||||||
<root level="INFO">
|
<root level="INFO">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="ERROR"/>
|
||||||
<appender-ref ref="ASYNC"/>
|
<appender-ref ref="ASYNC"/>
|
||||||
<appender-ref ref="GRPC"/>
|
<appender-ref ref="GRPC"/>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
<springProperty scope="context" name="zt.info.base-package" source="zt.info.base-package"/>
|
<springProperty scope="context" name="zt.info.base-package" source="zt.info.base-package"/>
|
||||||
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
|
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
|
||||||
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread [%tid]) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread [%tid]) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
||||||
|
<!--应用名称-->
|
||||||
|
<springProperty scope="context" name="spring.application.name" source="spring.application.name"/>
|
||||||
|
<!-- 日志输出路径 -->
|
||||||
|
<property name="LOG_DIR" value="${user.home}/logs/${spring.application.name}"/>
|
||||||
|
|
||||||
<!-- 控制台 Appender -->
|
<!-- 控制台 Appender -->
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
@@ -56,11 +60,29 @@
|
|||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
|
<!-- ERROR 级别日志 -->
|
||||||
|
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_DIR}-error.log</file>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>ERROR</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_DIR}-error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<maxHistory>30</maxHistory> <!-- 保留30天的日志 -->
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
<!--logback的日志级别 FATAL > ERROR > WARN > INFO > DEBUG-->
|
<!--logback的日志级别 FATAL > ERROR > WARN > INFO > DEBUG-->
|
||||||
<!-- 本地环境 -->
|
<!-- 本地环境 -->
|
||||||
<springProfile name="local,dev">
|
<springProfile name="local,dev">
|
||||||
<root level="WARN">
|
<root level="WARN">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="ERROR"/>
|
||||||
<appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
|
<appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
|
||||||
<appender-ref ref="ASYNC"/> <!-- 本地环境下,如果不想打印日志,可以注释掉本行 -->
|
<appender-ref ref="ASYNC"/> <!-- 本地环境下,如果不想打印日志,可以注释掉本行 -->
|
||||||
</root>
|
</root>
|
||||||
@@ -75,6 +97,7 @@
|
|||||||
<springProfile name="dev,test,stage,prod,default">
|
<springProfile name="dev,test,stage,prod,default">
|
||||||
<root level="INFO">
|
<root level="INFO">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="ERROR"/>
|
||||||
<appender-ref ref="ASYNC"/>
|
<appender-ref ref="ASYNC"/>
|
||||||
<appender-ref ref="GRPC"/>
|
<appender-ref ref="GRPC"/>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
<springProperty scope="context" name="zt.info.base-package" source="zt.info.base-package"/>
|
<springProperty scope="context" name="zt.info.base-package" source="zt.info.base-package"/>
|
||||||
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
|
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
|
||||||
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread [%tid]) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread [%tid]) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
||||||
|
<!--应用名称-->
|
||||||
|
<springProperty scope="context" name="spring.application.name" source="spring.application.name"/>
|
||||||
|
<!-- 日志输出路径 -->
|
||||||
|
<property name="LOG_DIR" value="${user.home}/logs/${spring.application.name}"/>
|
||||||
|
|
||||||
<!-- 控制台 Appender -->
|
<!-- 控制台 Appender -->
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
@@ -56,11 +60,29 @@
|
|||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
|
<!-- ERROR 级别日志 -->
|
||||||
|
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_DIR}-error.log</file>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>ERROR</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_DIR}-error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<maxHistory>30</maxHistory> <!-- 保留30天的日志 -->
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
<!--logback的日志级别 FATAL > ERROR > WARN > INFO > DEBUG-->
|
<!--logback的日志级别 FATAL > ERROR > WARN > INFO > DEBUG-->
|
||||||
<!-- 本地环境 -->
|
<!-- 本地环境 -->
|
||||||
<springProfile name="local,dev">
|
<springProfile name="local,dev">
|
||||||
<root level="WARN">
|
<root level="WARN">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="ERROR"/>
|
||||||
<appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
|
<appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
|
||||||
<appender-ref ref="ASYNC"/> <!-- 本地环境下,如果不想打印日志,可以注释掉本行 -->
|
<appender-ref ref="ASYNC"/> <!-- 本地环境下,如果不想打印日志,可以注释掉本行 -->
|
||||||
</root>
|
</root>
|
||||||
@@ -75,6 +97,7 @@
|
|||||||
<springProfile name="dev,test,stage,prod,default">
|
<springProfile name="dev,test,stage,prod,default">
|
||||||
<root level="INFO">
|
<root level="INFO">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="ERROR"/>
|
||||||
<appender-ref ref="ASYNC"/>
|
<appender-ref ref="ASYNC"/>
|
||||||
<appender-ref ref="GRPC"/>
|
<appender-ref ref="GRPC"/>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
<springProperty scope="context" name="zt.info.base-package" source="zt.info.base-package"/>
|
<springProperty scope="context" name="zt.info.base-package" source="zt.info.base-package"/>
|
||||||
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
|
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
|
||||||
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread [%tid]) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread [%tid]) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
||||||
|
<!--应用名称-->
|
||||||
|
<springProperty scope="context" name="spring.application.name" source="spring.application.name"/>
|
||||||
|
<!-- 日志输出路径 -->
|
||||||
|
<property name="LOG_DIR" value="${user.home}/logs/${spring.application.name}"/>
|
||||||
|
|
||||||
<!-- 控制台 Appender -->
|
<!-- 控制台 Appender -->
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
@@ -56,11 +60,29 @@
|
|||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
|
<!-- ERROR 级别日志 -->
|
||||||
|
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_DIR}-error.log</file>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>ERROR</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_DIR}-error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<maxHistory>30</maxHistory> <!-- 保留30天的日志 -->
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
<!--logback的日志级别 FATAL > ERROR > WARN > INFO > DEBUG-->
|
<!--logback的日志级别 FATAL > ERROR > WARN > INFO > DEBUG-->
|
||||||
<!-- 本地环境 -->
|
<!-- 本地环境 -->
|
||||||
<springProfile name="local,dev">
|
<springProfile name="local,dev">
|
||||||
<root level="WARN">
|
<root level="WARN">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="ERROR"/>
|
||||||
<appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
|
<appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
|
||||||
<appender-ref ref="ASYNC"/> <!-- 本地环境下,如果不想打印日志,可以注释掉本行 -->
|
<appender-ref ref="ASYNC"/> <!-- 本地环境下,如果不想打印日志,可以注释掉本行 -->
|
||||||
</root>
|
</root>
|
||||||
@@ -75,6 +97,7 @@
|
|||||||
<springProfile name="dev,test,stage,prod,default">
|
<springProfile name="dev,test,stage,prod,default">
|
||||||
<root level="INFO">
|
<root level="INFO">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="ERROR"/>
|
||||||
<appender-ref ref="ASYNC"/>
|
<appender-ref ref="ASYNC"/>
|
||||||
<appender-ref ref="GRPC"/>
|
<appender-ref ref="GRPC"/>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -1,228 +0,0 @@
|
|||||||
package com.zt.plat.module.system.service.integration.iwork.impl;
|
|
||||||
|
|
||||||
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkDetailRecordVO;
|
|
||||||
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkDetailTableVO;
|
|
||||||
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkFormFieldVO;
|
|
||||||
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkOperationRespVO;
|
|
||||||
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkUserInfoReqVO;
|
|
||||||
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkUserInfoRespVO;
|
|
||||||
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkWorkflowCreateReqVO;
|
|
||||||
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkWorkflowVoidReqVO;
|
|
||||||
import com.zt.plat.module.system.framework.integration.iwork.config.IWorkProperties;
|
|
||||||
import com.zt.plat.module.system.service.integration.iwork.IWorkIntegrationService;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import okhttp3.mockwebserver.MockResponse;
|
|
||||||
import okhttp3.mockwebserver.MockWebServer;
|
|
||||||
import okhttp3.mockwebserver.RecordedRequest;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.web.reactive.function.client.WebClient;
|
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.security.KeyFactory;
|
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.KeyPairGenerator;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.spec.X509EncodedKeySpec;
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
class IWorkIntegrationServiceImplTest {
|
|
||||||
|
|
||||||
private static KeyPair serverKeyPair;
|
|
||||||
private static String serverPublicKeyBase64;
|
|
||||||
private static String clientPublicKeyBase64;
|
|
||||||
|
|
||||||
private MockWebServer mockWebServer;
|
|
||||||
private IWorkIntegrationService integrationService;
|
|
||||||
private IWorkProperties properties;
|
|
||||||
|
|
||||||
@BeforeAll
|
|
||||||
static void initKeys() throws Exception {
|
|
||||||
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
|
|
||||||
generator.initialize(1024);
|
|
||||||
serverKeyPair = generator.generateKeyPair();
|
|
||||||
serverPublicKeyBase64 = Base64.getEncoder().encodeToString(serverKeyPair.getPublic().getEncoded());
|
|
||||||
|
|
||||||
KeyPair clientKeyPair = generator.generateKeyPair();
|
|
||||||
clientPublicKeyBase64 = Base64.getEncoder().encodeToString(clientKeyPair.getPublic().getEncoded());
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() throws Exception {
|
|
||||||
mockWebServer = new MockWebServer();
|
|
||||||
mockWebServer.start();
|
|
||||||
|
|
||||||
properties = buildProperties();
|
|
||||||
WebClient.Builder builder = WebClient.builder();
|
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
integrationService = new IWorkIntegrationServiceImpl(properties, objectMapper, builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
void tearDown() throws Exception {
|
|
||||||
mockWebServer.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testWorkflowLifecycle() throws Exception {
|
|
||||||
enqueueRegisterResponse();
|
|
||||||
enqueueApplyTokenResponse();
|
|
||||||
enqueueJsonResponse("{\"code\":1,\"userid\":\"1001\",\"msg\":\"OK\"}");
|
|
||||||
enqueueJsonResponse("{\"code\":\"1\",\"requestid\":\"REQ-001\",\"msg\":\"created\"}");
|
|
||||||
enqueueJsonResponse("{\"code\":\"1\",\"msg\":\"voided\"}");
|
|
||||||
|
|
||||||
IWorkUserInfoReqVO userReq = new IWorkUserInfoReqVO();
|
|
||||||
userReq.setIdentifierKey("loginid");
|
|
||||||
userReq.setIdentifierValue("zhangsan");
|
|
||||||
|
|
||||||
IWorkUserInfoRespVO userResp = integrationService.resolveUserId(userReq);
|
|
||||||
assertThat(userResp.isSuccess()).isTrue();
|
|
||||||
assertThat(userResp.getUserId()).isEqualTo("1001");
|
|
||||||
|
|
||||||
IWorkWorkflowCreateReqVO createReq = buildCreateRequest();
|
|
||||||
IWorkOperationRespVO createResp = integrationService.createWorkflow(createReq);
|
|
||||||
assertThat(createResp.isSuccess()).isTrue();
|
|
||||||
assertThat(createResp.getPayload().get("requestid")).isEqualTo("REQ-001");
|
|
||||||
|
|
||||||
IWorkWorkflowVoidReqVO voidReq = new IWorkWorkflowVoidReqVO();
|
|
||||||
voidReq.setRequestId("REQ-001");
|
|
||||||
voidReq.setReason("testing void");
|
|
||||||
IWorkOperationRespVO voidResp = integrationService.voidWorkflow(voidReq);
|
|
||||||
assertThat(voidResp.isSuccess()).isTrue();
|
|
||||||
|
|
||||||
verifyRegisterRequest(mockWebServer.takeRequest());
|
|
||||||
verifyApplyTokenRequest(mockWebServer.takeRequest());
|
|
||||||
verifyUserInfoRequest(mockWebServer.takeRequest());
|
|
||||||
verifyCreateRequest(mockWebServer.takeRequest());
|
|
||||||
verifyVoidRequest(mockWebServer.takeRequest());
|
|
||||||
|
|
||||||
assertThat(mockWebServer.getRequestCount()).isEqualTo(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IWorkProperties buildProperties() {
|
|
||||||
IWorkProperties properties = new IWorkProperties();
|
|
||||||
properties.setEnabled(true);
|
|
||||||
properties.setBaseUrl(mockWebServer.url("/").toString());
|
|
||||||
properties.setAppId("test-app");
|
|
||||||
properties.setClientPublicKey(clientPublicKeyBase64);
|
|
||||||
properties.setUserId("1");
|
|
||||||
properties.setWorkflowId(54L);
|
|
||||||
properties.getToken().setTtlSeconds(3600L);
|
|
||||||
properties.getToken().setRefreshAheadSeconds(30L);
|
|
||||||
properties.getClient().setResponseTimeout(Duration.ofSeconds(5));
|
|
||||||
|
|
||||||
properties.getPaths().setRegister("/api/ec/dev/auth/regist");
|
|
||||||
properties.getPaths().setApplyToken("/api/ec/dev/auth/applytoken");
|
|
||||||
properties.getPaths().setUserInfo("/api/workflow/paService/getUserInfo");
|
|
||||||
properties.getPaths().setCreateWorkflow("/api/workflow/paService/doCreateRequest");
|
|
||||||
properties.getPaths().setVoidWorkflow("/api/workflow/paService/doCancelRequest");
|
|
||||||
|
|
||||||
properties.getClient().setConnectTimeout(Duration.ofSeconds(5));
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyRegisterRequest(RecordedRequest request) {
|
|
||||||
assertThat(request.getPath()).isEqualTo("/api/ec/dev/auth/regist");
|
|
||||||
assertThat(request.getHeader(properties.getHeaders().getAppId())).isEqualTo("test-app");
|
|
||||||
assertThat(request.getHeader(properties.getHeaders().getClientPublicKey())).isEqualTo(clientPublicKeyBase64);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyApplyTokenRequest(RecordedRequest request) throws Exception {
|
|
||||||
assertThat(request.getPath()).isEqualTo("/api/ec/dev/auth/applytoken");
|
|
||||||
assertThat(request.getHeader(properties.getHeaders().getAppId())).isEqualTo("test-app");
|
|
||||||
assertThat(request.getHeader(properties.getHeaders().getTime())).isEqualTo("3600");
|
|
||||||
String decryptedSecret = decryptHeader(request.getHeader(properties.getHeaders().getSecret()));
|
|
||||||
assertThat(decryptedSecret).isEqualTo("plain-secret");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyUserInfoRequest(RecordedRequest request) throws Exception {
|
|
||||||
assertThat(request.getPath()).isEqualTo("/api/workflow/paService/getUserInfo");
|
|
||||||
assertThat(request.getHeader(properties.getHeaders().getToken())).isEqualTo("token-123");
|
|
||||||
String decryptedUserId = decryptHeader(request.getHeader(properties.getHeaders().getUserId()));
|
|
||||||
assertThat(decryptedUserId).isEqualTo("1");
|
|
||||||
String body = request.getBody().readUtf8();
|
|
||||||
assertThat(body).contains("loginid");
|
|
||||||
assertThat(body).contains("zhangsan");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyCreateRequest(RecordedRequest request) throws Exception {
|
|
||||||
assertThat(request.getPath()).isEqualTo("/api/workflow/paService/doCreateRequest");
|
|
||||||
assertThat(request.getHeader(properties.getHeaders().getToken())).isEqualTo("token-123");
|
|
||||||
String decryptedUserId = decryptHeader(request.getHeader(properties.getHeaders().getUserId()));
|
|
||||||
assertThat(decryptedUserId).isEqualTo("1");
|
|
||||||
String body = request.getBody().readUtf8();
|
|
||||||
assertThat(body).contains("requestName=测试流程");
|
|
||||||
assertThat(body).contains("workflowId=54");
|
|
||||||
assertThat(body).contains("mainData=%5B");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyVoidRequest(RecordedRequest request) throws Exception {
|
|
||||||
assertThat(request.getPath()).isEqualTo("/api/workflow/paService/doCancelRequest");
|
|
||||||
assertThat(request.getHeader(properties.getHeaders().getToken())).isEqualTo("token-123");
|
|
||||||
String decryptedUserId = decryptHeader(request.getHeader(properties.getHeaders().getUserId()));
|
|
||||||
assertThat(decryptedUserId).isEqualTo("1");
|
|
||||||
String body = request.getBody().readUtf8();
|
|
||||||
assertThat(body).contains("requestId=REQ-001");
|
|
||||||
assertThat(body).contains("remark=testing+void");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enqueueRegisterResponse() {
|
|
||||||
enqueueJsonResponse("{" +
|
|
||||||
"\"secret\":\"plain-secret\"," +
|
|
||||||
"\"spk\":\"" + serverPublicKeyBase64 + "\"}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enqueueApplyTokenResponse() {
|
|
||||||
enqueueJsonResponse("{\"token\":\"token-123\",\"expire\":3600}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enqueueJsonResponse(String body) {
|
|
||||||
mockWebServer.enqueue(new MockResponse()
|
|
||||||
.setHeader("Content-Type", "application/json")
|
|
||||||
.setBody(body));
|
|
||||||
}
|
|
||||||
|
|
||||||
private IWorkWorkflowCreateReqVO buildCreateRequest() {
|
|
||||||
IWorkFormFieldVO field1 = new IWorkFormFieldVO();
|
|
||||||
field1.setFieldName("sqr");
|
|
||||||
field1.setFieldValue("张三");
|
|
||||||
|
|
||||||
IWorkFormFieldVO field2 = new IWorkFormFieldVO();
|
|
||||||
field2.setFieldName("sqrq");
|
|
||||||
field2.setFieldValue("2023-11-02");
|
|
||||||
|
|
||||||
IWorkDetailRecordVO detailRecord = new IWorkDetailRecordVO();
|
|
||||||
detailRecord.setRecordOrder(0);
|
|
||||||
IWorkFormFieldVO detailField = new IWorkFormFieldVO();
|
|
||||||
detailField.setFieldName("ddh");
|
|
||||||
detailField.setFieldValue("100010");
|
|
||||||
detailRecord.setFields(List.of(detailField));
|
|
||||||
|
|
||||||
IWorkDetailTableVO detailTable = new IWorkDetailTableVO();
|
|
||||||
detailTable.setTableDBName("formtable_main_26_dt1");
|
|
||||||
detailTable.setRecords(List.of(detailRecord));
|
|
||||||
|
|
||||||
IWorkWorkflowCreateReqVO req = new IWorkWorkflowCreateReqVO();
|
|
||||||
req.setRequestName("测试流程");
|
|
||||||
req.setMainFields(List.of(field1, field2));
|
|
||||||
req.setDetailTables(List.of(detailTable));
|
|
||||||
req.setOtherParams(Map.of("isnextflow", "0"));
|
|
||||||
return req;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String decryptHeader(String headerValue) throws Exception {
|
|
||||||
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
|
||||||
cipher.init(Cipher.DECRYPT_MODE, serverKeyPair.getPrivate());
|
|
||||||
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(headerValue));
|
|
||||||
return new String(decrypted, StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
package com.zt.plat.module.system.service.integration.iwork.impl;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrSubcompanyPageRespVO;
|
|
||||||
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrSyncRespVO;
|
|
||||||
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkOrgSyncReqVO;
|
|
||||||
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkSubcompanyQueryReqVO;
|
|
||||||
import com.zt.plat.module.system.framework.integration.iwork.config.IWorkProperties;
|
|
||||||
import com.zt.plat.module.system.service.integration.iwork.IWorkOrgRestService;
|
|
||||||
import okhttp3.mockwebserver.MockResponse;
|
|
||||||
import okhttp3.mockwebserver.MockWebServer;
|
|
||||||
import okhttp3.mockwebserver.RecordedRequest;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.util.DigestUtils;
|
|
||||||
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.time.Clock;
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.time.ZoneOffset;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
class IWorkOrgRestServiceImplTest {
|
|
||||||
|
|
||||||
private MockWebServer mockWebServer;
|
|
||||||
private IWorkOrgRestService service;
|
|
||||||
private IWorkProperties properties;
|
|
||||||
private Clock fixedClock;
|
|
||||||
private ObjectMapper objectMapper;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() throws Exception {
|
|
||||||
mockWebServer = new MockWebServer();
|
|
||||||
mockWebServer.start();
|
|
||||||
|
|
||||||
properties = buildProperties();
|
|
||||||
fixedClock = Clock.fixed(Instant.ofEpochMilli(1_672_531_200_000L), ZoneOffset.UTC);
|
|
||||||
objectMapper = new ObjectMapper();
|
|
||||||
service = new IWorkOrgRestServiceImpl(properties, objectMapper, fixedClock);
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
void tearDown() throws Exception {
|
|
||||||
mockWebServer.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldListSubcompanies() throws Exception {
|
|
||||||
mockWebServer.enqueue(jsonResponse("{\"code\":\"1\",\"data\":{\"totalSize\":1,\"totalPage\":1,\"pageSize\":10,\"pageNumber\":1,\"dataList\":[{\"subcompanyid1\":4,\"subcompanyname\":\"总部\"}]}}"));
|
|
||||||
|
|
||||||
IWorkSubcompanyQueryReqVO reqVO = new IWorkSubcompanyQueryReqVO();
|
|
||||||
reqVO.setParams(Map.of("curpage", 1));
|
|
||||||
IWorkHrSubcompanyPageRespVO respVO = service.listSubcompanies(reqVO);
|
|
||||||
|
|
||||||
assertThat(respVO.isSuccess()).isTrue();
|
|
||||||
assertThat(respVO.getTotalSize()).isEqualTo(1);
|
|
||||||
assertThat(respVO.getDataList()).hasSize(1);
|
|
||||||
assertThat(respVO.getDataList().get(0).getSubcompanyname()).isEqualTo("总部");
|
|
||||||
|
|
||||||
RecordedRequest request = mockWebServer.takeRequest();
|
|
||||||
assertThat(request.getPath()).isEqualTo(properties.getOrg().getPaths().getSubcompanyPage());
|
|
||||||
String decoded = URLDecoder.decode(request.getBody().readUtf8(), StandardCharsets.UTF_8);
|
|
||||||
JsonNode bodyNode = objectMapper.readTree(decoded);
|
|
||||||
assertThat(bodyNode.path("params").path("curpage").asInt()).isEqualTo(1);
|
|
||||||
JsonNode tokenNode = bodyNode.path("token");
|
|
||||||
assertThat(tokenNode.path("ts").asText()).isEqualTo("1672531200000");
|
|
||||||
String expectedKey = DigestUtils.md5DigestAsHex("test-seed1672531200000".getBytes(StandardCharsets.UTF_8)).toUpperCase();
|
|
||||||
assertThat(tokenNode.path("key").asText()).isEqualTo(expectedKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldSyncDepartments() throws Exception {
|
|
||||||
mockWebServer.enqueue(jsonResponse("{\"code\":\"1\",\"result\":[{\"@action\":\"add\",\"code\":\"demo\",\"result\":\"success\"}]}"));
|
|
||||||
|
|
||||||
IWorkOrgSyncReqVO reqVO = new IWorkOrgSyncReqVO();
|
|
||||||
reqVO.setData(List.of(Map.of("@action", "add", "code", "demo")));
|
|
||||||
IWorkHrSyncRespVO respVO = service.syncDepartments(reqVO);
|
|
||||||
|
|
||||||
assertThat(respVO.isSuccess()).isTrue();
|
|
||||||
assertThat(respVO.getResult()).hasSize(1);
|
|
||||||
assertThat(respVO.getResult().get(0).getCode()).isEqualTo("demo");
|
|
||||||
|
|
||||||
RecordedRequest request = mockWebServer.takeRequest();
|
|
||||||
assertThat(request.getPath()).isEqualTo(properties.getOrg().getPaths().getSyncDepartment());
|
|
||||||
String decoded = URLDecoder.decode(request.getBody().readUtf8(), StandardCharsets.UTF_8);
|
|
||||||
JsonNode bodyNode = objectMapper.readTree(decoded);
|
|
||||||
assertThat(bodyNode.path("data").isArray()).isTrue();
|
|
||||||
assertThat(bodyNode.path("data").get(0).path("code").asText()).isEqualTo("demo");
|
|
||||||
}
|
|
||||||
|
|
||||||
private MockResponse jsonResponse(String body) {
|
|
||||||
return new MockResponse()
|
|
||||||
.setHeader("Content-Type", "application/json")
|
|
||||||
.setBody(body);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IWorkProperties buildProperties() {
|
|
||||||
IWorkProperties properties = new IWorkProperties();
|
|
||||||
properties.setBaseUrl(mockWebServer.url("/").toString());
|
|
||||||
properties.getClient().setConnectTimeout(Duration.ofSeconds(5));
|
|
||||||
properties.getClient().setResponseTimeout(Duration.ofSeconds(5));
|
|
||||||
properties.getOrg().setTokenSeed("test-seed");
|
|
||||||
IWorkProperties.OrgPaths paths = properties.getOrg().getPaths();
|
|
||||||
paths.setSubcompanyPage("/api/hrm/resful/getHrmsubcompanyWithPage");
|
|
||||||
paths.setDepartmentPage("/api/hrm/resful/getHrmdepartmentWithPage");
|
|
||||||
paths.setJobTitlePage("/api/hrm/resful/getJobtitleInfoWithPage");
|
|
||||||
paths.setUserPage("/api/hrm/resful/getHrmUserInfoWithPage");
|
|
||||||
paths.setSyncSubcompany("/api/hrm/resful/synSubcompany");
|
|
||||||
paths.setSyncDepartment("/api/hrm/resful/synDepartment");
|
|
||||||
paths.setSyncJobTitle("/api/hrm/resful/synJobtitle");
|
|
||||||
paths.setSyncUser("/api/hrm/resful/synHrmresource");
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user