init commit.
This commit is contained in:
31
orion-ops-framework/orion-ops-common/pom.xml
Normal file
31
orion-ops-framework/orion-ops-common/pom.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.orion.ops</groupId>
|
||||
<artifactId>orion-ops-framework</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>orion-ops-common</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<description>项目公共基准包</description>
|
||||
<url>https://github.com/lijiahangmax/orion-ops-pro</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.github.lijiahangmax</groupId>
|
||||
<artifactId>orion-all</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.orion.ops.framework.common.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 不执行统一日志打印
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2022/4/20 10:33
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface IgnoreLog {
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.orion.ops.framework.common.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 无需包装返回
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2021/4/2 10:36
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface IgnoreWrapper {
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.orion.ops.framework.common.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 统一返回包装
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2021/4/2 12:34
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RestWrapper {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.orion.ops.framework.common.enums;
|
||||
|
||||
/**
|
||||
* 消息常量
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2021/6/4 18:26
|
||||
*/
|
||||
public interface ExceptionMessageConst {
|
||||
|
||||
String INVALID_PARAM = "非法参数";
|
||||
|
||||
String OPERATOR_ERROR = "操作失败";
|
||||
|
||||
String HTTP_API = "api 调用异常";
|
||||
|
||||
String NETWORK_FLUCTUATION = "当前环境网路波动";
|
||||
|
||||
String OPEN_TEMPLATE_ERROR = "模板解析失败 请检查模板和密码";
|
||||
|
||||
String PARSE_TEMPLATE_DATA_ERROR = "模板解析失败 请检查模板数据";
|
||||
|
||||
String REPOSITORY_OPERATOR_ERROR = "应用版本仓库操作执行失败";
|
||||
|
||||
String TASK_ERROR = "任务执行异常";
|
||||
|
||||
String CONNECT_ERROR = "建立连接失败";
|
||||
|
||||
String TIMEOUT_ERROR = "处理超时";
|
||||
|
||||
String INTERRUPT_ERROR = "操作中断";
|
||||
|
||||
String UNSAFE_OPERATOR = "不安全的操作";
|
||||
|
||||
String ENCRYPT_ERROR = "数据加密异常";
|
||||
|
||||
String DECRYPT_ERROR = "数据解密异常";
|
||||
|
||||
String EXCEPTION_MESSAGE = "系统异常";
|
||||
|
||||
String IO_EXCEPTION_MESSAGE = "网络异常";
|
||||
|
||||
String SQL_EXCEPTION_MESSAGE = "数据异常";
|
||||
|
||||
String FILE_TOO_LARGE = "文件过大";
|
||||
|
||||
String ERROR_EXPRESSION = "表达式错误";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.orion.ops.framework.common.enums;
|
||||
|
||||
/**
|
||||
* 过滤器排序常量
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/6/16 17:04
|
||||
*/
|
||||
public interface FilterOrderConst {
|
||||
|
||||
int CORS_FILTER = Integer.MIN_VALUE;
|
||||
|
||||
int TRICE_ID_FILTER = Integer.MIN_VALUE + 10;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.orion.ops.framework.common.enums;
|
||||
|
||||
/**
|
||||
* 拦截器排序常量
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/6/16 18:15
|
||||
*/
|
||||
public interface InterceptorOrderConst {
|
||||
|
||||
int LOG_FILTER = Integer.MIN_VALUE;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.orion.ops.framework.common.enums;
|
||||
|
||||
/**
|
||||
* 项目常量
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/6/19 18:56
|
||||
*/
|
||||
public interface OrionOpsProConst {
|
||||
|
||||
String GITHUB = "https://github.com/lijiahangmax/orion-ops-pro";
|
||||
|
||||
String GITEE = "https://gitee.com/lijiahangmax/orion-ops-pro";
|
||||
|
||||
String ISSUES = "https://gitee.com/lijiahangmax/orion-ops-pro/issues";
|
||||
|
||||
String VERSION = "1.0.0";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.orion.ops.framework.common.meta;
|
||||
|
||||
/**
|
||||
* traceId 持有者
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/6/16 17:35
|
||||
*/
|
||||
public class TraceIdHolder {
|
||||
|
||||
private TraceIdHolder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求序列
|
||||
*/
|
||||
private static final ThreadLocal<String> HOLDER = new ThreadLocal<>();
|
||||
;
|
||||
|
||||
public static String get() {
|
||||
return HOLDER.get();
|
||||
}
|
||||
|
||||
public static void set(String traceId) {
|
||||
HOLDER.set(traceId);
|
||||
}
|
||||
|
||||
public static void remove() {
|
||||
HOLDER.remove();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
package com.orion.ops.framework.common.utils;
|
||||
|
||||
/**
|
||||
* ANSI 高亮颜色转义码
|
||||
* <p>
|
||||
* \u001B = \x1b = 27 = esc
|
||||
* <p>
|
||||
* 基本8色 基本高对比色 xterm 256 色
|
||||
* 30 ~ 37 90 ~ 97 0 ~ 256
|
||||
* <p>
|
||||
* \033[0m 关闭所有属性
|
||||
* \033[1m 设置高亮度
|
||||
* \033[4m 下划线
|
||||
* \033[5m 闪烁
|
||||
* \033[7m 反显
|
||||
* \033[8m 消隐
|
||||
* \033[30m 至 \33[37m 设置前景色
|
||||
* \033[40m 至 \33[47m 设置背景色
|
||||
* \033[nA 光标上移n行
|
||||
* \033[nB 光标下移n行
|
||||
* \033[nC 光标右移n行
|
||||
* \033[nD 光标左移n行
|
||||
* \033[y;xH 设置光标位置
|
||||
* \033[2J 清屏
|
||||
* \033[K 清除从光标到行尾的内容
|
||||
* \033[s 保存光标位置
|
||||
* \033[u 恢复光标位置
|
||||
* \033[?25l 隐藏光标
|
||||
* \033[?25h 显示光标
|
||||
* <p>
|
||||
* TODO 后续直接使用kit
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/6/20 10:51
|
||||
*/
|
||||
public enum AnsiCode {
|
||||
|
||||
/**
|
||||
* 黑色
|
||||
*/
|
||||
BLACK(30),
|
||||
|
||||
/**
|
||||
* 红色
|
||||
*/
|
||||
RED(31),
|
||||
|
||||
/**
|
||||
* 绿色
|
||||
*/
|
||||
GREEN(32),
|
||||
|
||||
/**
|
||||
* 黄色
|
||||
*/
|
||||
YELLOW(33),
|
||||
|
||||
/**
|
||||
* 蓝色
|
||||
*/
|
||||
BLUE(34),
|
||||
|
||||
/**
|
||||
* 紫色
|
||||
*/
|
||||
PURPLE(35),
|
||||
|
||||
/**
|
||||
* 青色
|
||||
*/
|
||||
CYAN(36),
|
||||
|
||||
/**
|
||||
* 白色
|
||||
*/
|
||||
WHITE(37),
|
||||
|
||||
// -------------------- 背景色 --------------------
|
||||
|
||||
/**
|
||||
* 黑色 背景色
|
||||
*/
|
||||
BG_BLACK(40),
|
||||
|
||||
/**
|
||||
* 红色 背景色
|
||||
*/
|
||||
BG_RED(41),
|
||||
|
||||
/**
|
||||
* 绿色 背景色
|
||||
*/
|
||||
BG_GREEN(42),
|
||||
|
||||
/**
|
||||
* 黄色 背景色
|
||||
*/
|
||||
BG_YELLOW(43),
|
||||
|
||||
/**
|
||||
* 蓝色 背景色
|
||||
*/
|
||||
BG_BLUE(44),
|
||||
|
||||
/**
|
||||
* 紫色 背景色
|
||||
*/
|
||||
BG_PURPLE(45),
|
||||
|
||||
/**
|
||||
* 青色 背景色
|
||||
*/
|
||||
BG_CYAN(46),
|
||||
|
||||
/**
|
||||
* 白色 背景色
|
||||
*/
|
||||
BG_WHITE(47),
|
||||
|
||||
// -------------------- 亮色 --------------------
|
||||
|
||||
/**
|
||||
* 亮黑色 (灰)
|
||||
*/
|
||||
GLOSS_BLACK(90),
|
||||
|
||||
/**
|
||||
* 亮红色
|
||||
*/
|
||||
GLOSS_RED(91),
|
||||
|
||||
/**
|
||||
* 亮绿色
|
||||
*/
|
||||
GLOSS_GREEN(92),
|
||||
|
||||
/**
|
||||
* 亮黄色
|
||||
*/
|
||||
GLOSS_YELLOW(93),
|
||||
|
||||
/**
|
||||
* 亮蓝色
|
||||
*/
|
||||
GLOSS_BLUE(94),
|
||||
|
||||
/**
|
||||
* 亮紫色
|
||||
*/
|
||||
GLOSS_PURPLE(95),
|
||||
|
||||
/**
|
||||
* 亮青色
|
||||
*/
|
||||
GLOSS_CYAN(96),
|
||||
|
||||
/**
|
||||
* 亮白色
|
||||
*/
|
||||
GLOSS_WHITE(97),
|
||||
|
||||
// -------------------- 亮背景色 --------------------
|
||||
|
||||
/**
|
||||
* 亮黑色 (灰) 背景色
|
||||
*/
|
||||
BG_GLOSS_BLACK(100),
|
||||
|
||||
/**
|
||||
* 亮红色 背景色
|
||||
*/
|
||||
BG_GLOSS_RED(101),
|
||||
|
||||
/**
|
||||
* 亮绿色 背景色
|
||||
*/
|
||||
BG_GLOSS_GREEN(102),
|
||||
|
||||
/**
|
||||
* 亮黄色 背景色
|
||||
*/
|
||||
BG_GLOSS_YELLOW(103),
|
||||
|
||||
/**
|
||||
* 亮蓝色 背景色
|
||||
*/
|
||||
BG_GLOSS_BLUE(104),
|
||||
|
||||
/**
|
||||
* 亮紫色 背景色
|
||||
*/
|
||||
BG_GLOSS_PURPLE(105),
|
||||
|
||||
/**
|
||||
* 亮青色 背景色
|
||||
*/
|
||||
BG_GLOSS_CYAN(106),
|
||||
|
||||
/**
|
||||
* 亮白色 背景色
|
||||
*/
|
||||
BG_GLOSS_WHITE(107),
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* 颜色码
|
||||
*/
|
||||
public final int code;
|
||||
|
||||
/**
|
||||
* 前缀
|
||||
*/
|
||||
public final String prefix;
|
||||
|
||||
/**
|
||||
* 后缀
|
||||
* \x1b[0m
|
||||
*/
|
||||
public static final String SUFFIX = (char) 27 + "[0m";
|
||||
|
||||
AnsiCode(int code) {
|
||||
this.code = code;
|
||||
this.prefix = getPrefix(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文字着色
|
||||
*
|
||||
* @param s s
|
||||
* @return s
|
||||
*/
|
||||
public String stain(String s) {
|
||||
return prefix + s + SUFFIX;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取颜色前缀
|
||||
* .e.g \x1b[31m
|
||||
*
|
||||
* @param code code
|
||||
* @return 前缀
|
||||
*/
|
||||
public static String getPrefix(int code) {
|
||||
return (char) 27 + "[" + code + "m";
|
||||
}
|
||||
|
||||
/**
|
||||
* 文字着色
|
||||
*
|
||||
* @param s s
|
||||
* @param code code
|
||||
* @return s
|
||||
*/
|
||||
public static String getStain(String s, int code) {
|
||||
return getPrefix(code) + s + SUFFIX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.orion.ops</groupId>
|
||||
<artifactId>orion-ops-framework</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>orion-ops-spring-boot-starter-banner</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<description>项目 banner 打印包</description>
|
||||
<url>https://github.com/lijiahangmax/orion-ops-pro</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.orion.ops</groupId>
|
||||
<artifactId>orion-ops-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.orion.ops.framework.banner.config;
|
||||
|
||||
import com.orion.ops.framework.banner.core.BannerApplicationRunner;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
* banner 自动配置类
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/6/15 16:16
|
||||
*/
|
||||
@AutoConfiguration
|
||||
public class OrionBannerAutoConfiguration {
|
||||
|
||||
/**
|
||||
* @return banner 打印器
|
||||
*/
|
||||
@Bean
|
||||
public BannerApplicationRunner bannerApplicationRunner() {
|
||||
return new BannerApplicationRunner();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.orion.ops.framework.banner.core;
|
||||
|
||||
import com.orion.ops.framework.common.utils.AnsiCode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
|
||||
/**
|
||||
* banner printer
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/6/15 16:18
|
||||
*/
|
||||
@Slf4j
|
||||
public class BannerApplicationRunner implements ApplicationRunner {
|
||||
|
||||
@Value("${spring.profiles.active}")
|
||||
private String env;
|
||||
|
||||
@Value("${orion.version}")
|
||||
private String version;
|
||||
|
||||
@Value("${server.port}")
|
||||
private String port;
|
||||
|
||||
@Value("${orion.api.prefix}")
|
||||
private String apiPrefix;
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) {
|
||||
String line = AnsiCode.GLOSS_GREEN.stain(":: orion-ops-server v" + version + " 服务已启动(" + env + ") ::\n") +
|
||||
AnsiCode.GLOSS_GREEN.stain(":: swagger 文档 ") +
|
||||
// TODO swagger 地址
|
||||
AnsiCode.GLOSS_BLUE.stain("http://127.0.0.1:xxxx/dox.html\n") +
|
||||
AnsiCode.GLOSS_GREEN.stain(":: server 心跳检测 ") +
|
||||
AnsiCode.GLOSS_BLUE +
|
||||
"curl -X GET --location \"http://127.0.0.1:" + port + apiPrefix + "/server/bootstrap/health\"" +
|
||||
AnsiCode.SUFFIX;
|
||||
System.out.println(line);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
com.orion.ops.framework.banner.config.OrionBannerAutoConfiguration
|
||||
@@ -0,0 +1,11 @@
|
||||
${AnsiColor.BRIGHT_GREEN} _ ${AnsiColor.BLUE}
|
||||
${AnsiColor.BRIGHT_GREEN} ____ _____(_)___ ____ ____ ____ _____ ${AnsiColor.BLUE} ____ _________
|
||||
${AnsiColor.BRIGHT_GREEN} / __ \/ ___/ / __ \/ __ \ / __ \/ __ \/ ___/ ${AnsiColor.BLUE} / __ \/ ___/ __ \
|
||||
${AnsiColor.BRIGHT_GREEN}/ /_/ / / / / /_/ / / / / / /_/ / /_/ (__ ) ${AnsiColor.BLUE} / /_/ / / / /_/ /
|
||||
${AnsiColor.BRIGHT_GREEN}\____/_/ /_/\____/_/ /_/ \____/ .___/____/ ${AnsiColor.BLUE} / .___/_/ \____/
|
||||
${AnsiColor.BRIGHT_GREEN} /_/ ${AnsiColor.BLUE} /_/
|
||||
|
||||
${AnsiColor.BRIGHT_GREEN}:: Application Name ${AnsiColor.BLUE}${spring.application.name}
|
||||
${AnsiColor.BRIGHT_GREEN}:: Application Version ${AnsiColor.BLUE}${orion.version}
|
||||
${AnsiColor.BRIGHT_GREEN}:: SpringBoot Version ${AnsiColor.BLUE}${spring-boot.version}
|
||||
${AnsiColor.BRIGHT_GREEN}:: Active Profile ${AnsiColor.BLUE}${spring.profiles.active}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.orion.ops</groupId>
|
||||
<artifactId>orion-ops-framework</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>orion-ops-spring-boot-starter-web</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<description>项目 web 包</description>
|
||||
<url>https://github.com/lijiahangmax/orion-ops-pro</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.orion.ops</groupId>
|
||||
<artifactId>orion-ops-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.orion.ops.framework.web.config;
|
||||
|
||||
import com.orion.ops.framework.common.enums.InterceptorOrderConst;
|
||||
import com.orion.ops.framework.web.core.interceptor.LogPrintInterceptor;
|
||||
import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
* 全局日志打印配置类
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/6/16 18:18
|
||||
*/
|
||||
@AutoConfiguration
|
||||
public class OrionLogPrinterConfiguration {
|
||||
|
||||
@Bean
|
||||
public LogPrintInterceptor logPrintInterceptor() {
|
||||
return new LogPrintInterceptor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AspectJExpressionPointcutAdvisor logPrinterAdvisor(LogPrintInterceptor logPrintInterceptor) {
|
||||
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
|
||||
advisor.setExpression("execution (* com.orion.ops.**.controller.*.*(..)) && !@annotation(com.orion.ops.framework.common.annotation.IgnoreLog)");
|
||||
advisor.setAdvice(logPrintInterceptor);
|
||||
advisor.setOrder(InterceptorOrderConst.LOG_FILTER);
|
||||
return advisor;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package com.orion.ops.framework.web.config;
|
||||
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||
import com.orion.lang.utils.collect.Lists;
|
||||
import com.orion.ops.framework.common.enums.FilterOrderConst;
|
||||
import com.orion.ops.framework.web.core.filter.TraceIdFilter;
|
||||
import com.orion.ops.framework.web.core.handler.GlobalExceptionHandler;
|
||||
import com.orion.ops.framework.web.core.handler.WrapperResultHandler;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* web 配置类
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/6/16 16:26
|
||||
*/
|
||||
@AutoConfiguration
|
||||
public class OrionWebAutoConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@Value("${orion.api.prefix}")
|
||||
private String orionApiPrefix;
|
||||
|
||||
// TODO XSS
|
||||
|
||||
@Override
|
||||
public void configurePathMatch(PathMatchConfigurer configurer) {
|
||||
// 公共 api 前缀
|
||||
configurer.addPathPrefix(orionApiPrefix, clazz -> clazz.isAnnotationPresent(RestController.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 全局异常处理器
|
||||
*/
|
||||
@Bean
|
||||
public GlobalExceptionHandler globalExceptionHandler() {
|
||||
return new GlobalExceptionHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 通用返回结果处理器
|
||||
*/
|
||||
@Bean
|
||||
public WrapperResultHandler wrapperResultHandler() {
|
||||
return new WrapperResultHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return http json 转换器
|
||||
*/
|
||||
@Bean
|
||||
public HttpMessageConverters fastJsonHttpMessageConverters() {
|
||||
// 转换器
|
||||
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
|
||||
// 配置
|
||||
FastJsonConfig config = new FastJsonConfig();
|
||||
// 支持的类型
|
||||
List<MediaType> mediaTypes = Lists.of(
|
||||
MediaType.APPLICATION_JSON,
|
||||
MediaType.APPLICATION_FORM_URLENCODED,
|
||||
MediaType.APPLICATION_XHTML_XML,
|
||||
MediaType.TEXT_PLAIN,
|
||||
MediaType.TEXT_HTML,
|
||||
MediaType.TEXT_XML
|
||||
);
|
||||
converter.setSupportedMediaTypes(mediaTypes);
|
||||
// 序列化配置
|
||||
config.setSerializerFeatures(
|
||||
SerializerFeature.DisableCircularReferenceDetect,
|
||||
SerializerFeature.WriteMapNullValue,
|
||||
SerializerFeature.WriteNullListAsEmpty,
|
||||
SerializerFeature.IgnoreNonFieldGetter
|
||||
);
|
||||
converter.setFastJsonConfig(config);
|
||||
return new HttpMessageConverters(converter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 跨域配置
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "orion.api.cors", havingValue = "true")
|
||||
public FilterRegistrationBean<CorsFilter> corsFilterBean() {
|
||||
// 跨域配置
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
config.setAllowCredentials(true);
|
||||
config.addAllowedOriginPattern("*");
|
||||
config.addAllowedMethod("*");
|
||||
config.addAllowedHeader("*");
|
||||
config.setMaxAge(3600L);
|
||||
// 创建 UrlBasedCorsConfigurationSource 对象
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
return createFilterBean(new CorsFilter(source), FilterOrderConst.CORS_FILTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return traceId 配置
|
||||
*/
|
||||
@Bean
|
||||
public FilterRegistrationBean<TraceIdFilter> traceIdFilterBean() {
|
||||
return createFilterBean(new TraceIdFilter(), FilterOrderConst.TRICE_ID_FILTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建过滤器
|
||||
*
|
||||
* @param filter filter
|
||||
* @param order order
|
||||
* @param <T> type
|
||||
* @return filter bean
|
||||
*/
|
||||
public static <T extends Filter> FilterRegistrationBean<T> createFilterBean(T filter, Integer order) {
|
||||
FilterRegistrationBean<T> bean = new FilterRegistrationBean<>(filter);
|
||||
bean.setOrder(order);
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.orion.ops.framework.web.core.filter;
|
||||
|
||||
import com.orion.lang.id.UUIds;
|
||||
import com.orion.ops.framework.common.meta.TraceIdHolder;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* traceId 过滤器
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/6/16 17:45
|
||||
*/
|
||||
public class TraceIdFilter extends OncePerRequestFilter {
|
||||
|
||||
private static final String TRACE_ID_HEADER = "trace-id";
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
try {
|
||||
// 获 traceId
|
||||
String traceId = UUIds.random32();
|
||||
TraceIdHolder.set(traceId);
|
||||
// 设置响应头
|
||||
response.setHeader(TRACE_ID_HEADER, traceId);
|
||||
// 执行请求
|
||||
filterChain.doFilter(request, response);
|
||||
} finally {
|
||||
TraceIdHolder.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
package com.orion.ops.framework.web.core.handler;
|
||||
|
||||
import com.orion.lang.define.wrapper.HttpWrapper;
|
||||
import com.orion.lang.exception.*;
|
||||
import com.orion.lang.exception.argument.CodeArgumentException;
|
||||
import com.orion.lang.exception.argument.HttpWrapperException;
|
||||
import com.orion.lang.exception.argument.InvalidArgumentException;
|
||||
import com.orion.lang.exception.argument.RpcWrapperException;
|
||||
import com.orion.lang.utils.Exceptions;
|
||||
import com.orion.ops.framework.common.enums.ExceptionMessageConst;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.EncryptedDocumentException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
||||
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* 全局异常处理器
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/6/15 17:19
|
||||
*/
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler(value = Exception.class)
|
||||
public HttpWrapper<?> normalExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("normalExceptionHandler url: {}, 抛出异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.EXCEPTION_MESSAGE).data(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = ApplicationException.class)
|
||||
public HttpWrapper<?> applicationExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("applicationExceptionHandler url: {}, 抛出异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ex.getMessage());
|
||||
}
|
||||
|
||||
// TODO datasource starter
|
||||
// @ExceptionHandler(value = DataAccessResourceFailureException.class)
|
||||
public HttpWrapper<?> dataAccessResourceFailureExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("dataAccessResourceFailureExceptionHandler url: {}, 抛出异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.NETWORK_FLUCTUATION);
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = {HttpMessageNotReadableException.class, MethodArgumentTypeMismatchException.class,
|
||||
HttpMessageNotReadableException.class, MethodArgumentNotValidException.class, BindException.class})
|
||||
public HttpWrapper<?> httpRequestExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("httpRequestExceptionHandler url: {}, http请求异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.INVALID_PARAM);
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = {HttpRequestException.class})
|
||||
public HttpWrapper<?> httpApiRequestExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("httpApiRequestExceptionHandler url: {}, http-api请求异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.HTTP_API);
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = {InvalidArgumentException.class, IllegalArgumentException.class, DisabledException.class})
|
||||
public HttpWrapper<?> invalidArgumentExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("invalidArgumentExceptionHandler url: {}, 参数异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = {IOException.class, IORuntimeException.class})
|
||||
public HttpWrapper<?> ioExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("ioExceptionHandler url: {}, io异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.IO_EXCEPTION_MESSAGE).data(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = SQLException.class)
|
||||
public HttpWrapper<?> sqlExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("sqlExceptionHandler url: {}, sql异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.SQL_EXCEPTION_MESSAGE);
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = {SftpException.class, com.jcraft.jsch.SftpException.class})
|
||||
public HttpWrapper<?> sftpExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("sftpExceptionHandler url: {}, sftp处理异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.OPERATOR_ERROR).data(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = ParseRuntimeException.class)
|
||||
public HttpWrapper<?> parseExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("parseExceptionHandler url: {}, 解析异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
if (Exceptions.isCausedBy(ex, EncryptedDocumentException.class)) {
|
||||
// excel 密码错误
|
||||
return HttpWrapper.error(ExceptionMessageConst.OPEN_TEMPLATE_ERROR).data(ex.getMessage());
|
||||
} else {
|
||||
return HttpWrapper.error(ExceptionMessageConst.PARSE_TEMPLATE_DATA_ERROR).data(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = EncryptException.class)
|
||||
public HttpWrapper<?> encryptExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("encryptExceptionHandler url: {}, 数据加密异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.ENCRYPT_ERROR).data(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = DecryptException.class)
|
||||
public HttpWrapper<?> decryptExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("decryptExceptionHandler url: {}, 数据解密异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.DECRYPT_ERROR).data(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = VcsException.class)
|
||||
public HttpWrapper<?> vcsExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("vcsExceptionHandler url: {}, vcs处理异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.REPOSITORY_OPERATOR_ERROR).data(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = {TaskExecuteException.class, ExecuteException.class})
|
||||
public HttpWrapper<?> taskExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("taskExceptionHandler url: {}, task处理异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.TASK_ERROR).data(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = ConnectionRuntimeException.class)
|
||||
public HttpWrapper<?> connectionExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("connectionExceptionHandler url: {}, connect异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.CONNECT_ERROR).data(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = {TimeoutException.class, java.util.concurrent.TimeoutException.class})
|
||||
public HttpWrapper<?> timeoutExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("timeoutExceptionHandler url: {}, timeout异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.TIMEOUT_ERROR).data(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = {InterruptedException.class, InterruptedRuntimeException.class, InterruptedIOException.class})
|
||||
public HttpWrapper<?> interruptExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("interruptExceptionHandler url: {}, interrupt异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.INTERRUPT_ERROR).data(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = UnsafeException.class)
|
||||
public HttpWrapper<?> unsafeExceptionHandler(HttpServletRequest request, Exception ex) {
|
||||
log.error("unsafeExceptionHandler url: {}, unsafe异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.UNSAFE_OPERATOR).data(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = LogException.class)
|
||||
public HttpWrapper<?> logExceptionHandler(HttpServletRequest request, LogException ex) {
|
||||
log.error("logExceptionHandler url: {}, 处理异常打印日志: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.EXCEPTION_MESSAGE).data(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = ParseCronException.class)
|
||||
public HttpWrapper<?> parseCronExceptionHandler(ParseCronException ex) {
|
||||
return HttpWrapper.error(ExceptionMessageConst.ERROR_EXPRESSION).data(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = MaxUploadSizeExceededException.class)
|
||||
public HttpWrapper<?> maxUploadSizeExceededExceptionHandler(HttpServletRequest request, MaxUploadSizeExceededException ex) {
|
||||
log.error("maxUploadSizeExceededExceptionHandler url: {}, 上传异常: {}, message: {}", request.getRequestURI(), ex.getClass(), ex.getMessage(), ex);
|
||||
return HttpWrapper.error(ExceptionMessageConst.FILE_TOO_LARGE).data(ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = CodeArgumentException.class)
|
||||
public HttpWrapper<?> codeArgumentExceptionHandler(CodeArgumentException ex) {
|
||||
return HttpWrapper.error(ex.getCode(), ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = HttpWrapperException.class)
|
||||
public HttpWrapper<?> httpWrapperExceptionHandler(HttpWrapperException ex) {
|
||||
return ex.getWrapper();
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = RpcWrapperException.class)
|
||||
public HttpWrapper<?> rpcWrapperExceptionHandler(RpcWrapperException ex) {
|
||||
return ex.getWrapper().toHttpWrapper();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.orion.ops.framework.web.core.handler;
|
||||
|
||||
import com.orion.lang.constant.StandardContentType;
|
||||
import com.orion.lang.define.wrapper.HttpWrapper;
|
||||
import com.orion.lang.define.wrapper.RpcWrapper;
|
||||
import com.orion.ops.framework.common.annotation.IgnoreWrapper;
|
||||
import com.orion.ops.framework.common.annotation.RestWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
||||
|
||||
/**
|
||||
* 返回值处理器
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/6/15 17:38
|
||||
*/
|
||||
@ControllerAdvice
|
||||
public class WrapperResultHandler implements ResponseBodyAdvice<Object> {
|
||||
|
||||
@Override
|
||||
public boolean supports(MethodParameter methodParameter, @NotNull Class converterType) {
|
||||
// 统一返回值
|
||||
if (!methodParameter.getContainingClass().isAnnotationPresent(RestWrapper.class)) {
|
||||
return false;
|
||||
}
|
||||
return !methodParameter.hasMethodAnnotation(IgnoreWrapper.class);
|
||||
// && methodParameter.getExecutable().getAnnotatedReturnType().getType() != Void.TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object beforeBodyWrite(Object body, @NotNull MethodParameter methodParameter, @NotNull MediaType selectedContentType, @NotNull Class selectedConverterType,
|
||||
@NotNull ServerHttpRequest request, @NotNull ServerHttpResponse response) {
|
||||
HttpWrapper<?> wrapper;
|
||||
if (body instanceof HttpWrapper) {
|
||||
wrapper = (HttpWrapper<?>) body;
|
||||
} else if (body instanceof RpcWrapper) {
|
||||
wrapper = ((RpcWrapper<?>) body).toHttpWrapper();
|
||||
} else {
|
||||
wrapper = new HttpWrapper<>().data(body);
|
||||
}
|
||||
if (response instanceof ServletServerHttpResponse) {
|
||||
((ServletServerHttpResponse) response).getServletResponse().setContentType(StandardContentType.APPLICATION_JSON);
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package com.orion.ops.framework.web.core.interceptor;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.PropertyFilter;
|
||||
import com.orion.lang.constant.Const;
|
||||
import com.orion.lang.utils.Arrays1;
|
||||
import com.orion.lang.utils.Exceptions;
|
||||
import com.orion.lang.utils.time.Dates;
|
||||
import com.orion.ops.framework.common.meta.TraceIdHolder;
|
||||
import com.orion.web.servlet.web.Servlets;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 日志打印拦截器
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2022/7/14 18:25
|
||||
*/
|
||||
@Slf4j
|
||||
@Order(10)
|
||||
public class LogPrintInterceptor implements MethodInterceptor {
|
||||
|
||||
// TODO @OperatorLog(bizName = "")
|
||||
// TODO 日志规格模型 SIMPLIFY FULL
|
||||
|
||||
// https://blog.csdn.net/gaojie_csdn/article/details/127810618
|
||||
// 加注解
|
||||
|
||||
// TODO 改为正则?
|
||||
@Value("#{'${log.interceptor.ignore.fields:}'.split(',')}")
|
||||
private String[] ignoreFields;
|
||||
|
||||
@Override
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
Date startTime = new Date();
|
||||
String traceId = TraceIdHolder.get();
|
||||
// 打印开始日志
|
||||
this.beforeLogPrint(startTime, traceId, invocation);
|
||||
try {
|
||||
// 执行方法
|
||||
Object ret = invocation.proceed();
|
||||
// 返回打印
|
||||
this.afterReturnLogPrint(startTime, traceId, ret);
|
||||
return ret;
|
||||
} catch (Throwable t) {
|
||||
// 异常打印
|
||||
this.afterThrowingLogPrint(startTime, traceId, t);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 方法进入打印
|
||||
*
|
||||
* @param startTime 开始时间
|
||||
* @param traceId trace
|
||||
* @param invocation invocation
|
||||
*/
|
||||
public void beforeLogPrint(Date startTime, String traceId, MethodInvocation invocation) {
|
||||
StringBuilder requestLog = new StringBuilder("\napi请求-开始-traceId: ").append(traceId).append('\n');
|
||||
// TODO 登陆用户
|
||||
// requestLog.append("\t当前用户: ").append(JSON.toJSONString(UserHolder.get())).append('\n');
|
||||
// TODO @OperatorLog
|
||||
// http请求信息
|
||||
Optional.ofNullable(RequestContextHolder.getRequestAttributes())
|
||||
.map(s -> (ServletRequestAttributes) s)
|
||||
.map(ServletRequestAttributes::getRequest)
|
||||
.ifPresent(request -> {
|
||||
// url
|
||||
requestLog.append("\t").append(Servlets.getMethod(request)).append(" ")
|
||||
.append(Servlets.getRequestUrl(request)).append('\n');
|
||||
// query
|
||||
requestLog.append("\tip: ").append(Servlets.getRemoteAddr(request)).append('\n')
|
||||
.append("\tquery: ").append(Servlets.getQueryString(request)).append('\n');
|
||||
// header
|
||||
Servlets.getHeaderMap(request).forEach((hk, hv) -> requestLog.append('\t')
|
||||
.append(hk).append(": ")
|
||||
.append(hv).append('\n'));
|
||||
});
|
||||
// 方法信息
|
||||
Method method = invocation.getMethod();
|
||||
requestLog.append("\t开始时间: ").append(Dates.format(startTime, Dates.YMD_HMSS)).append('\n')
|
||||
.append("\t方法签名: ").append(method.getDeclaringClass().getName()).append('#')
|
||||
.append(method.getName()).append("\n")
|
||||
.append("\t请求参数: ").append(this.argsToString(invocation.getArguments()));
|
||||
log.info(requestLog.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回打印
|
||||
*
|
||||
* @param startTime 开始时间
|
||||
* @param traceId traceId
|
||||
* @param ret return
|
||||
*/
|
||||
private void afterReturnLogPrint(Date startTime, String traceId, Object ret) {
|
||||
Date endTime = new Date();
|
||||
// 响应日志
|
||||
StringBuilder responseLog = new StringBuilder("\napi请求-结束-traceId: ").append(traceId).append('\n');
|
||||
responseLog.append("\t结束时间: ").append(Dates.format(endTime, Dates.YMD_HMSS))
|
||||
.append(" used: ").append(endTime.getTime() - startTime.getTime()).append("ms \n")
|
||||
.append("\t响应结果: ").append(this.argsToString(ret));
|
||||
log.info(responseLog.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 异常打印
|
||||
*
|
||||
* @param startTime 开始时间
|
||||
* @param traceId trace
|
||||
* @param throwable ex
|
||||
*/
|
||||
private void afterThrowingLogPrint(Date startTime, String traceId, Throwable throwable) {
|
||||
Date endTime = new Date();
|
||||
// 响应日志
|
||||
StringBuilder responseLog = new StringBuilder("\napi请求-异常-traceId: ").append(traceId).append('\n');
|
||||
responseLog.append("\t结束时间: ").append(Dates.format(endTime, Dates.YMD_HMSS))
|
||||
.append(" used: ").append(endTime.getTime() - startTime.getTime()).append("ms \n")
|
||||
.append("\t异常摘要: ").append(Exceptions.getDigest(throwable));
|
||||
log.error(responseLog.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数转json
|
||||
*
|
||||
* @param o object
|
||||
* @return json
|
||||
*/
|
||||
private String argsToString(Object o) {
|
||||
try {
|
||||
if (ignoreFields.length == 1 && Const.EMPTY.equals(ignoreFields[0])) {
|
||||
// 不过滤
|
||||
return JSON.toJSONString(o);
|
||||
} else {
|
||||
return JSON.toJSONString(o, (PropertyFilter) (object, name, value) -> !Arrays1.contains(ignoreFields, name));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return String.valueOf(o);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
com.orion.ops.framework.web.config.OrionWebAutoConfiguration
|
||||
com.orion.ops.framework.web.config.OrionLogPrinterConfiguration
|
||||
24
orion-ops-framework/pom.xml
Normal file
24
orion-ops-framework/pom.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.orion.ops</groupId>
|
||||
<artifactId>orion-ops-pro</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>orion-ops-framework</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<description>项目组件包</description>
|
||||
<url>https://github.com/lijiahangmax/orion-ops-pro</url>
|
||||
|
||||
<modules>
|
||||
<module>orion-ops-common</module>
|
||||
<module>orion-ops-spring-boot-starter-banner</module>
|
||||
<module>orion-ops-spring-boot-starter-web</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
Reference in New Issue
Block a user