feat:V3.1.1整合remi-comm到remi-cloud中
This commit is contained in:
14
derby.log
14
derby.log
@@ -1,12 +1,12 @@
|
|||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
Sun Sep 01 21:38:15 CST 2024:
|
Wed Sep 11 17:08:24 CST 2024:
|
||||||
Booting Derby version The Apache Software Foundation - Apache Derby - 10.14.2.0 - (1828579): instance a816c00e-0191-adce-b9d3-000003b04a40
|
Booting Derby version The Apache Software Foundation - Apache Derby - 10.14.2.0 - (1828579): instance a816c00e-0191-e057-45b8-000002512970
|
||||||
on database directory memory:D:\Codes\remi\remi-cloud\4f82a0bb-9d60-4d6f-b6a3-e6480d5e589c with class loader jdk.internal.loader.ClassLoaders$AppClassLoader@60e53b93
|
on database directory memory:D:\Codes\remi-top\remi-cloud\1ec76c96-9207-4b71-b497-ffec1d63b532 with class loader jdk.internal.loader.ClassLoaders$AppClassLoader@5e481248
|
||||||
Loaded from file:/D:/Maven/sdt-repository/org/apache/derby/derby/10.14.2.0/derby-10.14.2.0.jar
|
Loaded from file:/D:/Maven/remi-top-repo/org/apache/derby/derby/10.14.2.0/derby-10.14.2.0.jar
|
||||||
java.vendor=Amazon.com Inc.
|
java.vendor=Amazon.com Inc.
|
||||||
java.runtime.version=17.0.11+9-LTS
|
java.runtime.version=17.0.12+7-LTS
|
||||||
user.dir=D:\Codes\remi\remi-cloud
|
user.dir=D:\Codes\remi-top\remi-cloud
|
||||||
os.name=Windows 11
|
os.name=Windows 10
|
||||||
os.arch=amd64
|
os.arch=amd64
|
||||||
os.version=10.0
|
os.version=10.0
|
||||||
derby.system.home=null
|
derby.system.home=null
|
||||||
|
|||||||
155
pom.xml
155
pom.xml
@@ -4,9 +4,8 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>ai.remi.top.cloud</groupId>
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-cloud</artifactId>
|
<artifactId>remi-cloud</artifactId>
|
||||||
<version>3.1.0</version>
|
<version>3.1.1</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<url>https://github.com/remi/remi-cloud</url>
|
|
||||||
<name>remi-cloud</name>
|
<name>remi-cloud</name>
|
||||||
<description>Remi Cloud</description>
|
<description>Remi Cloud</description>
|
||||||
|
|
||||||
@@ -19,7 +18,7 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<!--remi-->
|
<!--remi-->
|
||||||
<remi.version>3.1.0</remi.version>
|
<remi.version>3.1.1</remi.version>
|
||||||
<!--jdk-->
|
<!--jdk-->
|
||||||
<java.version>17</java.version>
|
<java.version>17</java.version>
|
||||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||||
@@ -31,71 +30,59 @@
|
|||||||
<spring-boot.version>2.7.18</spring-boot.version>
|
<spring-boot.version>2.7.18</spring-boot.version>
|
||||||
<spring-cloud.version>2021.0.9</spring-cloud.version>
|
<spring-cloud.version>2021.0.9</spring-cloud.version>
|
||||||
<spring-cloud-alibaba.version>2021.0.6.0</spring-cloud-alibaba.version>
|
<spring-cloud-alibaba.version>2021.0.6.0</spring-cloud-alibaba.version>
|
||||||
<!--1.15-->
|
<!--commons-->
|
||||||
<commons-codec.version>1.17.0</commons-codec.version>
|
<commons-text.version>1.12.0</commons-text.version>
|
||||||
<!--3.2.2-->
|
|
||||||
<commons-collections.version>3.2.2</commons-collections.version>
|
|
||||||
<!--1.10.0-->
|
|
||||||
<commons-text.version>1.10.0</commons-text.version>
|
|
||||||
<!--2.11.0-->
|
|
||||||
<commons-io.version>2.16.1</commons-io.version>
|
<commons-io.version>2.16.1</commons-io.version>
|
||||||
<!--3.12.0-->
|
<commons-lang3.version>3.17.0</commons-lang3.version>
|
||||||
<commons-lang3.version>3.14.0</commons-lang3.version>
|
<commons-codec.version>1.17.1</commons-codec.version>
|
||||||
<!--1.0.4-->
|
<commons-logging.version>1.3.4</commons-logging.version>
|
||||||
<commons-logging.version>1.3.1</commons-logging.version>
|
<commons-collections.version>3.2.2</commons-collections.version>
|
||||||
<!--3.8.0-->
|
<commons-net.version>3.11.1</commons-net.version>
|
||||||
<commons-net.version>3.10.0</commons-net.version>
|
|
||||||
<!--1.7-->
|
|
||||||
<commons-validator.version>1.9.0</commons-validator.version>
|
|
||||||
<!--1.4-->
|
|
||||||
<commons-fileupload.version>1.5</commons-fileupload.version>
|
<commons-fileupload.version>1.5</commons-fileupload.version>
|
||||||
<!--1.0.10-->
|
<!--hutool-->
|
||||||
<device.version>1.0.10</device.version>
|
|
||||||
<!--2.1.3-->
|
|
||||||
<dom4j.version>2.1.3</dom4j.version>
|
|
||||||
<!--1.2.9-->
|
|
||||||
<druid.version>1.2.9</druid.version>
|
|
||||||
<!--3.1.1-->
|
|
||||||
<easyexcel.version>3.1.1</easyexcel.version>
|
|
||||||
<!--6.2.5.Final-->
|
|
||||||
<hibernate-validator.version>6.2.5.Final</hibernate-validator.version>
|
|
||||||
<!--1.21-->
|
|
||||||
<bitwalker.version>1.21</bitwalker.version>
|
|
||||||
<!--2.7.0-->
|
|
||||||
<ip2region.version>2.7.0</ip2region.version>
|
|
||||||
<!--5.8.4-->
|
|
||||||
<hutool.version>5.8.4</hutool.version>
|
<hutool.version>5.8.4</hutool.version>
|
||||||
<!--31.1-jre-->
|
<!--storage-->
|
||||||
<guava.version>31.1-jre</guava.version>
|
<tika.version>2.7.0</tika.version>
|
||||||
<!--2.9.0-->
|
<qiniu.version>7.13.1</qiniu.version>
|
||||||
|
<aliyun-sdk-oss.version>3.10.2</aliyun-sdk-oss.version>
|
||||||
|
<minio.version>8.5.12</minio.version>
|
||||||
|
<awssdk.version>2.26.3</awssdk.version>
|
||||||
|
<cos_api.version>5.6.213</cos_api.version>
|
||||||
|
<!--easyexcel-->
|
||||||
|
<easyexcel.version>4.0.2</easyexcel.version>
|
||||||
|
<!--xxl-job-->
|
||||||
|
<xxl-job.version>2.4.1</xxl-job.version>
|
||||||
|
<!--user-agent-->
|
||||||
|
<device.version>1.0.10</device.version>
|
||||||
|
<bitwalker.version>1.21</bitwalker.version>
|
||||||
|
<!--xml-dom-->
|
||||||
|
<dom4j.version>2.1.3</dom4j.version>
|
||||||
|
<!--validator-->
|
||||||
|
<commons-validator.version>1.9.0</commons-validator.version>
|
||||||
|
<hibernate-validator.version>8.0.1.Final</hibernate-validator.version>
|
||||||
|
<!--ip2region-->
|
||||||
|
<ip2region.version>2.7.0</ip2region.version>
|
||||||
|
<!--json-->
|
||||||
<gson.version>2.9.0</gson.version>
|
<gson.version>2.9.0</gson.version>
|
||||||
<!--2.0.6-->
|
|
||||||
<fastjson.version>2.0.6</fastjson.version>
|
<fastjson.version>2.0.6</fastjson.version>
|
||||||
<!--2.13.3-->
|
|
||||||
<jackson.version>2.13.3</jackson.version>
|
<jackson.version>2.13.3</jackson.version>
|
||||||
<!--4.0.0-->
|
<!--java-extend-->
|
||||||
<java-jwt.version>0.12.6</java-jwt.version>
|
<guava.version>33.3.0-jre</guava.version>
|
||||||
<!--4.0.1-->
|
|
||||||
<javax.version>4.0.1</javax.version>
|
<javax.version>4.0.1</javax.version>
|
||||||
<!--2.3.1-->
|
|
||||||
<jaxb-api.version>2.3.1</jaxb-api.version>
|
<jaxb-api.version>2.3.1</jaxb-api.version>
|
||||||
<!--3.3.0-->
|
|
||||||
<cglib.version>3.3.0</cglib.version>
|
<cglib.version>3.3.0</cglib.version>
|
||||||
<!--4.5.0-->
|
<!--knife4j-->
|
||||||
<knife4j.version>4.5.0</knife4j.version>
|
<knife4j.version>4.5.0</knife4j.version>
|
||||||
<!--2.6.0-->
|
|
||||||
<springdoc.version>2.6.0</springdoc.version>
|
<springdoc.version>2.6.0</springdoc.version>
|
||||||
<!--1.18.34-->
|
<!--mapstruct-->
|
||||||
<lombok.version>1.18.34</lombok.version>
|
<lombok.version>1.18.34</lombok.version>
|
||||||
<!--1.5.2.Final-->
|
|
||||||
<mapstruct.version>1.5.2.Final</mapstruct.version>
|
<mapstruct.version>1.5.2.Final</mapstruct.version>
|
||||||
<!--0.2.0-->
|
|
||||||
<lombok-mapstruct.version>0.2.0</lombok-mapstruct.version>
|
<lombok-mapstruct.version>0.2.0</lombok-mapstruct.version>
|
||||||
<!--3.5.2-->
|
<!--jdbc-->
|
||||||
<mybatis-plus.version>3.5.2</mybatis-plus.version>
|
<druid.version>1.2.9</druid.version>
|
||||||
<!--2.2.2-->
|
|
||||||
<mybatis.version>2.2.2</mybatis.version>
|
<mybatis.version>2.2.2</mybatis.version>
|
||||||
<!--rdb-sql-->
|
<mybatis-plus.version>3.5.2</mybatis-plus.version>
|
||||||
|
<!--jdbc rom-->
|
||||||
<mysql.version>8.0.33</mysql.version>
|
<mysql.version>8.0.33</mysql.version>
|
||||||
<ojdbc.version>19.7.0.0</ojdbc.version>
|
<ojdbc.version>19.7.0.0</ojdbc.version>
|
||||||
<mssql-jdbc.version>7.4.1.jre8</mssql-jdbc.version>
|
<mssql-jdbc.version>7.4.1.jre8</mssql-jdbc.version>
|
||||||
@@ -103,26 +90,20 @@
|
|||||||
<postgresql.version>42.6.0</postgresql.version>
|
<postgresql.version>42.6.0</postgresql.version>
|
||||||
<h2.db.version>2.2.224</h2.db.version>
|
<h2.db.version>2.2.224</h2.db.version>
|
||||||
<mongodb-driver-sync.version>4.10.2</mongodb-driver-sync.version>
|
<mongodb-driver-sync.version>4.10.2</mongodb-driver-sync.version>
|
||||||
<!--4.5.13-->
|
<!--http-->
|
||||||
<httpclient.version>4.5.13</httpclient.version>
|
<httpclient.version>4.5.13</httpclient.version>
|
||||||
<!--8.4.6 4.10.0-->
|
|
||||||
<minio.version>8.5.12</minio.version>
|
|
||||||
<!--4.9.3-->
|
|
||||||
<okhttp3.version>4.12.0</okhttp3.version>
|
<okhttp3.version>4.12.0</okhttp3.version>
|
||||||
<!--velocity-->
|
<!--velocity-->
|
||||||
<velocity.version>1.7</velocity.version>
|
<velocity.version>1.7</velocity.version>
|
||||||
<!--2.4.1-->
|
<!--logger-->
|
||||||
<xxl-job.version>2.4.1</xxl-job.version>
|
|
||||||
<!--8.13.0-->
|
|
||||||
<trace.version>8.13.0</trace.version>
|
<trace.version>8.13.0</trace.version>
|
||||||
<!--1.7.36-->
|
|
||||||
<slf4j.version>1.7.32</slf4j.version>
|
<slf4j.version>1.7.32</slf4j.version>
|
||||||
<!--logback-->
|
|
||||||
<logback.version>1.3.14</logback.version>
|
<logback.version>1.3.14</logback.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<!--基础服务-->
|
<!--基础服务-->
|
||||||
|
<module>remi-comm</module>
|
||||||
<module>remi-nacos</module>
|
<module>remi-nacos</module>
|
||||||
<module>remi-sys</module>
|
<module>remi-sys</module>
|
||||||
<module>remi-demo</module>
|
<module>remi-demo</module>
|
||||||
@@ -160,82 +141,82 @@
|
|||||||
<!--内部服务依赖开始-->
|
<!--内部服务依赖开始-->
|
||||||
<!--remi-comm-->
|
<!--remi-comm-->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm</artifactId>
|
<artifactId>remi-comm</artifactId>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm-core</artifactId>
|
<artifactId>remi-comm-core</artifactId>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm-minio</artifactId>
|
<artifactId>remi-comm-minio</artifactId>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm-redis</artifactId>
|
<artifactId>remi-comm-redis</artifactId>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm-jdbc</artifactId>
|
<artifactId>remi-comm-jdbc</artifactId>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm-domain</artifactId>
|
<artifactId>remi-comm-domain</artifactId>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm-exception</artifactId>
|
<artifactId>remi-comm-exception</artifactId>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm-feign</artifactId>
|
<artifactId>remi-comm-feign</artifactId>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm-job</artifactId>
|
<artifactId>remi-comm-job</artifactId>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm-log</artifactId>
|
<artifactId>remi-comm-log</artifactId>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm-swagger</artifactId>
|
<artifactId>remi-comm-swagger</artifactId>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm-thread</artifactId>
|
<artifactId>remi-comm-thread</artifactId>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm-util</artifactId>
|
<artifactId>remi-comm-util</artifactId>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm-auth</artifactId>
|
<artifactId>remi-comm-auth</artifactId>
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm-safe</artifactId>
|
<artifactId>remi-comm-safe</artifactId>
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ai.remi.top.comm</groupId>
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
<artifactId>remi-comm-web</artifactId>
|
<artifactId>remi-comm-web</artifactId>
|
||||||
<version>${remi.version}</version>
|
<version>${remi.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
@@ -396,12 +377,12 @@
|
|||||||
<groupId>commons-fileupload</groupId>
|
<groupId>commons-fileupload</groupId>
|
||||||
<version>${commons-fileupload.version}</version>
|
<version>${commons-fileupload.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- validator -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<artifactId>commons-validator</artifactId>
|
<artifactId>commons-validator</artifactId>
|
||||||
<groupId>commons-validator</groupId>
|
<groupId>commons-validator</groupId>
|
||||||
<version>${commons-validator.version}</version>
|
<version>${commons-validator.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- hibernate-validator -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<artifactId>hibernate-validator</artifactId>
|
<artifactId>hibernate-validator</artifactId>
|
||||||
<groupId>org.hibernate.validator</groupId>
|
<groupId>org.hibernate.validator</groupId>
|
||||||
@@ -565,22 +546,6 @@
|
|||||||
<artifactId>velocity</artifactId>
|
<artifactId>velocity</artifactId>
|
||||||
<version>${velocity.version}</version>
|
<version>${velocity.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- jwt -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt-api</artifactId>
|
|
||||||
<version>${java-jwt.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt-impl</artifactId>
|
|
||||||
<version>${java-jwt.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt-jackson</artifactId>
|
|
||||||
<version>${java-jwt.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- jaxb-api -->
|
<!-- jaxb-api -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<artifactId>jaxb-api</artifactId>
|
<artifactId>jaxb-api</artifactId>
|
||||||
|
|||||||
60
remi-comm/README.md
Normal file
60
remi-comm/README.md
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Remi Comm</h1>
|
||||||
|
|
||||||
|
## 平台简介
|
||||||
|
|
||||||
|
Remi Comm 即 Remi Dev Tools 启迪快速开发平台所依赖的公共依赖模块。
|
||||||
|
|
||||||
|
## 项目文档
|
||||||
|
|
||||||
|
https://remi.yuque.com/r/organizations/homepage
|
||||||
|
|
||||||
|
## 体验地址
|
||||||
|
|
||||||
|
https://remi.run
|
||||||
|
|
||||||
|
RemiAdmin/123456
|
||||||
|
|
||||||
|
## 项目源码
|
||||||
|
|
||||||
|
### Gitee
|
||||||
|
|
||||||
|
https://gitee.com/remi-top
|
||||||
|
|
||||||
|
### GitTok
|
||||||
|
|
||||||
|
https://gittok.com/remi-top
|
||||||
|
|
||||||
|
### Gitlab
|
||||||
|
|
||||||
|
https://gitlab.com/remi-top
|
||||||
|
|
||||||
|
### Github
|
||||||
|
|
||||||
|
https://github.com/remi-top
|
||||||
|
|
||||||
|
## 系统模块
|
||||||
|
|
||||||
|
~~~
|
||||||
|
remi-comm
|
||||||
|
├── remi-comm-auth // 权限控制
|
||||||
|
├── remi-comm-core // 核心模块
|
||||||
|
├── remi-comm-domain // 领域模型
|
||||||
|
├── remi-comm-jdbc // 数据配置
|
||||||
|
├── remi-comm-exception // 异常模块
|
||||||
|
├── remi-comm-feign // 通信模块
|
||||||
|
├── remi-comm-job // 任务模块
|
||||||
|
├── remi-comm-minio // MinIo 文件存储
|
||||||
|
├── remi-comm-activemq // ActiveMQ
|
||||||
|
├── remi-comm-rabbitmq // RabbitMQ
|
||||||
|
├── remi-comm-rocketmq // RocketMQ
|
||||||
|
├── remi-comm-redis // 缓存服务
|
||||||
|
├── remi-comm-util // 工具类
|
||||||
|
├── remi-comm-thread // 线程池
|
||||||
|
├── remi-comm-swagger // 系统接口
|
||||||
|
├── remi-comm-netty // Netty
|
||||||
|
├── remi-comm-safe // 安全控制
|
||||||
|
├── remi-comm-web // Web
|
||||||
|
├── remi-comm-webservice // WebService
|
||||||
|
├── remi-comm-websocket // WebSocket
|
||||||
|
├── pom.xml // 公共依赖
|
||||||
|
~~~
|
||||||
56
remi-comm/pom.xml
Normal file
56
remi-comm/pom.xml
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>remi-comm</artifactId>
|
||||||
|
<name>remi-comm</name>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<description>瑞米平台-公共依赖</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-cloud</artifactId>
|
||||||
|
<version>3.1.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>17</java.version>
|
||||||
|
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||||
|
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<!--子模块管理-->
|
||||||
|
<modules>
|
||||||
|
<module>remi-comm-core</module>
|
||||||
|
<module>remi-comm-util</module>
|
||||||
|
<module>remi-comm-domain</module>
|
||||||
|
<module>remi-comm-jdbc</module>
|
||||||
|
<module>remi-comm-thread</module>
|
||||||
|
<module>remi-comm-job</module>
|
||||||
|
<module>remi-comm-log</module>
|
||||||
|
<module>remi-comm-minio</module>
|
||||||
|
<module>remi-comm-redis</module>
|
||||||
|
<module>remi-comm-feign</module>
|
||||||
|
<module>remi-comm-email</module>
|
||||||
|
<module>remi-comm-exception</module>
|
||||||
|
<module>remi-comm-auth</module>
|
||||||
|
<module>remi-comm-safe</module>
|
||||||
|
<module>remi-comm-swagger</module>
|
||||||
|
<module>remi-comm-web</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
<!-- 打包上传到私服, 需要和配置文件中的server节点配合使用 -->
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>maven-releases</id>
|
||||||
|
<name>release</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-releases/</url>
|
||||||
|
</repository>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>maven-snapshots</id>
|
||||||
|
<name>snapshot</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-snapshots/</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
</distributionManagement>
|
||||||
|
</project>
|
||||||
59
remi-comm/remi-comm-auth/pom.xml
Normal file
59
remi-comm/remi-comm-auth/pom.xml
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>remi-comm-auth</artifactId>
|
||||||
|
<name>remi-comm-auth</name>
|
||||||
|
<description>remi-comm-auth</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm</artifactId>
|
||||||
|
<version>3.1.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<!-- 打包上传到私服, 需要和配置文件中的server节点配合使用 -->
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>maven-releases</id>
|
||||||
|
<name>release</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-releases/</url>
|
||||||
|
</repository>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>maven-snapshots</id>
|
||||||
|
<name>snapshot</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-snapshots/</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!--公共依赖-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm-exception</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--spring-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-aop</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--lombok-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package ai.remi.comm.auth.annotation;
|
||||||
|
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author DianJiu 【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @date 2022-07-19
|
||||||
|
* @desc 权限校验
|
||||||
|
*/
|
||||||
|
@Inherited
|
||||||
|
@Documented
|
||||||
|
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
|
public @interface RbacPermission {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String roles() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String permissions() default "";
|
||||||
|
}
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
package ai.remi.comm.auth.aspect;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import ai.remi.comm.auth.annotation.RbacPermission;
|
||||||
|
import ai.remi.comm.core.constant.Constants;
|
||||||
|
import ai.remi.comm.core.constant.HeaderConstant;
|
||||||
|
import ai.remi.comm.exception.custom.BusinessException;
|
||||||
|
import ai.remi.comm.redis.service.RedisService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestAttributes;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author DianJiu 【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @date 2022-07-19
|
||||||
|
* @desc
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
@Order(10)
|
||||||
|
@Slf4j
|
||||||
|
public class RbacPermissionAspect {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(RbacPermissionAspect.class);
|
||||||
|
|
||||||
|
private final ThreadLocal<Map<String, Object>> threadLocal = new ThreadLocal<Map<String, Object>>();
|
||||||
|
|
||||||
|
private final String ROLE_MENU = "tdcd-cloud-mps:role-menu:{}";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisService redisService;
|
||||||
|
|
||||||
|
@Pointcut("@annotation(ai.remi.comm.auth.annotation.RbacPermission)")
|
||||||
|
public void rbacPermissionPointCut() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 环绕通知
|
||||||
|
* 方式一:传入注解,获取注解中的参数
|
||||||
|
*
|
||||||
|
* @Around("logRecordPointCut()&&@annotation(logRecord)") public void doAround(ProceedingJoinPoint joinPoint, LogRecord logRecord) {}
|
||||||
|
* 方式二:通过切点获取注解实体
|
||||||
|
*/
|
||||||
|
@Around("rbacPermissionPointCut()")
|
||||||
|
//@Around("rbacPermissionPointCut()&&@annotation(RbacPermission)")
|
||||||
|
//public void doAround(ProceedingJoinPoint joinPoint, RbacPermission rbacPermission) {
|
||||||
|
public Object doAround(ProceedingJoinPoint joinPoint) {
|
||||||
|
// 接收到请求
|
||||||
|
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
|
||||||
|
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
|
||||||
|
HttpServletRequest request = sra.getRequest();
|
||||||
|
// 记录请求内容,threadInfo存储所有内容
|
||||||
|
Map<String, Object> threadInfo = new HashMap<>();
|
||||||
|
//该方法用于获取客户端发出请求时的完整URL,包括协议、服务器名、端口号、资源路径等信息,但不包括后面的查询参数部分。
|
||||||
|
// 注意,getRequestRUL()方法返回的时StringBuffer类型,而不是String类型。
|
||||||
|
threadInfo.put("url", request.getRequestURL());
|
||||||
|
//该方法用于获取请求行中资源名称部分,即位于URL的主机和端口之后、参数部分之前的部分
|
||||||
|
threadInfo.put("uri", request.getRequestURI());
|
||||||
|
//该方法用于获取请求的协议名,例如http、https或ftp
|
||||||
|
threadInfo.put("scheme", request.getScheme());
|
||||||
|
//该方法用于获取HTTP请求消息中的请求方式(如GET、POST等)
|
||||||
|
threadInfo.put("method", request.getMethod());
|
||||||
|
logger.info("请求方式:{}", threadInfo.get("method"));
|
||||||
|
//该方法用于获取请求客户端的IP地址,其格式类似于"192.168.0.1"
|
||||||
|
threadInfo.put("ip", request.getRemoteAddr());
|
||||||
|
logger.info("请求ip:{}", threadInfo.get("ip"));
|
||||||
|
//该方法用于获取Content-Type头字段的值,结果为String类型
|
||||||
|
threadInfo.put("contentType", request.getContentType());
|
||||||
|
//包含了一个特征字符串,用来让网络协议的对端来识别发起请求的用户代理软件的应用类型、操作系统、软件开发商以及版本号。
|
||||||
|
threadInfo.put("userAgent", request.getHeader("User-Agent"));
|
||||||
|
//threadInfo.put("businessNo", request.getHeader("businessNo"));
|
||||||
|
threadLocal.set(threadInfo);
|
||||||
|
//获取方法签名
|
||||||
|
MethodSignature signature = getSignature(joinPoint);
|
||||||
|
//获取注解对象
|
||||||
|
RbacPermission rbacPermission = getAnnotation(joinPoint, RbacPermission.class);
|
||||||
|
//获取注解方法
|
||||||
|
Method method = getMethod(joinPoint);
|
||||||
|
// 获取连接点所在类名
|
||||||
|
String classname = joinPoint.getTarget().getClass().getSimpleName();
|
||||||
|
// 获取连接点所在方法名称
|
||||||
|
String methodName = method.getName();
|
||||||
|
String functionName = String.format("【%s.%s()】", classname, methodName);
|
||||||
|
threadInfo.put("functionName", functionName);
|
||||||
|
logger.info("请求类方法:{}", threadInfo.get("functionName"));
|
||||||
|
// 下面两个数组中,参数值和参数名的个数和位置是一一对应的。
|
||||||
|
// 参数名
|
||||||
|
String[] argNames = signature.getParameterNames();
|
||||||
|
// 参数值
|
||||||
|
Object[] args = joinPoint.getArgs();
|
||||||
|
StringBuilder functionArgs = new StringBuilder();
|
||||||
|
//不为空时便利组装
|
||||||
|
if (Objects.nonNull(argNames) && argNames.length > 0 && args.length > 0) {
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
functionArgs.append(argNames[i] + ":" + args[i] + ";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
threadInfo.put("functionArgs", functionArgs.toString());
|
||||||
|
logger.info("请求参数:{}", threadInfo.get("functionArgs"));
|
||||||
|
|
||||||
|
// threadInfo.put("accessToken", request.getHeader("accessToken"));
|
||||||
|
threadInfo.put("accessToken", request.getHeader(HeaderConstant.X_ACCESS_TOKEN));
|
||||||
|
logger.info("鉴权令牌:{}", threadInfo.get("accessToken"));
|
||||||
|
|
||||||
|
// 权限校验
|
||||||
|
if (method.isAnnotationPresent(RbacPermission.class)) {
|
||||||
|
String roles = rbacPermission.roles();
|
||||||
|
String permissions = rbacPermission.permissions();
|
||||||
|
|
||||||
|
// 根据鉴权令牌去redis查询到用户信息、角色信息、权限信息
|
||||||
|
//Map map = redisService.hmget(RedisDemoEnum.ACCESS_TOKEN.getKey(String.valueOf(threadInfo.get("accessToken"))));
|
||||||
|
Map map = redisService.hmget(String.valueOf(threadInfo.get("accessToken")));
|
||||||
|
if (null == map || map.size() == 0) {
|
||||||
|
throw new BusinessException(Constants.LOGIN_NO_PERMISSION, "accessToken expire! please login again!");
|
||||||
|
}
|
||||||
|
String roleCode = String.valueOf(map.get("roleCode"));
|
||||||
|
List<String> roleCodes = Arrays.asList(roleCode.split(","));
|
||||||
|
// 校验角色
|
||||||
|
if (StringUtils.isNotBlank(roles)) {
|
||||||
|
// 校验用户角色
|
||||||
|
// JSONObject jsonObject = JSONObject.parseObject(String.valueOf(map.get("user")));
|
||||||
|
// if (!Arrays.asList(roles.split(",")).contains(jsonObject.get("roleCode"))) {
|
||||||
|
// throw new BusinessException(Constants.CODE_403, "当前角色权限不足");
|
||||||
|
// }
|
||||||
|
for (String authRoleCode : Arrays.asList(roles.split(","))) {
|
||||||
|
if (!roleCodes.contains(authRoleCode)){
|
||||||
|
throw new BusinessException(Constants.CODE_403, "the role no Permission!");
|
||||||
|
}else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if (!Arrays.asList(roles.split(",")).contains(roleCode)) {
|
||||||
|
// throw new BusinessException(Constants.CODE_403, "the role no Permission!");
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
// 校验权限
|
||||||
|
if (StringUtils.isNotBlank(permissions)) {
|
||||||
|
// 组装用户权限
|
||||||
|
StringBuilder userPermissions = new StringBuilder();
|
||||||
|
|
||||||
|
// String menuString = JSONObject.toJSONString(map.get("menus"));
|
||||||
|
// List<JSONObject> menus = JSONObject.parseArray(menuString);
|
||||||
|
List<JSONObject> menus = new ArrayList<>();
|
||||||
|
for (String code : roleCodes) {
|
||||||
|
String data = null;
|
||||||
|
try {
|
||||||
|
data = redisService.getString(StrUtil.format(ROLE_MENU, code));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取用户权限异常:{}", e.getMessage());
|
||||||
|
throw new BusinessException(Constants.CODE_403, "get user Permission error!");
|
||||||
|
}
|
||||||
|
List<JSONObject> menuList = JSONObject.parseArray(data, JSONObject.class);
|
||||||
|
menus.addAll(menuList);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < menus.size(); i++) {
|
||||||
|
if ("2".equals(menus.get(i).get("menuType"))) {
|
||||||
|
userPermissions.append(menus.get(i).get("menuPermission"));
|
||||||
|
if (i != menus.size() - 1) {
|
||||||
|
userPermissions.append(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 校验用户权限
|
||||||
|
if (!Arrays.asList(userPermissions.toString().split(",")).containsAll(Arrays.asList(permissions.split(",")))) {
|
||||||
|
throw new BusinessException(Constants.CODE_403, "the user no Permission");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//执行到这里开始走进来的方法体(必须声明)
|
||||||
|
Object returnValue;
|
||||||
|
try {
|
||||||
|
returnValue = joinPoint.proceed(args);
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
throw new BusinessException(((BusinessException) throwable).getCode(), (throwable).getMessage());
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private MethodSignature getSignature(JoinPoint joinPoint) {
|
||||||
|
//通过连接点获取方法签名
|
||||||
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Method getMethod(JoinPoint joinPoint) {
|
||||||
|
//通过连接点获取方法签名
|
||||||
|
MethodSignature signature = getSignature(joinPoint);
|
||||||
|
//获取注解服务的方法
|
||||||
|
Method method = signature.getMethod();
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Annotation> T getAnnotation(JoinPoint joinPoint, Class<T> annotationClass) {
|
||||||
|
Method method = getMethod(joinPoint);
|
||||||
|
//获取注解类
|
||||||
|
T annotation = method.getAnnotation(annotationClass);
|
||||||
|
return annotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
83
remi-comm/remi-comm-core/README.md
Normal file
83
remi-comm/remi-comm-core/README.md
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
## 方式1: 实现ApplicationContextInitializer接口
|
||||||
|
实现接口后,将此类注入到Spring容器中,有两种方式。当然也可以直接调用静态方法
|
||||||
|
|
||||||
|
第一种: 在此类上加`@Component`注解
|
||||||
|
|
||||||
|
第二种:在 `resources/META-INF/spring.factories`文件中添加以下配置: org.springframework.context.ApplicationContextInitializer=CustomerApplicationContextInitializer的路径
|
||||||
|
|
||||||
|
实现ApplicationContextInitializer的源码示例:
|
||||||
|
```java
|
||||||
|
|
||||||
|
public class CustomApplicationContextInitializer implements ApplicationContextInitializer {
|
||||||
|
@Override
|
||||||
|
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||||
|
SpringBeanUtils.setApplicationContext(applicationContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 方式2. 实现ApplicationListener接口
|
||||||
|
实现接口后,将此类注入到Spring容器中,有两种方式。当然也可以直接调用静态方法
|
||||||
|
|
||||||
|
第一种: 在此类上加`@Component`注解
|
||||||
|
|
||||||
|
第二种:在 `resources/META-INF/spring.factories`文件中添加以下配置: org.springframework.context.ApplicationContextInitializer=CustomerApplicationListener的路径
|
||||||
|
|
||||||
|
实现ApplicationListener的源码示例:
|
||||||
|
```java
|
||||||
|
|
||||||
|
public class CustomApplicationListener implements ApplicationListener<ApplicationContextEvent> {
|
||||||
|
@Override
|
||||||
|
public void onApplicationEvent(ApplicationContextEvent event) {
|
||||||
|
SpringBeanUtils.setApplicationContext(event.getApplicationContext());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
方式3. 在启动类main方法中设置
|
||||||
|
```java
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableSwagger2
|
||||||
|
public class Application {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ConfigurableApplicationContext applicationContext = SpringApplication.run(WangMikeSpringApplication.class, args);
|
||||||
|
SpringBeanUtils.setApplicationContext(applicationContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
方式4. 实现ApplicationContextAware接口
|
||||||
|
```java
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class SpringBeanUtils implements ApplicationContextAware {
|
||||||
|
private static ApplicationContext applicationContext;
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext){
|
||||||
|
SpringBeanUtils.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApplicationContext getApplicationContext(
|
||||||
|
return applicationContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
方式5. 直接通过@Resource注解注入
|
||||||
|
```java
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Order(value = 1)
|
||||||
|
@Slf4j
|
||||||
|
public class AppStartRunner implements org.springframework.boot.ApplicationRunner {
|
||||||
|
protected static Logger logger = LoggerFactory.getLogger(AppStartRunner.class);
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
ApplicationContext applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
55
remi-comm/remi-comm-core/pom.xml
Normal file
55
remi-comm/remi-comm-core/pom.xml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>remi-comm-core</artifactId>
|
||||||
|
<name>remi-comm-core</name>
|
||||||
|
<description>remi-comm-core</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm</artifactId>
|
||||||
|
<version>3.1.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<!-- 打包上传到私服, 需要和配置文件中的server节点配合使用 -->
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>maven-releases</id>
|
||||||
|
<name>release</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-releases/</url>
|
||||||
|
</repository>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>maven-snapshots</id>
|
||||||
|
<name>snapshot</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-snapshots/</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- spring -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 解析user-agent的包 -->
|
||||||
|
<dependency>
|
||||||
|
<artifactId>device-detector</artifactId>
|
||||||
|
<groupId>io.github.mngsk</groupId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!--lombok-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package ai.remi.comm.core.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc AuthFilterConfig
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "filter.config")
|
||||||
|
public class AuthFilterConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公共忽略的url,网关、公共web的AuthFilter 都会忽略---- 配置在application-dev.yaml
|
||||||
|
*/
|
||||||
|
private List<String> commonIgnoreUrl= new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网关忽略的ur----配置在ebg-shop-gateway-dev.yaml
|
||||||
|
*/
|
||||||
|
private List<String> gatewayIgnoreUrl=new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*各个服务自定义忽略的url---配置在自己的服务
|
||||||
|
*/
|
||||||
|
private List<String> customIgnoreUrl= new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否验证权限----配置在idaas服务
|
||||||
|
*/
|
||||||
|
private Boolean verifyPermission=true;
|
||||||
|
/**
|
||||||
|
* 只验证token不验证 权限的
|
||||||
|
*/
|
||||||
|
private List<String> onlyVerifyToken=new ArrayList<>();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package ai.remi.comm.core.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 流程审批常量信息
|
||||||
|
*/
|
||||||
|
public class ApprovalStatusConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 待审批
|
||||||
|
*/
|
||||||
|
public static final Integer DSP = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批中
|
||||||
|
*/
|
||||||
|
public static final Integer SPZ = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批完成
|
||||||
|
*/
|
||||||
|
public static final Integer SPWC = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已撤销
|
||||||
|
*/
|
||||||
|
public static final Integer YCX = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已驳回
|
||||||
|
*/
|
||||||
|
public static final Integer YBH = 4;
|
||||||
|
}
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
package ai.remi.comm.core.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 通用常量信息
|
||||||
|
*/
|
||||||
|
public class Constants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UTF-8 字符集
|
||||||
|
*/
|
||||||
|
public static final String UTF8 = "UTF-8";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GBK 字符集
|
||||||
|
*/
|
||||||
|
public static final String GBK = "GBK";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RMI 远程方法调用
|
||||||
|
*/
|
||||||
|
public static final String LOOKUP_RMI = "rmi:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LDAP 远程方法调用
|
||||||
|
*/
|
||||||
|
public static final String LOOKUP_LDAP = "ldap:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LDAPS 远程方法调用
|
||||||
|
*/
|
||||||
|
public static final String LOOKUP_LDAPS = "ldaps:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http请求
|
||||||
|
*/
|
||||||
|
public static final String HTTP = "http://";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https请求
|
||||||
|
*/
|
||||||
|
public static final String HTTPS = "https://";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成功标记
|
||||||
|
*/
|
||||||
|
public static final String SUCCESS = "000000";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 失败标记
|
||||||
|
*/
|
||||||
|
public static final String ERROR = "111111";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录成功状态
|
||||||
|
*/
|
||||||
|
public static final String LOGIN_SUCCESS_STATUS = "0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录失败状态
|
||||||
|
*/
|
||||||
|
public static final String LOGIN_FAIL_STATUS = "1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录成功
|
||||||
|
*/
|
||||||
|
public static final String LOGIN_SUCCESS = "Success";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录失败
|
||||||
|
*/
|
||||||
|
public static final String LOGIN_FAIL = "Error";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注销
|
||||||
|
*/
|
||||||
|
public static final String LOGOUT = "Logout";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册
|
||||||
|
*/
|
||||||
|
public static final String REGISTER = "Register";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前记录起始索引
|
||||||
|
*/
|
||||||
|
public static final String PAGE_NUM = "pageNum";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每页显示记录数
|
||||||
|
*/
|
||||||
|
public static final String PAGE_SIZE = "pageSize";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序列
|
||||||
|
*/
|
||||||
|
public static final String ORDER_BY_COLUMN = "orderByColumn";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序的方向 "desc" 或者 "asc".
|
||||||
|
*/
|
||||||
|
public static final String IS_ASC = "isAsc";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码 redis key
|
||||||
|
*/
|
||||||
|
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码有效期(分钟)
|
||||||
|
*/
|
||||||
|
public static final long CAPTCHA_EXPIRATION = 2;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数管理 cache key
|
||||||
|
*/
|
||||||
|
public static final String SYS_CONFIG_KEY = "sys_config:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典管理 cache key
|
||||||
|
*/
|
||||||
|
public static final String SYS_DICT_KEY = "sys_dict:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源映射路径 前缀
|
||||||
|
*/
|
||||||
|
public static final String RESOURCE_PREFIX = "/profile";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
|
||||||
|
*/
|
||||||
|
public static final String[] JOB_WHITELIST_STR = {"ai.remi"};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时任务违规的字符
|
||||||
|
*/
|
||||||
|
public static final String[] JOB_ERROR_STR = {"java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
|
||||||
|
"org.springframework", "org.apache", "ai.remi.comm.core.utils.file"};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统市公司编号
|
||||||
|
*/
|
||||||
|
public static final String SYS_COMPANY_ID = "1667075454562709506";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录无权限
|
||||||
|
*/
|
||||||
|
public static final String LOGIN_NO_PERMISSION = "401";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 无权限访问资源
|
||||||
|
*/
|
||||||
|
public static final String CODE_401 = "401";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前角色权限不足
|
||||||
|
*/
|
||||||
|
public static final String CODE_403 = "403";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SRS校验数据错误码
|
||||||
|
*/
|
||||||
|
public static final String SRS_DATA_CHECK_ERROR = "A02001";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能检验错误码
|
||||||
|
*/
|
||||||
|
public static final String COMM_CHECK_ERROR = "222222";
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package ai.remi.comm.core.constant;
|
||||||
|
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 过滤器忽略常量
|
||||||
|
*/
|
||||||
|
public class FilterIgnoreConstant {
|
||||||
|
/**
|
||||||
|
* 默认全部忽略的url 一般用于跟服务无关的
|
||||||
|
*/
|
||||||
|
public static final Set<String> FILTER_COMMON_IGNORE_URL = Sets.newHashSet("/**/swagger**/**", "/**/webjars/**",
|
||||||
|
"/**/v2/api-docs", "/**/v3/api-docs", "/**/error", "/**/doc.html", "/doc.html", "/**/favicon.ico");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局拦截器忽略的服务
|
||||||
|
*/
|
||||||
|
public static final Set<String> AUTH_FILTER_IGNORE_SERVICE_NAME = Sets.newHashSet("remi-ids-web","remi-ams-web","remi-mps-web","remi-sso-web","remi-dfe-web","remi-wfe-web","remi-bie-web","remi-wpe-web","remi-job-web","remi-lce-web");
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package ai.remi.comm.core.constant;
|
||||||
|
|
||||||
|
import ai.remi.comm.core.enums.IdentityTypeEnum;
|
||||||
|
import ai.remi.comm.core.enums.PermissionScopeEnum;
|
||||||
|
import ai.remi.comm.core.enums.ServiceTypeEnum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 全局请求头常量
|
||||||
|
*/
|
||||||
|
public class HeaderConstant {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门租户id
|
||||||
|
*/
|
||||||
|
public static final String X_DEPT_TENANT_ID = "X-DEPT-TENANT-ID";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公司租户id
|
||||||
|
*/
|
||||||
|
public static final String X_COMPANY_TENANT_ID = "X-COMPANY-TENANT-ID";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前登陆人唯一id
|
||||||
|
*/
|
||||||
|
public static final String X_UNIQUE_ID = "X-UNIQUE-ID";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户系统语言
|
||||||
|
*/
|
||||||
|
public static final String X_USER_LANGUAGE = "X-USER-LANGUAGE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户设备唯一标识
|
||||||
|
*/
|
||||||
|
public static final String X_DISTINCT_ID = "X-DISTINCT-ID";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录token
|
||||||
|
*/
|
||||||
|
public static final String X_ACCESS_TOKEN = "X-ACCESS-TOKEN";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务类型
|
||||||
|
*
|
||||||
|
* @see ServiceTypeEnum
|
||||||
|
*/
|
||||||
|
public static final String X_SERVICE_TYPE = "X-SERVICE-TYPE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 身份类型 公司用户 访客用户 瑞米用户
|
||||||
|
*
|
||||||
|
* @see IdentityTypeEnum
|
||||||
|
*/
|
||||||
|
public static final String X_IDENTITY_TYPE = "X-IDENTITY-TYPE";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 此请求头为用户请求过来的为集团还是公司权限
|
||||||
|
*
|
||||||
|
* @see PermissionScopeEnum
|
||||||
|
*/
|
||||||
|
public static final String X_PERMISSION_SCOPE = "X-PERMISSION-SCOPE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当权限类型为集团类型时,此请求头包含的为这个用户管理的所有公司id {@link PermissionScopeEnum}
|
||||||
|
*/
|
||||||
|
public static final String X_COMPANY_IDS = "X-COMPANY-IDS";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当权限类型为公司类型时,此请求头包含的为这个用户管理的所有部门id {@link PermissionScopeEnum}
|
||||||
|
*/
|
||||||
|
public static final String X_DEPT_IDS = "X-DEPT-IDS";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求/响应头报文类型
|
||||||
|
*/
|
||||||
|
public static final String CONTENT_TYPE = "Content-Type";
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package ai.remi.comm.core.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc HTTP状态码
|
||||||
|
*/
|
||||||
|
public class HttpStatus {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作成功
|
||||||
|
*/
|
||||||
|
public static final int SUCCESS = 200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对象创建成功
|
||||||
|
*/
|
||||||
|
public static final int CREATED = 201;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求已经被接受
|
||||||
|
*/
|
||||||
|
public static final int ACCEPTED = 202;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作已经执行成功,但是没有返回数据
|
||||||
|
*/
|
||||||
|
public static final int NO_CONTENT = 204;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源已被移除
|
||||||
|
*/
|
||||||
|
public static final int MOVED_PERM = 301;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重定向
|
||||||
|
*/
|
||||||
|
public static final int SEE_OTHER = 303;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源没有被修改
|
||||||
|
*/
|
||||||
|
public static final int NOT_MODIFIED = 304;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数列表错误(缺少,格式不匹配)
|
||||||
|
*/
|
||||||
|
public static final int BAD_REQUEST = 400;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未授权
|
||||||
|
*/
|
||||||
|
public static final int UNAUTHORIZED = 401;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问受限,授权过期
|
||||||
|
*/
|
||||||
|
public static final int FORBIDDEN = 403;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源,服务未找到
|
||||||
|
*/
|
||||||
|
public static final int NOT_FOUND = 404;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不允许的http方法
|
||||||
|
*/
|
||||||
|
public static final int BAD_METHOD = 405;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源冲突,或者资源被锁
|
||||||
|
*/
|
||||||
|
public static final int CONFLICT = 409;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不支持的数据,媒体类型
|
||||||
|
*/
|
||||||
|
public static final int UNSUPPORTED_TYPE = 415;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统内部错误
|
||||||
|
*/
|
||||||
|
public static final int ERROR = 500;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接口未实现
|
||||||
|
*/
|
||||||
|
public static final int NOT_IMPLEMENTED = 501;
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package ai.remi.comm.core.constant;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc OAuth2异常常量
|
||||||
|
*/
|
||||||
|
public class OAuth2Constants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 认证异常
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum Error {
|
||||||
|
USERNAME_NOT_FOUND("username_not_found", "用户名未找到", ""),
|
||||||
|
BAD_CREDENTIALS("bad_credentials", "错误凭证", "AbstractUserDetailsAuthenticationProvider.badCredentials : Bad credentials"),
|
||||||
|
USER_LOCKED("user_locked", "用户被锁", "AbstractUserDetailsAuthenticationProvider.locked : User account is locked"),
|
||||||
|
USER_DISABLE("user_disable", "用户禁用", "AbstractUserDetailsAuthenticationProvider.disabled : User is disabled"),
|
||||||
|
USER_EXPIRED("user_expired", "用户过期", "AbstractUserDetailsAuthenticationProvider.expired : User account has expired"),
|
||||||
|
CREDENTIALS_EXPIRED("credentials_expired", "证书过期", "AbstractUserDetailsAuthenticationProvider.credentialsExpired : User credentials have expired"),
|
||||||
|
INVALID_SCOPE("invalid_scope", "无效作用域", "AbstractAccessDecisionManager.accessDenied : invalid_scope"),
|
||||||
|
SCOPE_IS_EMPTY("scope_is_empty", "scope 为空异常", ""),
|
||||||
|
TOKEN_MISSING("token_missing", "令牌不存在", ""),
|
||||||
|
UN_KNOW_LOGIN_ERROR("un_know_login_error", "未知的登录异常", ""),
|
||||||
|
INVALID_BEARER_TOKEN("invalid_bearer_token", "不合法的Token", "");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
private final String msg;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package ai.remi.comm.core.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc Token的Key通用常量
|
||||||
|
*/
|
||||||
|
public class TokenConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 令牌自定义标识
|
||||||
|
*/
|
||||||
|
public static final String AUTHENTICATION = "Authorization";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 补充令牌自定义标识
|
||||||
|
*/
|
||||||
|
public static final String SUPPLY_AUTHORIZATION = "X-Access-Token";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 令牌前缀
|
||||||
|
*/
|
||||||
|
public static final String PREFIX = "Remi";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回调地址
|
||||||
|
*/
|
||||||
|
public static final String REDIRECT_URL = "redirect_url";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 令牌秘钥
|
||||||
|
*/
|
||||||
|
public final static String SECRET = "ce6e6cc15d0349b58f9d8c43e5f328ce7f329029434242c6aaaec5a06b930a4a4d73cf1a7e7b48eb80fad6a916ded78d614cc2e63779489d9a2aaaafd674c5515e708ba5869a4dcfa3e66799";
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
package ai.remi.comm.core.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 用户常量信息
|
||||||
|
*/
|
||||||
|
public class UserConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 平台内系统用户的唯一标志
|
||||||
|
*/
|
||||||
|
public static final String SYS_USER = "SYS_USER";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正常状态
|
||||||
|
*/
|
||||||
|
public static final String NORMAL = "0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异常状态
|
||||||
|
*/
|
||||||
|
public static final String EXCEPTION = "1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户封禁状态
|
||||||
|
*/
|
||||||
|
public static final String USER_DISABLE = "1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色封禁状态
|
||||||
|
*/
|
||||||
|
public static final String ROLE_DISABLE = "1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门正常状态
|
||||||
|
*/
|
||||||
|
public static final String DEPT_NORMAL = "0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门停用状态
|
||||||
|
*/
|
||||||
|
public static final String DEPT_DISABLE = "1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典正常状态
|
||||||
|
*/
|
||||||
|
public static final String DICT_NORMAL = "0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为系统默认(是)
|
||||||
|
*/
|
||||||
|
public static final String YES = "Y";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否菜单外链(是)
|
||||||
|
*/
|
||||||
|
public static final String YES_FRAME = "0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否菜单外链(否)
|
||||||
|
*/
|
||||||
|
public static final String NO_FRAME = "1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单类型(目录)
|
||||||
|
*/
|
||||||
|
public static final String TYPE_DIR = "M";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单类型(菜单)
|
||||||
|
*/
|
||||||
|
public static final String TYPE_MENU = "C";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单类型(按钮)
|
||||||
|
*/
|
||||||
|
public static final String TYPE_BUTTON = "F";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layout组件标识
|
||||||
|
*/
|
||||||
|
public final static String LAYOUT = "Layout";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ParentView组件标识
|
||||||
|
*/
|
||||||
|
public final static String PARENT_VIEW = "ParentView";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* InnerLink组件标识
|
||||||
|
*/
|
||||||
|
public final static String INNER_LINK = "InnerLink";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验返回结果码
|
||||||
|
*/
|
||||||
|
public final static String UNIQUE = "0";
|
||||||
|
|
||||||
|
public final static String NOT_UNIQUE = "1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户名长度限制
|
||||||
|
*/
|
||||||
|
public static final int USERNAME_MIN_LENGTH = 2;
|
||||||
|
|
||||||
|
public static final int USERNAME_MAX_LENGTH = 20;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码长度限制
|
||||||
|
*/
|
||||||
|
public static final int PASSWORD_MIN_LENGTH = 5;
|
||||||
|
|
||||||
|
public static final int PASSWORD_MAX_LENGTH = 20;
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package ai.remi.comm.core.enums;
|
||||||
|
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 请求方式
|
||||||
|
*/
|
||||||
|
public enum HttpMethod {
|
||||||
|
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
|
||||||
|
|
||||||
|
private static final Map<String, HttpMethod> mappings = new HashMap<>(16);
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (HttpMethod httpMethod : values()) {
|
||||||
|
mappings.put(httpMethod.name(), httpMethod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static HttpMethod resolve(@Nullable String method) {
|
||||||
|
return (method != null ? mappings.get(method) : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(String method) {
|
||||||
|
return (this == resolve(method));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package ai.remi.comm.core.enums;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 身份类型枚举定义
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public enum IdentityTypeEnum {
|
||||||
|
|
||||||
|
STARTDIS("remi", "瑞米官方账号"),
|
||||||
|
COMPANY("company", "集团公司账户"),
|
||||||
|
VISITOR("visitor", "游客体验账号");
|
||||||
|
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
private String desc;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package ai.remi.comm.core.enums;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 权限范围枚举定义
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum PermissionScopeEnum {
|
||||||
|
|
||||||
|
GROUP("group","集团范围"),
|
||||||
|
COMPANY("company","公司范围"),
|
||||||
|
DEPT("dept","部门范围");
|
||||||
|
|
||||||
|
@JsonValue
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
private String desc;
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
public static PermissionScopeEnum codeOf(String code) {
|
||||||
|
return Arrays.stream(PermissionScopeEnum.values())
|
||||||
|
.filter(each -> each.getCode().equals(code))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> {
|
||||||
|
throw new IllegalArgumentException("非法参数");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package ai.remi.comm.core.enums;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 错误码设计描述
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public enum ServiceTypeEnum {
|
||||||
|
|
||||||
|
WEB_SERVICE("webService", "/web-api/**", "管理端服务"),
|
||||||
|
APP_SERVICE("appService", "/app-api/**", "移动端服务");
|
||||||
|
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务对应的路径前缀
|
||||||
|
*/
|
||||||
|
private String pathPrefix;
|
||||||
|
|
||||||
|
private String desc;
|
||||||
|
|
||||||
|
|
||||||
|
public static ServiceTypeEnum codeOf(String code) {
|
||||||
|
return Arrays.stream(values())
|
||||||
|
.filter((each) -> each.getCode().equals(code)).findFirst()
|
||||||
|
.orElseThrow(()->new RuntimeException("找不到服务"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServiceTypeEnum pathPrefixOf(String pathPrefix){
|
||||||
|
return Arrays.stream(values())
|
||||||
|
.filter((each) -> each.getPathPrefix().equals(pathPrefix)).findFirst()
|
||||||
|
.orElseThrow(()->new RuntimeException("找不到服务"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package ai.remi.comm.core.enums;
|
||||||
|
|
||||||
|
public interface TypeEnum {
|
||||||
|
/**
|
||||||
|
* 类型编码
|
||||||
|
*/
|
||||||
|
Integer getCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型描述
|
||||||
|
*/
|
||||||
|
String getDesc();
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package ai.remi.comm.core.enums;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum YesNoEnum implements TypeEnum{
|
||||||
|
|
||||||
|
NO(0, "否"),
|
||||||
|
|
||||||
|
YES(1, "是");
|
||||||
|
|
||||||
|
@JsonValue
|
||||||
|
private Integer code;
|
||||||
|
|
||||||
|
private String desc;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package ai.remi.comm.core.excel;
|
||||||
|
|
||||||
|
public interface ExcelDynamicSelect {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取动态生成的下拉框可选数据
|
||||||
|
* @return 动态生成的下拉框可选数据
|
||||||
|
*/
|
||||||
|
String[] getSource();
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package ai.remi.comm.core.excel;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
@Documented
|
||||||
|
@Target({ElementType.FIELD})//用此注解用在属性上。
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
|
||||||
|
public @interface ExcelSelected {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 固定下拉内容
|
||||||
|
*/
|
||||||
|
String[] source() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态下拉内容
|
||||||
|
*/
|
||||||
|
Class<? extends ExcelDynamicSelect>[] sourceClass() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置下拉框的起始行,默认为第二行
|
||||||
|
*/
|
||||||
|
int firstRow() default 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置下拉框的结束行,默认为最后一行
|
||||||
|
*/
|
||||||
|
int lastRow() default 0x10000;
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package ai.remi.comm.core.result;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc PagerBean
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class PagerBean<T> implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 4804053559968742915L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总记录数
|
||||||
|
*/
|
||||||
|
private Long total;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前页
|
||||||
|
*/
|
||||||
|
protected Long pageNum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页大小
|
||||||
|
*/
|
||||||
|
protected Long pageSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表数据
|
||||||
|
*/
|
||||||
|
private List<?> records;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否可导入
|
||||||
|
*/
|
||||||
|
private boolean if_import;
|
||||||
|
public PagerBean() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public PagerBean(Long total, Long pageNum, Long pageSize, List<T> records) {
|
||||||
|
this.total = total;
|
||||||
|
this.pageNum = pageNum;
|
||||||
|
this.pageSize = pageSize;
|
||||||
|
this.records = records;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package ai.remi.comm.core.result;
|
||||||
|
|
||||||
|
import ai.remi.comm.core.constant.Constants;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc ResultBean
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@SuperBuilder
|
||||||
|
public class ResultBean<T> implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 8676131899637805509L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成功
|
||||||
|
*/
|
||||||
|
public static final String SUCCESS = Constants.SUCCESS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 失败
|
||||||
|
*/
|
||||||
|
public static final String ERROR = Constants.ERROR;
|
||||||
|
|
||||||
|
// 返回编码
|
||||||
|
private String code;
|
||||||
|
// 返回信息
|
||||||
|
private String msg;
|
||||||
|
// 返回数据封装
|
||||||
|
@Builder.Default
|
||||||
|
private T data = (T) "";
|
||||||
|
|
||||||
|
public ResultBean() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> ResultBean<T> restResult(String code, String msg, T data) {
|
||||||
|
ResultBean<T> apiResult = new ResultBean<>();
|
||||||
|
apiResult.setCode(code);
|
||||||
|
apiResult.setData(data);
|
||||||
|
apiResult.setMsg(msg);
|
||||||
|
return apiResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回成功消息
|
||||||
|
*
|
||||||
|
* @return 成功消息
|
||||||
|
*/
|
||||||
|
public static <T> ResultBean<T> success() {
|
||||||
|
return restResult(SUCCESS, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ResultBean<T> success(String msg) {
|
||||||
|
return restResult(SUCCESS, msg, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ResultBean<T> success(T data) {
|
||||||
|
return restResult(SUCCESS, null, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ResultBean<T> success(String msg, T data) {
|
||||||
|
return restResult(SUCCESS, msg, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ResultBean<T> error() {
|
||||||
|
return restResult(ERROR, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ResultBean<T> error(String msg) {
|
||||||
|
return restResult(ERROR, msg, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ResultBean<T> error(T data) {
|
||||||
|
return restResult(ERROR, null, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ResultBean<T> error(String msg, T data) {
|
||||||
|
return restResult(ERROR, msg, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ResultBean<T> error(String code, String msg, T data) {
|
||||||
|
return restResult(code, msg, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package ai.remi.comm.core.spring;
|
||||||
|
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc SpringBeanUtils
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class SpringBeans implements ApplicationContextAware {
|
||||||
|
|
||||||
|
private static ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||||
|
if (SpringBeans.applicationContext == null) {
|
||||||
|
SpringBeans.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by dianjiu on 2022-06-23 ,contact lidianjiu@njydsz.com. 获取applicationContext.
|
||||||
|
*/
|
||||||
|
public static ApplicationContext getApplicationContext() {
|
||||||
|
return applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by dianjiu on 2022-06-23 ,contact lidianjiu@njydsz.com. 通过name获取 Bean.
|
||||||
|
*/
|
||||||
|
public static Object getBean(String name) {
|
||||||
|
return getApplicationContext().getBean(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by dianjiu on 2022-06-23 ,contact lidianjiu@njydsz.com. 通过class获取Bean.
|
||||||
|
*/
|
||||||
|
public static <T> T getBean(Class<T> clazz) {
|
||||||
|
return getApplicationContext().getBean(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by dianjiu on 2022-06-23 ,contact lidianjiu@njydsz.com. 通过name,以及Clazz返回指定的Bean.
|
||||||
|
*/
|
||||||
|
public static <T> T getBean(String name, Class<T> clazz) {
|
||||||
|
return getApplicationContext().getBean(name, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据clazz类型获取spring容器中的对象
|
||||||
|
*/
|
||||||
|
public static <T> Map<String, T> getBeansOfType(Class<T> clazz) {
|
||||||
|
return getApplicationContext().getBeansOfType(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据注解类从容器中获取对象
|
||||||
|
*/
|
||||||
|
public static <T> Map<String, Object> getBeansOfAnnotation(Class<? extends Annotation> clazz) {
|
||||||
|
return getApplicationContext().getBeansWithAnnotation(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package ai.remi.comm.core.spring;
|
||||||
|
|
||||||
|
import org.springframework.context.EnvironmentAware;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 通过"server.port"作为name格式调用getPropertiesValue()方法
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class SpringProperties implements EnvironmentAware {
|
||||||
|
|
||||||
|
private static Environment env;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEnvironment(Environment environment) {
|
||||||
|
env = environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getString(String key) {
|
||||||
|
return env.getProperty(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
ai.remi.comm.core.config.AuthFilterConfig,\
|
||||||
|
ai.remi.comm.core.spring.SpringProperties,\
|
||||||
|
ai.remi.comm.core.spring.SpringBeans
|
||||||
|
|
||||||
|
|
||||||
87
remi-comm/remi-comm-domain/pom.xml
Normal file
87
remi-comm/remi-comm-domain/pom.xml
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>remi-comm-domain</artifactId>
|
||||||
|
<name>remi-comm-domain</name>
|
||||||
|
<description>remi-comm-domain</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm</artifactId>
|
||||||
|
<version>3.1.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<!-- 打包上传到私服, 需要和配置文件中的server节点配合使用 -->
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>maven-releases</id>
|
||||||
|
<name>release</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-releases/</url>
|
||||||
|
</repository>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>maven-snapshots</id>
|
||||||
|
<name>snapshot</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-snapshots/</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!--remi-comm-core-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--remi-comm-util-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm-util</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--mybatis-plus-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-annotation</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--jackson-core -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-annotations</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- validator -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-validator</groupId>
|
||||||
|
<artifactId>commons-validator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate.validator</groupId>
|
||||||
|
<artifactId>hibernate-validator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-validator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--mapstruct-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct-processor</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--lombok-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package ai.remi.comm.domain.entity;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc BaseEntity
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@SuperBuilder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||||
|
public class BaseEntity implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 乐观锁
|
||||||
|
*/
|
||||||
|
@Version
|
||||||
|
@TableField("revision")
|
||||||
|
private Integer revision;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 逻辑删除 (0正常 1删除)
|
||||||
|
* value = "" 默认的原值,默认为 0;
|
||||||
|
* delval = "" 删除后的值,默认为1;
|
||||||
|
*/
|
||||||
|
// @TableLogic(value="0",delval="1")
|
||||||
|
@TableField("deleted")
|
||||||
|
private Integer deleted;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门租户ID
|
||||||
|
*/
|
||||||
|
@TableField("dept_tenant_id")
|
||||||
|
private String deptTenantId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公司租户ID
|
||||||
|
*/
|
||||||
|
@TableField("company_tenant_id")
|
||||||
|
private String companyTenantId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建人
|
||||||
|
*/
|
||||||
|
@TableField("created_by")
|
||||||
|
private String createdBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "created_at", fill = FieldFill.INSERT)
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新人
|
||||||
|
*/
|
||||||
|
@TableField("updated_by")
|
||||||
|
private String updatedBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "updated_at", fill = FieldFill.UPDATE)
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package ai.remi.comm.domain.entity;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc RootEntity
|
||||||
|
*/
|
||||||
|
public interface RootEntity extends Serializable {
|
||||||
|
|
||||||
|
public String getId();
|
||||||
|
|
||||||
|
public RootEntity setId(String id);
|
||||||
|
|
||||||
|
public Integer getRevision();
|
||||||
|
|
||||||
|
public RootEntity setRevision(Integer revision);
|
||||||
|
|
||||||
|
public Integer getDeleted();
|
||||||
|
|
||||||
|
public RootEntity setDeleted(Integer deleted);
|
||||||
|
|
||||||
|
public String getDeptTenantId();
|
||||||
|
|
||||||
|
public RootEntity setDeptTenantId(String deptTenantId);
|
||||||
|
|
||||||
|
public String getCompanyTenantId();
|
||||||
|
|
||||||
|
public RootEntity setCompanyTenantId(String companyTenantId);
|
||||||
|
|
||||||
|
public String getCreatedBy();
|
||||||
|
|
||||||
|
public RootEntity setCreatedBy(String createdBy);
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedAt();
|
||||||
|
|
||||||
|
public RootEntity setCreatedAt(LocalDateTime createdAt);
|
||||||
|
|
||||||
|
public String getUpdatedBy();
|
||||||
|
|
||||||
|
public RootEntity setUpdatedBy(String updatedBy);
|
||||||
|
|
||||||
|
public LocalDateTime getUpdatedAt();
|
||||||
|
|
||||||
|
public RootEntity setUpdatedAt(LocalDateTime updatedAt);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package ai.remi.comm.domain.query;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc PageQuery
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@SuperBuilder(toBuilder = true)
|
||||||
|
public class PageQuery implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前页
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "pageNum当前页不能为空")
|
||||||
|
private Integer pageNum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页大小
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "pageSize页大小不能为空")
|
||||||
|
private Integer pageSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定排序字段
|
||||||
|
*/
|
||||||
|
private String orderBy;
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package ai.remi.comm.domain.tree;
|
||||||
|
|
||||||
|
import ai.remi.comm.util.collection.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TreeBuild<T extends TreeNode> {
|
||||||
|
/**
|
||||||
|
* rootId
|
||||||
|
*/
|
||||||
|
public String rootId;
|
||||||
|
/**
|
||||||
|
* 保存参与构建树形的所有数据(通常数据库查询结果)
|
||||||
|
*/
|
||||||
|
public List<T> nodeList = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造方法
|
||||||
|
*
|
||||||
|
* @param nodeList 将数据集合赋值给nodeList,即所有数据作为所有节点。
|
||||||
|
*/
|
||||||
|
public TreeBuild(String rootId, List<T> nodeList) {
|
||||||
|
this.rootId = rootId;
|
||||||
|
this.nodeList = nodeList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取需构建的所有根节点(顶级节点) "0"
|
||||||
|
*
|
||||||
|
* @return 所有根节点List集合
|
||||||
|
*/
|
||||||
|
public List<T> getRootNode() {
|
||||||
|
// 保存所有根节点(所有根节点的数据)
|
||||||
|
List<T> rootNodeList = new ArrayList<>();
|
||||||
|
// treeNode:查询出的每一条数据(节点)
|
||||||
|
for (T treeNode : nodeList) {
|
||||||
|
// 判断当前节点是否为根节点,此处注意:若parentId类型是String,则要采用equals()方法判断。
|
||||||
|
if (this.rootId.equals(treeNode.getParentId())) {
|
||||||
|
// 是,添加
|
||||||
|
rootNodeList.add(treeNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rootNodeList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据每一个顶级节点(根节点)进行构建树形结构
|
||||||
|
*
|
||||||
|
* @return 构建整棵树
|
||||||
|
*/
|
||||||
|
public List<T> buildTree() {
|
||||||
|
// treeNodes:保存一个顶级节点所构建出来的完整树形
|
||||||
|
List<T> treeNodes = new ArrayList<T>();
|
||||||
|
// getRootNode():获取所有的根节点
|
||||||
|
for (T treeRootNode : getRootNode()) {
|
||||||
|
// 将顶级节点进行构建子树
|
||||||
|
treeRootNode = buildChildTree(treeRootNode);
|
||||||
|
// 完成一个顶级节点所构建的树形,增加进来
|
||||||
|
treeNodes.add(treeRootNode);
|
||||||
|
}
|
||||||
|
// 这里对父节点排序
|
||||||
|
CollectionUtils.sort(treeNodes, "sort");
|
||||||
|
// for循环结束,即获取所有的根节点,树形构建结束,设置树结果
|
||||||
|
return treeNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归-----构建子树形结构
|
||||||
|
*
|
||||||
|
* @param pNode 根节点(顶级节点)
|
||||||
|
* @return 整棵树
|
||||||
|
*/
|
||||||
|
public T buildChildTree(T pNode) {
|
||||||
|
List<T> childTree = new ArrayList<T>();
|
||||||
|
// nodeList:所有节点集合(所有数据)
|
||||||
|
for (T treeNode : nodeList) {
|
||||||
|
// 判断当前节点的父节点ID是否等于根节点的ID,即当前节点为其下的子节点
|
||||||
|
if (treeNode.getParentId().equals(pNode.getId())) {
|
||||||
|
// 再递归进行判断当前节点的情况,调用自身方法
|
||||||
|
childTree.add(buildChildTree(treeNode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 这里对子节点排序
|
||||||
|
CollectionUtils.sort(childTree, "sort");
|
||||||
|
// for循环结束,即节点下没有任何节点,树形构建结束,设置树结果
|
||||||
|
pNode.setChildren(childTree);
|
||||||
|
return pNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package ai.remi.comm.domain.tree;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc ResultBean
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@SuperBuilder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||||
|
public class TreeNode<T extends TreeNode> implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 8676131899637805509L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前节点ID
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父节点ID 顶级节点为0
|
||||||
|
*/
|
||||||
|
private String parentId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子节点
|
||||||
|
*/
|
||||||
|
private List<T> children;
|
||||||
|
}
|
||||||
57
remi-comm/remi-comm-email/pom.xml
Normal file
57
remi-comm/remi-comm-email/pom.xml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>remi-comm-email</artifactId>
|
||||||
|
<name>remi-comm-email</name>
|
||||||
|
<description>remi-comm-email</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm</artifactId>
|
||||||
|
<version>3.1.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<!-- 打包上传到私服, 需要和配置文件中的server节点配合使用 -->
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>maven-releases</id>
|
||||||
|
<name>release</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-releases/</url>
|
||||||
|
</repository>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>maven-snapshots</id>
|
||||||
|
<name>snapshot</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-snapshots/</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!--common-core-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--springboot-mail整合包-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-mail</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- thymeleaf 模版 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- freemarker 模版 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--slf4j-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package ai.remi.comm.email.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email startdis@njydsz.com
|
||||||
|
* @desc MinioConfig
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties(EmailProperties.class)
|
||||||
|
public class EmailConfig {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private EmailProperties emailProperties;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化 JavaMailSender
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public JavaMailSenderImpl javaMailSenderImpl() {
|
||||||
|
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
|
||||||
|
javaMailSender.setProtocol(emailProperties.getProtocol());
|
||||||
|
javaMailSender.setHost(emailProperties.getSmtpHost());
|
||||||
|
javaMailSender.setPort(Integer.parseInt(emailProperties.getSmtpPort()));
|
||||||
|
javaMailSender.setDefaultEncoding(emailProperties.getEncoding());
|
||||||
|
javaMailSender.setUsername(emailProperties.getFromMail());
|
||||||
|
javaMailSender.setPassword(emailProperties.getPassword());
|
||||||
|
// TODO 设置邮件参数
|
||||||
|
Properties props = new Properties();
|
||||||
|
// props.setProperty("mail.smtp.auth", emailProperties.get());
|
||||||
|
javaMailSender.setJavaMailProperties(props);
|
||||||
|
return javaMailSender;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package ai.remi.comm.email.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email startdis@njydsz.com
|
||||||
|
* @desc Email配置类
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "remi-comm.email")
|
||||||
|
public class EmailProperties {
|
||||||
|
/**
|
||||||
|
* 发送协议
|
||||||
|
*/
|
||||||
|
private String protocol;
|
||||||
|
/**
|
||||||
|
* 服务器地址
|
||||||
|
*/
|
||||||
|
private String smtpHost;
|
||||||
|
/**
|
||||||
|
* 服务器端口
|
||||||
|
*/
|
||||||
|
private String smtpPort;
|
||||||
|
/**
|
||||||
|
* 发件人名称
|
||||||
|
*/
|
||||||
|
private String fromName;
|
||||||
|
/**
|
||||||
|
* 发件人邮箱
|
||||||
|
*/
|
||||||
|
private String fromMail;
|
||||||
|
/**
|
||||||
|
* 发件人密码
|
||||||
|
*/
|
||||||
|
private String password;
|
||||||
|
/**
|
||||||
|
* 邮件编码
|
||||||
|
*/
|
||||||
|
private String encoding;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSL配置
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties("remi-comm.email.ssl")
|
||||||
|
class sslConf {
|
||||||
|
private String enabled;
|
||||||
|
private String sslPort;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package ai.remi.comm.email.domain;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@SuperBuilder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class Email {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收件人,多个收件人用“,”隔开
|
||||||
|
*/
|
||||||
|
private String to;
|
||||||
|
/**
|
||||||
|
* 抄送人,多个抄送人用“,”隔开
|
||||||
|
*/
|
||||||
|
private String cc;
|
||||||
|
/**
|
||||||
|
* 密送人,多个密送人用“,”隔开
|
||||||
|
*/
|
||||||
|
private String bcc;
|
||||||
|
/**
|
||||||
|
* 邮件主题
|
||||||
|
*/
|
||||||
|
private String subject;
|
||||||
|
/**
|
||||||
|
* 邮件内容
|
||||||
|
*/
|
||||||
|
private String content;
|
||||||
|
/**
|
||||||
|
* 图片资源路径
|
||||||
|
*/
|
||||||
|
private String rscPath;
|
||||||
|
/**
|
||||||
|
* 图片资源ID(CID)
|
||||||
|
*/
|
||||||
|
private String rscId;
|
||||||
|
/**
|
||||||
|
* 附件路径
|
||||||
|
*/
|
||||||
|
private String[] filePaths;
|
||||||
|
/**
|
||||||
|
* 邮件模板地址
|
||||||
|
*/
|
||||||
|
private String template;
|
||||||
|
/**
|
||||||
|
* 邮件模板变量
|
||||||
|
*/
|
||||||
|
private Map<String, Object> variable;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
package ai.remi.comm.email.service;
|
||||||
|
|
||||||
|
import ai.remi.comm.email.config.EmailProperties;
|
||||||
|
import ai.remi.comm.email.domain.Email;
|
||||||
|
import freemarker.template.Configuration;
|
||||||
|
import freemarker.template.Template;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.core.io.FileSystemResource;
|
||||||
|
import org.springframework.mail.MailException;
|
||||||
|
import org.springframework.mail.SimpleMailMessage;
|
||||||
|
import org.springframework.mail.javamail.JavaMailSender;
|
||||||
|
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
|
||||||
|
import org.thymeleaf.TemplateEngine;
|
||||||
|
import org.thymeleaf.context.Context;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.mail.MessagingException;
|
||||||
|
import javax.mail.internet.MimeMessage;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class EmailService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 邮件配置
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private EmailProperties emailProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 邮件执行
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private JavaMailSender mailSender;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* thymeleaf
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private TemplateEngine templateEngine;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* freemarker
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
public Configuration configuration;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送文本邮件
|
||||||
|
*/
|
||||||
|
public void sendTextMail(Email email) {
|
||||||
|
SimpleMailMessage message = new SimpleMailMessage();
|
||||||
|
try {
|
||||||
|
message.setFrom(emailProperties.getFromName());
|
||||||
|
message.setTo(email.getTo());
|
||||||
|
message.setCc(email.getCc());
|
||||||
|
message.setBcc(email.getBcc());
|
||||||
|
message.setSubject(email.getSubject());
|
||||||
|
message.setText(email.getContent());
|
||||||
|
mailSender.send(message);
|
||||||
|
log.info("发送基础邮件成功!");
|
||||||
|
} catch (MailException e) {
|
||||||
|
log.error("发送基础邮件异常:" + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送html邮件
|
||||||
|
*/
|
||||||
|
public void sendHtmlMail(Email email) {
|
||||||
|
MimeMessage message = mailSender.createMimeMessage();
|
||||||
|
try {
|
||||||
|
//true表示需要创建一个multipart message
|
||||||
|
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||||
|
helper.setFrom(emailProperties.getFromName());
|
||||||
|
helper.setTo(email.getTo());
|
||||||
|
helper.setSubject(email.getSubject());
|
||||||
|
helper.setText(email.getContent(), true);
|
||||||
|
// 检查附件数组是否为空
|
||||||
|
String[] filePaths = email.getFilePaths();
|
||||||
|
if (checkFilePaths(filePaths)) {
|
||||||
|
for (String filePath : filePaths) {
|
||||||
|
FileSystemResource file = new FileSystemResource(new File(filePath));
|
||||||
|
String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
|
||||||
|
helper.addAttachment(fileName, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mailSender.send(message);
|
||||||
|
log.info("发送html邮件成功");
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
log.error("发送html邮件异常:" + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送正文是静态资源(图片)的邮件
|
||||||
|
*/
|
||||||
|
public void sendInlineMail(Email email) {
|
||||||
|
MimeMessage message = mailSender.createMimeMessage();
|
||||||
|
try {
|
||||||
|
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||||
|
helper.setFrom(emailProperties.getFromName());
|
||||||
|
helper.setTo(email.getTo());
|
||||||
|
helper.setSubject(email.getSubject());
|
||||||
|
helper.setText(email.getContent(), true);
|
||||||
|
// 嵌入静态资源
|
||||||
|
FileSystemResource res = new FileSystemResource(new File(email.getRscPath()));
|
||||||
|
helper.addInline(email.getRscId(), res);
|
||||||
|
// 检查附件数组是否为空
|
||||||
|
String[] filePaths = email.getFilePaths();
|
||||||
|
if (checkFilePaths(filePaths)) {
|
||||||
|
for (String filePath : filePaths) {
|
||||||
|
FileSystemResource file = new FileSystemResource(new File(filePath));
|
||||||
|
String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
|
||||||
|
helper.addAttachment(fileName, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mailSender.send(message);
|
||||||
|
log.info("发送嵌入图片的邮件成功!");
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
log.error("发送嵌入图片的邮件异常:" + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送带附件的邮件
|
||||||
|
*/
|
||||||
|
public void sendAttachmentsMail(Email email) {
|
||||||
|
MimeMessage message = mailSender.createMimeMessage();
|
||||||
|
try {
|
||||||
|
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||||
|
helper.setFrom(emailProperties.getFromName());
|
||||||
|
helper.setTo(email.getTo());
|
||||||
|
helper.setSubject(email.getSubject());
|
||||||
|
helper.setText(email.getContent(), true);
|
||||||
|
// 检查附件数组是否为空
|
||||||
|
String[] filePaths = email.getFilePaths();
|
||||||
|
if (checkFilePaths(filePaths)) {
|
||||||
|
for (String filePath : filePaths) {
|
||||||
|
FileSystemResource file = new FileSystemResource(new File(filePath));
|
||||||
|
String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
|
||||||
|
helper.addAttachment(fileName, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mailSender.send(message);
|
||||||
|
log.info("发送带附件的邮件成功!");
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
log.error("发送带附件的邮件异常:" + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendThymeleafMail(Email email) {
|
||||||
|
MimeMessage message = mailSender.createMimeMessage();
|
||||||
|
try {
|
||||||
|
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||||
|
helper.setFrom(emailProperties.getFromName());
|
||||||
|
helper.setTo(email.getTo());
|
||||||
|
helper.setSubject(email.getSubject());
|
||||||
|
helper.setText(email.getContent(), true);
|
||||||
|
// 设置邮件正文
|
||||||
|
Context context = new Context();
|
||||||
|
context.setVariables(email.getVariable());
|
||||||
|
String htmlContent = templateEngine.process(email.getTemplate(), context);
|
||||||
|
// 检查附件数组是否为空
|
||||||
|
String[] filePaths = email.getFilePaths();
|
||||||
|
if (checkFilePaths(filePaths)) {
|
||||||
|
for (String filePath : filePaths) {
|
||||||
|
FileSystemResource file = new FileSystemResource(new File(filePath));
|
||||||
|
String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
|
||||||
|
helper.addAttachment("瑞米平台:" + fileName, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 第二个参数设置为true表示HTML格式
|
||||||
|
helper.setText(htmlContent, true);
|
||||||
|
mailSender.send(message);
|
||||||
|
log.info("发送Thymeleaf模板邮件成功!");
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
log.error("发送Thymeleaf模板邮件异常:" + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendFreemarkerMail(Email email) {
|
||||||
|
MimeMessage message = mailSender.createMimeMessage();
|
||||||
|
try {
|
||||||
|
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||||
|
helper.setFrom(emailProperties.getFromName());
|
||||||
|
helper.setTo(email.getTo());
|
||||||
|
helper.setSubject(email.getSubject());
|
||||||
|
helper.setText(email.getContent(), true);
|
||||||
|
// 设置邮件正文
|
||||||
|
Template template = configuration.getTemplate(email.getTemplate() + ".flt");
|
||||||
|
String htmlContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, email.getVariable());
|
||||||
|
// 检查附件数组是否为空
|
||||||
|
String[] filePaths = email.getFilePaths();
|
||||||
|
if (checkFilePaths(filePaths)) {
|
||||||
|
for (String filePath : filePaths) {
|
||||||
|
FileSystemResource file = new FileSystemResource(new File(filePath));
|
||||||
|
String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
|
||||||
|
helper.addAttachment("瑞米平台:" + fileName, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 第二个参数设置为true表示HTML格式
|
||||||
|
helper.setText(htmlContent, true);
|
||||||
|
mailSender.send(message);
|
||||||
|
log.info("发送Freemarker模板邮件成功!");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送Freemarker模板邮件异常:" + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean checkFilePaths(String[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
log.info("附件数组为null");
|
||||||
|
return false;
|
||||||
|
} else if (array.length == 0) {
|
||||||
|
log.info("附件数组为空");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
log.info("附件数组不为空且不为null");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
ai.remi.comm.email.service.EmailService
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>${title}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>${greeting}</h1>
|
||||||
|
<p>${message}</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title th:text="${title}">Welcome</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1 th:text="${greeting}">Hello,</h1>
|
||||||
|
<p th:text="${message}">Welcome to our site!</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
6
remi-comm/remi-comm-exception/README.md
Normal file
6
remi-comm/remi-comm-exception/README.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
```yaml
|
||||||
|
i18n:
|
||||||
|
messages:
|
||||||
|
basename: i18n/messages
|
||||||
|
encoding: utf-8
|
||||||
|
```
|
||||||
55
remi-comm/remi-comm-exception/pom.xml
Normal file
55
remi-comm/remi-comm-exception/pom.xml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>remi-comm-exception</artifactId>
|
||||||
|
<name>remi-comm-exception</name>
|
||||||
|
<description>remi-comm-exception</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm</artifactId>
|
||||||
|
<version>3.1.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<!-- 打包上传到私服, 需要和配置文件中的server节点配合使用 -->
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>maven-releases</id>
|
||||||
|
<name>release</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-releases/</url>
|
||||||
|
</repository>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>maven-snapshots</id>
|
||||||
|
<name>snapshot</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-snapshots/</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!--remi-comm-domain-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm-domain</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--spring-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-aop</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--slf4j-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-nop</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package ai.remi.comm.exception.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
|
||||||
|
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class I18nConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
//@Value("${i18n.messages.basename:}")
|
||||||
|
//private String messagesBasename;
|
||||||
|
|
||||||
|
//@Value("${i18n.messages.encoding:}")
|
||||||
|
//private String messagesEncoding;
|
||||||
|
|
||||||
|
@Bean(name = "messageSource")
|
||||||
|
public ReloadableResourceBundleMessageSource messageSource() {
|
||||||
|
ReloadableResourceBundleMessageSource rbms = new ReloadableResourceBundleMessageSource();
|
||||||
|
//if (!StringUtils.isEmpty(messagesBasename)) {
|
||||||
|
// //设置path
|
||||||
|
// rbms.addBasenames(messagesBasename.split(","));
|
||||||
|
//}
|
||||||
|
//rbms.setDefaultEncoding(messagesEncoding);
|
||||||
|
rbms.setBasenames("classpath:i18n/messages");
|
||||||
|
rbms.setDefaultEncoding("UTF-8");
|
||||||
|
rbms.setUseCodeAsDefaultMessage(true);
|
||||||
|
rbms.setFallbackToSystemLocale(false);
|
||||||
|
return rbms;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LocalValidatorFactoryBean getValidator() {
|
||||||
|
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
|
||||||
|
bean.setValidationMessageSource(messageSource());
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package ai.remi.comm.exception.custom;
|
||||||
|
|
||||||
|
import ai.remi.comm.core.constant.Constants;
|
||||||
|
import ai.remi.comm.exception.util.MessageUtils;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc BusinessException
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class BusinessException extends RuntimeException {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private String code;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private String key;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private Object[] params;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public BusinessException(String key) {
|
||||||
|
super(MessageUtils.getMessage(key));
|
||||||
|
this.code = Constants.ERROR;
|
||||||
|
this.message = MessageUtils.getMessage(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(String key, Object[] params) {
|
||||||
|
super(MessageUtils.getMessage(key, params));
|
||||||
|
this.code = Constants.ERROR;
|
||||||
|
this.message = MessageUtils.getMessage(key, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(String code, String key) {
|
||||||
|
super(MessageUtils.getMessage(key));
|
||||||
|
this.code = code;
|
||||||
|
this.message = MessageUtils.getMessage(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(String code, String key, Object[] params) {
|
||||||
|
super(MessageUtils.getMessage(key, params));
|
||||||
|
this.code = code;
|
||||||
|
this.message = MessageUtils.getMessage(key, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(String code, Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(String code, String key, Throwable cause) {
|
||||||
|
super(MessageUtils.getMessage(key), cause);
|
||||||
|
this.code = code;
|
||||||
|
this.message = MessageUtils.getMessage(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(String code, String key, Object[] params, Throwable cause) {
|
||||||
|
super(MessageUtils.getMessage(key, params), cause);
|
||||||
|
this.code = code;
|
||||||
|
this.message = MessageUtils.getMessage(key, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(String code, String key, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(MessageUtils.getMessage(key), cause, enableSuppression, writableStackTrace);
|
||||||
|
this.code = code;
|
||||||
|
this.message = MessageUtils.getMessage(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(String code, String key, Object[] params, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(MessageUtils.getMessage(key, params), cause, enableSuppression, writableStackTrace);
|
||||||
|
this.code = code;
|
||||||
|
this.message = MessageUtils.getMessage(key, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package ai.remi.comm.exception.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 错误码设计描述
|
||||||
|
* <p>
|
||||||
|
* 面向日志的错误码定义共十三位(十位有意义,三位连接符),并且应该具有如下分类: 应用标识,表示错误属于哪个应用,三位数字。 功能域标识,表示错误属于应用中的哪个功能模块,三位数字。 错误类型,表示错误属于那种类型,一位字母。
|
||||||
|
* 错误编码,错误类型下的具体错误,三位数字。
|
||||||
|
* <p>
|
||||||
|
* 面向外部传递的错误码共六位,并且有如下分类: 错误类型,表示错误来源,1位字母。 应用标识,表示错误属于哪个应用,2位数字。 错误编码,错误类型下的具体错误,3位数字。
|
||||||
|
* <p>
|
||||||
|
* 错误类型: A-表示错误来源于用户 B-表示错误来源于系统 C-表示错误来源于第三方接口
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum CommExceptionCode implements ExceptionCode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 面向外部传递的错误码共六位,并且有如下分类:
|
||||||
|
* 错误类型,表示错误来源,1位字母。
|
||||||
|
* 应用标识,表示错误属于哪个应用,2位数字。
|
||||||
|
* 错误编码,错误类型下的具体错误,3位数字。
|
||||||
|
* <p>
|
||||||
|
* 错误类型: A-表示错误来源于用户 B-表示错误来源于系统 C-表示错误来源于第三方接口
|
||||||
|
*/
|
||||||
|
/****************************客户端异常****************************/
|
||||||
|
BUSINESS_ERROR("A01001", "business.error"),
|
||||||
|
ILLEGAL_ARGUMENT("A01002", "illegal.argument"),
|
||||||
|
NOT_LOGGED_IN("A01003", "not.logged.in"),
|
||||||
|
/****************************系统异常****************************/
|
||||||
|
SYSTEM_ERROR("B01001", "system.error"),
|
||||||
|
ASSERT_ERROR("B01002", "assert.error"),
|
||||||
|
/****************************三方异常****************************/
|
||||||
|
OTHER_SYSTEM_ERROR("C01001", "other.system.error"),
|
||||||
|
CALL_FEIGN_ERROR("C01002", "call.feign.error"),
|
||||||
|
CALL_SQL_ERROR("C01003", "call.sql.error"),
|
||||||
|
CALL_REDIS_ERROR("C01004", "call.redis.error"),
|
||||||
|
CALL_MINIO_ERROR("C01005", "call.minio.error"),
|
||||||
|
CALL_NACOS_ERROR("C01006", "call.nacos.error"),
|
||||||
|
CALL_JOB_ERROR("C01007", "call.job.error"),
|
||||||
|
CALL_MQ_ERROR("C01008", "call.mq.error"),
|
||||||
|
CALL_ES_ERROR("C01009", "call.es.error");
|
||||||
|
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
private String key;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package ai.remi.comm.exception.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异常code接口
|
||||||
|
*/
|
||||||
|
public interface ExceptionCode {
|
||||||
|
/**
|
||||||
|
* 异常code
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String getCode();
|
||||||
|
/**
|
||||||
|
* 异常消息
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String getKey();
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package ai.remi.comm.exception.util;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc ExceptionUtils
|
||||||
|
*/
|
||||||
|
public class ExceptionUtils {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取exception的详细错误信息。
|
||||||
|
*/
|
||||||
|
public static String getTrace(Throwable e) {
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
e.printStackTrace(new PrintWriter(sw, true));
|
||||||
|
return sw.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
package ai.remi.comm.exception.util;
|
||||||
|
|
||||||
|
import ai.remi.comm.core.spring.SpringBeans;
|
||||||
|
import ai.remi.comm.util.auth.AuthInfoUtils;
|
||||||
|
import ai.remi.comm.util.string.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.MessageSource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc MessageUtils
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class MessageUtils {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(MessageUtils.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得多语言内容,默认根据当前用户的Local获取
|
||||||
|
*
|
||||||
|
* @param key 多语言key
|
||||||
|
* @return 翻译后的值,如获取不到则返回key
|
||||||
|
*/
|
||||||
|
public static String getMessage(String key) {
|
||||||
|
return getMessage(key, new Object[]{});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得多语言内容--带参数,默认根据当前用户的Local获取
|
||||||
|
*
|
||||||
|
* @param key 多语言key
|
||||||
|
* @param params 参数
|
||||||
|
* @return 翻译后的值,如获取不到则返回key
|
||||||
|
*/
|
||||||
|
public static String getMessage(String key, Object[] params) {
|
||||||
|
Locale locale = getLocale();
|
||||||
|
if (params == null) {
|
||||||
|
params = new Object[]{};
|
||||||
|
}
|
||||||
|
return getMessage(locale, key, params);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取多语言内容--带默认值,默认根据当前用户的Local获取
|
||||||
|
*
|
||||||
|
* @param key 多语言key
|
||||||
|
* @param defaultMsg 默认返回值
|
||||||
|
* @return 翻译后的值,获取不到返回默认值
|
||||||
|
*/
|
||||||
|
public static String getMessage(String key, String defaultMsg) {
|
||||||
|
return getMessage(key, new Object[]{}, defaultMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得多语言内容--带参数--带默认值,默认根据当前用户的Local获取
|
||||||
|
*
|
||||||
|
* @param key 多语言key
|
||||||
|
* @param defaultMsg 默认返回值
|
||||||
|
* @param params 参数
|
||||||
|
* @return 翻译后的值,获取不到返回默认值
|
||||||
|
*/
|
||||||
|
public static String getMessage(String key, Object[] params, String defaultMsg) {
|
||||||
|
Locale locale = getLocale();
|
||||||
|
return getMessage(locale, key, params, defaultMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不带参数
|
||||||
|
*
|
||||||
|
* @param locale 语言信息
|
||||||
|
* @param key 多语言key
|
||||||
|
* @return 翻译后的值
|
||||||
|
*/
|
||||||
|
public static String getMessage(Locale locale, String key) {
|
||||||
|
return getMessage(locale, key, new Object[]{});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取多语言数据
|
||||||
|
*
|
||||||
|
* @param locale 语言信息
|
||||||
|
* @param key 多语言key
|
||||||
|
* @param params 参数
|
||||||
|
* @return 翻译后的值
|
||||||
|
*/
|
||||||
|
public static String getMessage(Locale locale, String key, Object[] params) {
|
||||||
|
try {
|
||||||
|
MessageSource messageSource = (MessageSource) SpringBeans.getBean("messageSource");
|
||||||
|
return messageSource.getMessage(key, params, locale);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("get locale msg error", e);
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取多语言数据
|
||||||
|
*
|
||||||
|
* @param key 多语言key
|
||||||
|
* @param params 参数
|
||||||
|
* @param defaultMsg 默认返回值
|
||||||
|
* @param locale 语言信息
|
||||||
|
* @return 翻译后的值
|
||||||
|
*/
|
||||||
|
public static String getMessage(Locale locale, String key, Object[] params, String defaultMsg) {
|
||||||
|
MessageSource messageSource = (MessageSource) SpringBeans.getBean("messageSource");
|
||||||
|
return messageSource.getMessage(key, params, defaultMsg, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前语言
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static Locale getLocale() {
|
||||||
|
String userLanguage = AuthInfoUtils.getUserLanguage();
|
||||||
|
if (StringUtils.isBlank(userLanguage)) {
|
||||||
|
return Locale.CHINA;
|
||||||
|
}
|
||||||
|
switch (userLanguage.toLowerCase()) {
|
||||||
|
case "zh_cn":
|
||||||
|
case "zh-CN":
|
||||||
|
case "zh":
|
||||||
|
return Locale.CHINA;
|
||||||
|
default:
|
||||||
|
return Locale.US;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
ai.remi.comm.exception.config.I18nConfig
|
||||||
59
remi-comm/remi-comm-feign/pom.xml
Normal file
59
remi-comm/remi-comm-feign/pom.xml
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>remi-comm-feign</artifactId>
|
||||||
|
<name>remi-comm-feign</name>
|
||||||
|
<description>remi-comm-feign</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm</artifactId>
|
||||||
|
<version>3.1.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<!-- 打包上传到私服, 需要和配置文件中的server节点配合使用 -->
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>maven-releases</id>
|
||||||
|
<name>release</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-releases/</url>
|
||||||
|
</repository>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>maven-snapshots</id>
|
||||||
|
<name>snapshot</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-snapshots/</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!--openfeign-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--remi-comm-util-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm-util</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--servlet-api-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--slf4j-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-nop</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package ai.remi.comm.feign.annotation;
|
||||||
|
|
||||||
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Remi
|
||||||
|
* @email remi@dianjiu.cc
|
||||||
|
* @desc 自定义feign注解,添加basePackages路径
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
@EnableFeignClients
|
||||||
|
public @interface EnableRemiFeignClients {
|
||||||
|
String[] value() default {};
|
||||||
|
|
||||||
|
String[] basePackages() default {"ai.remi"};
|
||||||
|
|
||||||
|
Class<?>[] basePackageClasses() default {};
|
||||||
|
|
||||||
|
Class<?>[] defaultConfiguration() default {};
|
||||||
|
|
||||||
|
Class<?>[] clients() default {};
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package ai.remi.comm.feign.aspect;
|
||||||
|
|
||||||
|
import feign.Logger;
|
||||||
|
import feign.RequestInterceptor;
|
||||||
|
import feign.codec.ErrorDecoder;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Remi
|
||||||
|
* @email remi@dianjiu.cc
|
||||||
|
* @desc Feign 配置注册
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class FeignAutoConfiguration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义请求拦截器
|
||||||
|
* 传递用户信息请求头,防止丢失
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public RequestInterceptor requestInterceptor() {
|
||||||
|
return new FeignRequestInterceptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置Feign客户端日志级别
|
||||||
|
* <p>
|
||||||
|
* 有四种日志记录级别可供选择:
|
||||||
|
* <p>
|
||||||
|
* - NONE – 不记录日志,这是默认设置
|
||||||
|
* - BASIC – 仅记录请求方法、URL 和响应状态
|
||||||
|
* - HEADERS – 将基本信息与请求和响应标头一起记录
|
||||||
|
* - FULL – 记录请求和响应的主体、标头和元数据
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
Logger.Level level() {
|
||||||
|
return Logger.Level.FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feign 的默认错误处理程序ErrorDecoder.default总是抛出FeignException。
|
||||||
|
* 种行为并不总是最有用的。因此,要自定义抛出的异常
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public ErrorDecoder errorDecoder() {
|
||||||
|
return new RemiFeignErrorDecoder();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package ai.remi.comm.feign.aspect;
|
||||||
|
|
||||||
|
import ai.remi.comm.core.constant.HeaderConstant;
|
||||||
|
import ai.remi.comm.core.enums.IdentityTypeEnum;
|
||||||
|
import ai.remi.comm.core.enums.PermissionScopeEnum;
|
||||||
|
import ai.remi.comm.util.auth.AuthInfoUtils;
|
||||||
|
import ai.remi.comm.util.http.ServletUtils;
|
||||||
|
import ai.remi.comm.util.ip.IpAddrUtils;
|
||||||
|
import ai.remi.comm.util.string.StringUtils;
|
||||||
|
import feign.RequestInterceptor;
|
||||||
|
import feign.RequestTemplate;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Remi
|
||||||
|
* @email remi@dianjiu.cc
|
||||||
|
* @desc Feign 请求拦截器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class FeignRequestInterceptor implements RequestInterceptor {
|
||||||
|
private Logger log = LoggerFactory.getLogger(FeignRequestInterceptor.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(RequestTemplate requestTemplate) {
|
||||||
|
HttpServletRequest httpServletRequest = ServletUtils.getRequest();
|
||||||
|
Map<String, String> headers = ServletUtils.getHeaders(httpServletRequest);
|
||||||
|
// 传递用户信息请求头,防止丢失
|
||||||
|
//String userId = headers.get(HeaderConstant.X_UNIQUE_ID);
|
||||||
|
if (StringUtils.isNotNull(httpServletRequest)) {
|
||||||
|
// 传递服务类型请求头,防止丢失
|
||||||
|
log.info("FeignHeaderRequestInterceptor X_SERVICE_TYPE:{}", AuthInfoUtils.getServiceTypeCode());
|
||||||
|
requestTemplate.header(HeaderConstant.X_SERVICE_TYPE, AuthInfoUtils.getServiceTypeCode());
|
||||||
|
// 传递部门租户请求头,防止丢失
|
||||||
|
requestTemplate.header(HeaderConstant.X_DEPT_TENANT_ID, AuthInfoUtils.getDeptTenantId());
|
||||||
|
// 传递公司租户请求头,防止丢失
|
||||||
|
requestTemplate.header(HeaderConstant.X_COMPANY_TENANT_ID, AuthInfoUtils.getCompanyTenantId());
|
||||||
|
// 传递用户信息请求头,防止丢失
|
||||||
|
requestTemplate.header(HeaderConstant.X_UNIQUE_ID, AuthInfoUtils.getUniqueId());
|
||||||
|
// 传递系统语言请求头,防止丢失
|
||||||
|
requestTemplate.header(HeaderConstant.X_USER_LANGUAGE, AuthInfoUtils.getUserLanguage());
|
||||||
|
// 传递用户设备请求头,防止丢失
|
||||||
|
requestTemplate.header(HeaderConstant.X_DISTINCT_ID, headers.get(HeaderConstant.X_DISTINCT_ID));
|
||||||
|
// 传递鉴权信息请求头,防止丢失
|
||||||
|
requestTemplate.header(HeaderConstant.X_ACCESS_TOKEN, headers.get(HeaderConstant.X_ACCESS_TOKEN));
|
||||||
|
|
||||||
|
// 判断用户类型是否为集团公司,是的话进一步判断是否为集团权限,是集团权限需要传递集团下属公司IDs
|
||||||
|
IdentityTypeEnum identityTypeEnum = AuthInfoUtils.getIdentityTypeEnum();
|
||||||
|
//集团公司的用户
|
||||||
|
if (identityTypeEnum == IdentityTypeEnum.COMPANY) {
|
||||||
|
//权限范围
|
||||||
|
String permissionScope = Optional.ofNullable(AuthInfoUtils.getPermissionScopeEnum())
|
||||||
|
.map(PermissionScopeEnum::getCode).orElse("");
|
||||||
|
requestTemplate.header(HeaderConstant.X_PERMISSION_SCOPE, permissionScope);
|
||||||
|
//当权限范围为集团时,为这个用户管理公司的id
|
||||||
|
requestTemplate.header(HeaderConstant.X_COMPANY_IDS, AuthInfoUtils.getHasPermissionCompanyIds());
|
||||||
|
//当权限范围为公司时,为这个用户管理部门的id
|
||||||
|
requestTemplate.header(HeaderConstant.X_COMPANY_IDS, AuthInfoUtils.getHasPermissionCompanyIds());
|
||||||
|
} else if (identityTypeEnum == IdentityTypeEnum.VISITOR) {
|
||||||
|
//访客体验的用户 do anything
|
||||||
|
}
|
||||||
|
|
||||||
|
// 传递请求来源请求头,防止丢失
|
||||||
|
requestTemplate.header("X-Forwarded-For", IpAddrUtils.getIpAddr(ServletUtils.getRequest()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package ai.remi.comm.feign.aspect;
|
||||||
|
|
||||||
|
import ai.remi.comm.feign.exception.BadRequestException;
|
||||||
|
import ai.remi.comm.feign.exception.NotFoundException;
|
||||||
|
import ai.remi.comm.feign.exception.OpenFeignException;
|
||||||
|
import feign.Response;
|
||||||
|
import feign.codec.ErrorDecoder;
|
||||||
|
|
||||||
|
public class RemiFeignErrorDecoder implements ErrorDecoder {
|
||||||
|
@Override
|
||||||
|
public Exception decode(String methodKey, Response response) {
|
||||||
|
|
||||||
|
return switch (response.status()) {
|
||||||
|
case 400 -> new BadRequestException();
|
||||||
|
case 404 -> new NotFoundException("Remi Feign ");
|
||||||
|
default -> new OpenFeignException("Remi Feign error");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package ai.remi.comm.feign.exception;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Remi
|
||||||
|
* @email remi@dianjiu.cc
|
||||||
|
* @desc BadRequestException
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class BadRequestException extends RuntimeException {
|
||||||
|
public BadRequestException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package ai.remi.comm.feign.exception;
|
||||||
|
|
||||||
|
import ai.remi.comm.core.constant.Constants;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Remi
|
||||||
|
* @email remi@dianjiu.cc
|
||||||
|
* @desc NotFoundException
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class NotFoundException extends Exception {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private String code;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public NotFoundException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
this.code = Constants.ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotFoundException(String msg, Exception e) {
|
||||||
|
super(msg + " not found,because of" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package ai.remi.comm.feign.exception;
|
||||||
|
|
||||||
|
import ai.remi.comm.core.constant.Constants;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Remi
|
||||||
|
* @email remi@dianjiu.cc
|
||||||
|
* @desc OpenFeignException
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class OpenFeignException extends RuntimeException {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private String code;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private Object data;
|
||||||
|
|
||||||
|
public OpenFeignException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenFeignException(String message) {
|
||||||
|
super(message);
|
||||||
|
this.code = Constants.ERROR;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenFeignException(String code, String message) {
|
||||||
|
super(message);
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenFeignException(String code, Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
this.code = code;
|
||||||
|
this.message = cause.getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenFeignException(String code, String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenFeignException(String code, String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
90
remi-comm/remi-comm-jdbc/pom.xml
Normal file
90
remi-comm/remi-comm-jdbc/pom.xml
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>remi-comm-jdbc</artifactId>
|
||||||
|
<name>remi-comm-jdbc</name>
|
||||||
|
<description>remi-comm-jdbc</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm</artifactId>
|
||||||
|
<version>3.1.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<!-- 打包上传到私服, 需要和配置文件中的server节点配合使用 -->
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>maven-releases</id>
|
||||||
|
<name>release</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-releases/</url>
|
||||||
|
</repository>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>maven-snapshots</id>
|
||||||
|
<name>snapshot</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-snapshots/</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!--remi-comm-core-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--remi-comm-util-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm-util</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- mybatis-plus -->
|
||||||
|
<dependency>
|
||||||
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<artifactId>mybatis-plus-annotation</artifactId>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-extension</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--mybatis-->
|
||||||
|
<dependency>
|
||||||
|
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||||
|
<groupId>org.mybatis.spring.boot</groupId>
|
||||||
|
</dependency>
|
||||||
|
<!-- druid-->
|
||||||
|
<dependency>
|
||||||
|
<artifactId>druid-spring-boot-starter</artifactId>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
</dependency>
|
||||||
|
<!--jdbc-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- mysql -->
|
||||||
|
<dependency>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<!--slf4j-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-nop</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package ai.remi.comm.jdbc.config;
|
||||||
|
|
||||||
|
import ai.remi.comm.jdbc.handler.CompanyTenantHandler;
|
||||||
|
import ai.remi.comm.jdbc.handler.DeptTenantHandler;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 自动配置类
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@Import({CompanyTenantHandler.class, DeptTenantHandler.class,TenantConfig.class})
|
||||||
|
public class AutoConfig {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package ai.remi.comm.jdbc.config;
|
||||||
|
|
||||||
|
import com.alibaba.druid.pool.DruidDataSource;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc DruidConfig 配置类
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class DruidConfig {
|
||||||
|
|
||||||
|
/*
|
||||||
|
将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建
|
||||||
|
绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效
|
||||||
|
@ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中
|
||||||
|
前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties(prefix = "spring.datasource")
|
||||||
|
@Bean
|
||||||
|
public DataSource druidDataSource() {
|
||||||
|
return new DruidDataSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package ai.remi.comm.jdbc.config;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 字段填充配置类
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "sql-intercept.field-fill")
|
||||||
|
public class FieldFillConfig {
|
||||||
|
|
||||||
|
private InterceptConfig createdByIntercept=new InterceptConfig();
|
||||||
|
|
||||||
|
private InterceptConfig updateByIntercept=new InterceptConfig();
|
||||||
|
|
||||||
|
private InterceptConfig createAtIntercept=new InterceptConfig();
|
||||||
|
|
||||||
|
private InterceptConfig updateAtIntercept=new InterceptConfig();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package ai.remi.comm.jdbc.config;
|
||||||
|
|
||||||
|
import ai.remi.comm.jdbc.enums.InterceptTableStrategy;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 拦截器配置类
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class InterceptConfig {
|
||||||
|
/**
|
||||||
|
* 拦截表策略,默认拦截不包含这些表
|
||||||
|
*/
|
||||||
|
private InterceptTableStrategy interceptTableStrategy = InterceptTableStrategy.EXCLUDE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否打开拦截配置
|
||||||
|
*/
|
||||||
|
private Boolean enable = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不拦截或拦截的表
|
||||||
|
*/
|
||||||
|
private Set<String> tables = new HashSet<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理的字段
|
||||||
|
*/
|
||||||
|
private String column = "";
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
package ai.remi.comm.jdbc.config;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.DbType;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
||||||
|
import ai.remi.comm.jdbc.handler.*;
|
||||||
|
import ai.remi.comm.jdbc.interceptor.FieldFillInterceptor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc MybatisPlusConfig 配置类
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
@MapperScan(value = {"ai.remi.*.infra.mapper"})
|
||||||
|
public class MybatisPlusConfig {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TenantConfig tenantConfig;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private FieldFillConfig fieldFillConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页插件
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||||
|
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||||
|
// 多租户(部门)拦截器
|
||||||
|
Boolean deptTenantEnable = tenantConfig.getDeptTenant().getEnable();
|
||||||
|
if (deptTenantEnable){
|
||||||
|
TenantLineInnerInterceptor tenantSqlParser = new TenantLineInnerInterceptor();
|
||||||
|
tenantSqlParser.setTenantLineHandler(getDeptTenantInterceptor());
|
||||||
|
interceptor.addInnerInterceptor(tenantSqlParser);
|
||||||
|
log.info("----------------部门租户拦截器开启-----------------------");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 多租户(公司)拦截器
|
||||||
|
Boolean companyTenantEnable = tenantConfig.getCompanyTenant().getEnable();
|
||||||
|
if (companyTenantEnable){
|
||||||
|
TenantLineInnerInterceptor dealerSqlParser = new TenantLineInnerInterceptor();
|
||||||
|
dealerSqlParser.setTenantLineHandler(getCompanyTenantInterceptor());
|
||||||
|
interceptor.addInnerInterceptor(dealerSqlParser);
|
||||||
|
log.info("----------------公司租户拦截器开启-----------------------");
|
||||||
|
}
|
||||||
|
|
||||||
|
//创建人填充
|
||||||
|
Boolean createByEnable = fieldFillConfig.getCreatedByIntercept().getEnable();
|
||||||
|
if (createByEnable){
|
||||||
|
FieldFillInterceptor createByInterceptor = new FieldFillInterceptor();
|
||||||
|
createByInterceptor.setFieldFillHandler(getCreatedByHandler());
|
||||||
|
interceptor.addInnerInterceptor(createByInterceptor);
|
||||||
|
log.info("----------------创建人填充器开启-----------------------");
|
||||||
|
}
|
||||||
|
|
||||||
|
//更新人填充
|
||||||
|
Boolean updateByEnable = fieldFillConfig.getUpdateByIntercept().getEnable();
|
||||||
|
if (updateByEnable){
|
||||||
|
FieldFillInterceptor updateByInterceptor = new FieldFillInterceptor();
|
||||||
|
updateByInterceptor.setFieldFillHandler(getUpdatedByHandler());
|
||||||
|
interceptor.addInnerInterceptor(updateByInterceptor);
|
||||||
|
log.info("----------------更新人填充器开启-----------------------");
|
||||||
|
}
|
||||||
|
|
||||||
|
//创建时间
|
||||||
|
Boolean createAtEnable = fieldFillConfig.getCreateAtIntercept().getEnable();
|
||||||
|
if (createAtEnable){
|
||||||
|
FieldFillInterceptor createAtInterceptor = new FieldFillInterceptor();
|
||||||
|
createAtInterceptor.setFieldFillHandler(getCreatedAtHandler());
|
||||||
|
interceptor.addInnerInterceptor(createAtInterceptor);
|
||||||
|
log.info("----------------创建时间填充器开启-----------------------");
|
||||||
|
}
|
||||||
|
//更新时间
|
||||||
|
Boolean updateAtEnable = fieldFillConfig.getUpdateAtIntercept().getEnable();
|
||||||
|
if (updateAtEnable){
|
||||||
|
FieldFillInterceptor updateAtInterceptor = new FieldFillInterceptor();
|
||||||
|
updateAtInterceptor.setFieldFillHandler(getUpdatedAtHandler());
|
||||||
|
interceptor.addInnerInterceptor(updateAtInterceptor);
|
||||||
|
log.info("----------------更新时间填充器开启-----------------------");
|
||||||
|
}
|
||||||
|
|
||||||
|
//自带分页拦截器
|
||||||
|
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
|
||||||
|
|
||||||
|
//自带乐观锁插件
|
||||||
|
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
|
||||||
|
|
||||||
|
return interceptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public UpdatedByHandler getUpdatedByHandler(){
|
||||||
|
return new UpdatedByHandler(fieldFillConfig);
|
||||||
|
}
|
||||||
|
@Bean
|
||||||
|
public UpdatedAtHandler getUpdatedAtHandler(){
|
||||||
|
return new UpdatedAtHandler(fieldFillConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CreatedByHandler getCreatedByHandler(){
|
||||||
|
return new CreatedByHandler(fieldFillConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CreatedAtHandler getCreatedAtHandler(){
|
||||||
|
return new CreatedAtHandler(fieldFillConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DeptTenantHandler getDeptTenantInterceptor() {
|
||||||
|
return new DeptTenantHandler(tenantConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CompanyTenantHandler getCompanyTenantInterceptor() {
|
||||||
|
return new CompanyTenantHandler(tenantConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package ai.remi.comm.jdbc.config;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 租户配置类
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "sql-intercept.tenant")
|
||||||
|
public class TenantConfig {
|
||||||
|
|
||||||
|
//不拦截的请求
|
||||||
|
private String anonUrlSet="";
|
||||||
|
|
||||||
|
private InterceptConfig deptTenant=new InterceptConfig();
|
||||||
|
|
||||||
|
private InterceptConfig companyTenant=new InterceptConfig();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package ai.remi.comm.jdbc.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据源
|
||||||
|
*
|
||||||
|
* @author DianJiu 【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @date 2022-07-19
|
||||||
|
*/
|
||||||
|
public enum DataSourceType {
|
||||||
|
/**
|
||||||
|
* 主库
|
||||||
|
*/
|
||||||
|
MASTER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从库
|
||||||
|
*/
|
||||||
|
SLAVE
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package ai.remi.comm.jdbc.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 字段填充策略枚举
|
||||||
|
*/
|
||||||
|
public enum FieldFillStrategyEnum {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插入时填充字段
|
||||||
|
*/
|
||||||
|
INSERT,
|
||||||
|
/**
|
||||||
|
* 更新时填充字段
|
||||||
|
*/
|
||||||
|
UPDATE,
|
||||||
|
/**
|
||||||
|
* 插入和更新时填充字段
|
||||||
|
*/
|
||||||
|
INSERT_UPDATE
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package ai.remi.comm.jdbc.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 拦截表策略
|
||||||
|
*/
|
||||||
|
public enum InterceptTableStrategy {
|
||||||
|
INCLUDE,
|
||||||
|
EXCLUDE;
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package ai.remi.comm.jdbc.handler;
|
||||||
|
|
||||||
|
import ai.remi.comm.jdbc.config.InterceptConfig;
|
||||||
|
import ai.remi.comm.jdbc.enums.FieldFillStrategyEnum;
|
||||||
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 字段填充拦截器抽象类
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("checkstyle:Indentation")
|
||||||
|
public abstract class AbstractFieldFillHandler extends AbstractSqlHandler implements FieldFillHandler {
|
||||||
|
|
||||||
|
|
||||||
|
private FieldFillStrategyEnum fieldFillStrategyEnum;
|
||||||
|
|
||||||
|
public AbstractFieldFillHandler(FieldFillStrategyEnum fieldFillStrategyEnum, InterceptConfig interceptConfig) {
|
||||||
|
super(interceptConfig);
|
||||||
|
this.fieldFillStrategyEnum = fieldFillStrategyEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected abstract Expression doGetFieldFillValue();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Expression getFieldFillValue() {
|
||||||
|
return doGetFieldFillValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优先级配置填充字段--》子类实现getDefaultFieldFillColumn
|
||||||
|
* 如果都为指定则抛出异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getFieldFillColumn() {
|
||||||
|
return handleColumn(interceptConfig.getColumn());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean createIgnore(String tableName) {
|
||||||
|
if (FieldFillStrategyEnum.UPDATE==fieldFillStrategyEnum){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return defaultIgnoreStrategy(tableName,interceptConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean customIgnore(){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean updateIgnore(String tableName) {
|
||||||
|
if (FieldFillStrategyEnum.INSERT==fieldFillStrategyEnum){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return defaultIgnoreStrategy(tableName,interceptConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package ai.remi.comm.jdbc.handler;
|
||||||
|
|
||||||
|
import ai.remi.comm.jdbc.config.InterceptConfig;
|
||||||
|
import ai.remi.comm.jdbc.enums.InterceptTableStrategy;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc SQL拦截器抽象类
|
||||||
|
*/
|
||||||
|
public abstract class AbstractSqlHandler {
|
||||||
|
|
||||||
|
protected InterceptConfig interceptConfig;
|
||||||
|
|
||||||
|
public AbstractSqlHandler(InterceptConfig interceptConfig) {
|
||||||
|
this.interceptConfig = interceptConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean defaultIgnoreStrategy(String tableName, InterceptConfig interceptConfig) {
|
||||||
|
if (customIgnore()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
InterceptTableStrategy interceptTableStrategy = interceptConfig.getInterceptTableStrategy();
|
||||||
|
Set<String> tables = interceptConfig.getTables();
|
||||||
|
if (InterceptTableStrategy.EXCLUDE.equals(interceptTableStrategy)) {
|
||||||
|
return tables.contains(tableName);
|
||||||
|
} else if (InterceptTableStrategy.INCLUDE.equals(interceptTableStrategy)) {
|
||||||
|
return !tables.contains(tableName);
|
||||||
|
}else {
|
||||||
|
throw new RuntimeException("未指定表拦截策略");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果传入的字段名为空串,则获取默认的字段
|
||||||
|
* @param column
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected String handleColumn(String column) {
|
||||||
|
if (isNotBlank(column)){
|
||||||
|
return column;
|
||||||
|
}
|
||||||
|
column = getDefaultColumn();
|
||||||
|
if (isNotBlank(column)){
|
||||||
|
return column;
|
||||||
|
}
|
||||||
|
throw new RuntimeException(this.getClass()+"未指定填充字段,请检查");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isNotBlank(String str) {
|
||||||
|
return str!=null&&str.trim().length() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子类实现指定 字段名
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected String getDefaultColumn(){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子类需要实现自定义忽略策略
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected abstract boolean customIgnore();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package ai.remi.comm.jdbc.handler;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
|
||||||
|
import ai.remi.comm.jdbc.config.InterceptConfig;
|
||||||
|
import ai.remi.comm.util.auth.TenantHolder;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
|
import net.sf.jsqlparser.expression.StringValue;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 租户拦截器抽象类
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public abstract class AbstractTenantHandler extends AbstractSqlHandler implements TenantLineHandler {
|
||||||
|
|
||||||
|
|
||||||
|
@Value("${spring.application.name}")
|
||||||
|
private String applicationContextName;
|
||||||
|
|
||||||
|
private final static List<String> IGNORE_APP_NAME = List.of("remi-ids-web","remi-ams-web","remi-mps-web","remi-sso-web","remi-dfe-web","remi-wfe-web","remi-bie-web","remi-wpe-web","remi-job-web","remi-lce-web");
|
||||||
|
|
||||||
|
|
||||||
|
public AbstractTenantHandler(InterceptConfig interceptConfig) {
|
||||||
|
super(interceptConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected abstract String doGetTenantId();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Expression getTenantId() {
|
||||||
|
return new StringValue(doGetTenantId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTenantIdColumn() {
|
||||||
|
return handleColumn(interceptConfig.getColumn());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean ignoreTable(String tableName) {
|
||||||
|
return defaultIgnoreStrategy(tableName, interceptConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean customIgnore(){
|
||||||
|
// 忽略的服务
|
||||||
|
if (IGNORE_APP_NAME.contains(applicationContextName)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Boolean isAdmin=Optional.ofNullable(TenantHolder.isAdmin()).orElse(false);
|
||||||
|
// 是否是不拦截的请求
|
||||||
|
Boolean ignoredRequest = Optional.ofNullable(TenantHolder.getIgnoredRequest()).orElse(false);
|
||||||
|
// 拦截未打开、忽略的请求、ebg账号---》这些情况都忽略掉
|
||||||
|
return ignoredRequest || isAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package ai.remi.comm.jdbc.handler;
|
||||||
|
|
||||||
|
import ai.remi.comm.jdbc.config.TenantConfig;
|
||||||
|
import ai.remi.comm.util.auth.AuthInfoUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 部门租户ID字段填充拦截器
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class CompanyTenantHandler extends AbstractTenantHandler {
|
||||||
|
|
||||||
|
|
||||||
|
public CompanyTenantHandler(TenantConfig tenantConfig) {
|
||||||
|
super(tenantConfig.getCompanyTenant());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String doGetTenantId() {
|
||||||
|
return Optional.ofNullable(AuthInfoUtils.getCompanyTenantId()).orElse("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDefaultColumn() {
|
||||||
|
return "company_tenant_id";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package ai.remi.comm.jdbc.handler;
|
||||||
|
|
||||||
|
import ai.remi.comm.jdbc.config.FieldFillConfig;
|
||||||
|
import ai.remi.comm.jdbc.enums.FieldFillStrategyEnum;
|
||||||
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
|
import net.sf.jsqlparser.expression.TimestampValue;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 创建时间字段填充拦截器
|
||||||
|
*/
|
||||||
|
public class CreatedAtHandler extends AbstractFieldFillHandler {
|
||||||
|
|
||||||
|
public CreatedAtHandler(FieldFillConfig fieldFillConfig) {
|
||||||
|
super(FieldFillStrategyEnum.INSERT, fieldFillConfig.getUpdateAtIntercept());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Expression doGetFieldFillValue() {
|
||||||
|
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
String date = format.format(new Date());
|
||||||
|
return new TimestampValue(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDefaultColumn() {
|
||||||
|
return "created_at";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package ai.remi.comm.jdbc.handler;
|
||||||
|
|
||||||
|
import ai.remi.comm.jdbc.config.FieldFillConfig;
|
||||||
|
import ai.remi.comm.jdbc.enums.FieldFillStrategyEnum;
|
||||||
|
import ai.remi.comm.util.auth.AuthInfo;
|
||||||
|
import ai.remi.comm.util.auth.AuthInfoUtils;
|
||||||
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
|
import net.sf.jsqlparser.expression.StringValue;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 创建人字段填充拦截器
|
||||||
|
*/
|
||||||
|
public class CreatedByHandler extends AbstractFieldFillHandler {
|
||||||
|
|
||||||
|
|
||||||
|
public CreatedByHandler(FieldFillConfig fieldFillConfig) {
|
||||||
|
super(FieldFillStrategyEnum.INSERT, fieldFillConfig.getCreatedByIntercept());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Expression doGetFieldFillValue() {
|
||||||
|
AuthInfo authInfo = AuthInfoUtils.getAuthInfo();
|
||||||
|
String uniqueId = Optional.ofNullable(authInfo)
|
||||||
|
.map(AuthInfo::getUniqueId).orElse("系统创建");
|
||||||
|
return new StringValue(uniqueId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDefaultColumn() {
|
||||||
|
return "created_by";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package ai.remi.comm.jdbc.handler;
|
||||||
|
|
||||||
|
import ai.remi.comm.jdbc.config.TenantConfig;
|
||||||
|
import ai.remi.comm.util.auth.AuthInfoUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 部门租户ID字段填充拦截器
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class DeptTenantHandler extends AbstractTenantHandler {
|
||||||
|
|
||||||
|
public DeptTenantHandler(TenantConfig tenantConfig) {
|
||||||
|
super(tenantConfig.getDeptTenant());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String doGetTenantId() {
|
||||||
|
return Optional.ofNullable(AuthInfoUtils.getDeptTenantId()).orElse("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDefaultColumn() {
|
||||||
|
return "dept_tenant_id";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package ai.remi.comm.jdbc.handler;
|
||||||
|
|
||||||
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 字段填充拦截器
|
||||||
|
*/
|
||||||
|
public interface FieldFillHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取自动填充值表达式
|
||||||
|
*/
|
||||||
|
Expression getFieldFillValue();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取自动填充的字段名
|
||||||
|
*/
|
||||||
|
String getFieldFillColumn();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在创建的时候根据表名判断是否忽略拼接字段
|
||||||
|
*
|
||||||
|
* @param tableName 表名
|
||||||
|
* @return 是否忽略, true:表示忽略,false:需要解析并拼接
|
||||||
|
*/
|
||||||
|
default boolean createIgnore(String tableName){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在更新的时候根据表名判断是否忽略拼接字段
|
||||||
|
*
|
||||||
|
* @param tableName 表名
|
||||||
|
* @return 是否忽略, true:表示忽略,false:需要解析并拼接
|
||||||
|
*/
|
||||||
|
default boolean updateIgnore(String tableName) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package ai.remi.comm.jdbc.handler;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.apache.ibatis.type.BaseTypeHandler;
|
||||||
|
import org.apache.ibatis.type.JdbcType;
|
||||||
|
|
||||||
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc Json类型转换器
|
||||||
|
*/
|
||||||
|
public class JsonTypeHandler<T> extends BaseTypeHandler<T> {
|
||||||
|
|
||||||
|
private static ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
private Class<T> type;
|
||||||
|
|
||||||
|
public JsonTypeHandler(Class<T> type) {
|
||||||
|
if (type == null) {
|
||||||
|
throw new NullPointerException("Type argument cannot be null");
|
||||||
|
}
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
|
||||||
|
ps.setString(i, toJsonString(parameter));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
|
||||||
|
return parse(rs.getString(columnName));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
|
||||||
|
return parse(rs.getString(columnIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
|
||||||
|
return parse(cs.getString(columnIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String toJsonString(Object parameter) {
|
||||||
|
try {
|
||||||
|
return objectMapper.writeValueAsString(parameter);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private T parse(String json) {
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(json, type);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package ai.remi.comm.jdbc.handler;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc List类型转换器
|
||||||
|
*/
|
||||||
|
public class ListTypeHandler extends JsonTypeHandler<List> {
|
||||||
|
public ListTypeHandler() {
|
||||||
|
super(List.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package ai.remi.comm.jdbc.handler;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc Map类型转换器
|
||||||
|
*/
|
||||||
|
public class MapTypeHandler extends JsonTypeHandler<Map> {
|
||||||
|
public MapTypeHandler() {
|
||||||
|
super(Map.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package ai.remi.comm.jdbc.handler;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.ibatis.reflection.MetaObject;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc MyMetaObjectHandler 配置类
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class MyMetaObjectHandler implements MetaObjectHandler {
|
||||||
|
@Override
|
||||||
|
public void insertFill(MetaObject metaObject) {
|
||||||
|
log.info("start insert fill...");
|
||||||
|
this.setFieldValByName("createdAt", LocalDateTime.now(), metaObject);
|
||||||
|
//this.setFieldValByName("createdBy", AuthInfoUtils.getUniqueId(), metaObject);
|
||||||
|
this.setFieldValByName("updatedAt", LocalDateTime.now(), metaObject);
|
||||||
|
//this.setFieldValByName("updatedBy", AuthInfoUtils.getUniqueId(), metaObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateFill(MetaObject metaObject) {
|
||||||
|
log.info("start update fill...");
|
||||||
|
this.setFieldValByName("updatedAt", LocalDateTime.now(), metaObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package ai.remi.comm.jdbc.handler;
|
||||||
|
|
||||||
|
import ai.remi.comm.jdbc.config.FieldFillConfig;
|
||||||
|
import ai.remi.comm.jdbc.enums.FieldFillStrategyEnum;
|
||||||
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
|
import net.sf.jsqlparser.expression.TimestampValue;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 更新时间字段填充拦截器
|
||||||
|
*/
|
||||||
|
public class UpdatedAtHandler extends AbstractFieldFillHandler {
|
||||||
|
|
||||||
|
public UpdatedAtHandler(FieldFillConfig fieldFillConfig) {
|
||||||
|
super(FieldFillStrategyEnum.INSERT_UPDATE, fieldFillConfig.getUpdateAtIntercept());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Expression doGetFieldFillValue() {
|
||||||
|
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
String date = format.format(new Date());
|
||||||
|
return new TimestampValue(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDefaultColumn() {
|
||||||
|
return "updated_at";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package ai.remi.comm.jdbc.handler;
|
||||||
|
|
||||||
|
import ai.remi.comm.jdbc.config.FieldFillConfig;
|
||||||
|
import ai.remi.comm.jdbc.enums.FieldFillStrategyEnum;
|
||||||
|
import ai.remi.comm.util.auth.AuthInfo;
|
||||||
|
import ai.remi.comm.util.auth.AuthInfoUtils;
|
||||||
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
|
import net.sf.jsqlparser.expression.StringValue;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 更新人字段填充拦截器
|
||||||
|
*/
|
||||||
|
public class UpdatedByHandler extends AbstractFieldFillHandler {
|
||||||
|
|
||||||
|
public UpdatedByHandler(FieldFillConfig fieldFillConfig) {
|
||||||
|
super(FieldFillStrategyEnum.INSERT_UPDATE, fieldFillConfig.getUpdateByIntercept());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Expression doGetFieldFillValue() {
|
||||||
|
AuthInfo authInfo = AuthInfoUtils.getAuthInfo();
|
||||||
|
String uniqueId = Optional.ofNullable(authInfo)
|
||||||
|
.map(AuthInfo::getUniqueId).orElse("系统创建");
|
||||||
|
return new StringValue(uniqueId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDefaultColumn() {
|
||||||
|
return "updated_by";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,430 @@
|
|||||||
|
package ai.remi.comm.jdbc.interceptor;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.*;
|
||||||
|
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.toolkit.PropertyMapper;
|
||||||
|
import ai.remi.comm.jdbc.handler.FieldFillHandler;
|
||||||
|
import lombok.*;
|
||||||
|
import net.sf.jsqlparser.expression.*;
|
||||||
|
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
||||||
|
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
||||||
|
import net.sf.jsqlparser.expression.operators.relational.*;
|
||||||
|
import net.sf.jsqlparser.schema.Column;
|
||||||
|
import net.sf.jsqlparser.schema.Table;
|
||||||
|
import net.sf.jsqlparser.statement.delete.Delete;
|
||||||
|
import net.sf.jsqlparser.statement.insert.Insert;
|
||||||
|
import net.sf.jsqlparser.statement.select.*;
|
||||||
|
import net.sf.jsqlparser.statement.update.Update;
|
||||||
|
import org.apache.ibatis.executor.statement.StatementHandler;
|
||||||
|
import org.apache.ibatis.mapping.MappedStatement;
|
||||||
|
import org.apache.ibatis.mapping.SqlCommandType;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dianjiu【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @desc 字段填充拦截器
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class FieldFillInterceptor extends JsqlParserSupport implements InnerInterceptor {
|
||||||
|
|
||||||
|
private FieldFillHandler fieldFillHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拦截器处理前
|
||||||
|
*
|
||||||
|
* @param sh
|
||||||
|
* @param connection
|
||||||
|
* @param transactionTimeout
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
|
||||||
|
PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
|
||||||
|
MappedStatement ms = mpSh.mappedStatement();
|
||||||
|
SqlCommandType sct = ms.getSqlCommandType();
|
||||||
|
if (sct == SqlCommandType.INSERT || sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
|
||||||
|
if (InterceptorIgnoreHelper.willIgnoreTenantLine(ms.getId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
|
||||||
|
mpBs.sql(parserMulti(mpBs.sql(), null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询进程拦截器
|
||||||
|
*
|
||||||
|
* @param select
|
||||||
|
* @param index
|
||||||
|
* @param sql
|
||||||
|
* @param obj
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void processSelect(Select select, int index, String sql, Object obj) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除进程拦截器
|
||||||
|
*
|
||||||
|
* @param delete
|
||||||
|
* @param index
|
||||||
|
* @param sql
|
||||||
|
* @param obj
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void processDelete(Delete delete, int index, String sql, Object obj) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询属性进程拦截器
|
||||||
|
*
|
||||||
|
* @param selectBody
|
||||||
|
*/
|
||||||
|
protected void processSelectBody(SelectBody selectBody) {
|
||||||
|
if (selectBody == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (selectBody instanceof PlainSelect) {
|
||||||
|
processPlainSelect((PlainSelect) selectBody);
|
||||||
|
} else if (selectBody instanceof WithItem) {
|
||||||
|
WithItem withItem = (WithItem) selectBody;
|
||||||
|
processSelectBody(withItem.getSubSelect().getSelectBody());
|
||||||
|
} else {
|
||||||
|
SetOperationList operationList = (SetOperationList) selectBody;
|
||||||
|
List<SelectBody> selectBodys = operationList.getSelects();
|
||||||
|
if (CollectionUtils.isNotEmpty(selectBodys)) {
|
||||||
|
selectBodys.forEach(this::processSelectBody);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增进程拦截器
|
||||||
|
*
|
||||||
|
* @param insert
|
||||||
|
* @param index
|
||||||
|
* @param sql
|
||||||
|
* @param obj
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void processInsert(Insert insert, int index, String sql, Object obj) {
|
||||||
|
if (fieldFillHandler.createIgnore(insert.getTable().getName())) {
|
||||||
|
// 过滤退出执行
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//获取所有字段
|
||||||
|
List<Column> columns = insert.getColumns();
|
||||||
|
if (CollectionUtils.isEmpty(columns)) {
|
||||||
|
// 针对没有任何列的insert 不处理
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//获取操作人字段
|
||||||
|
String FieldFillColumn = fieldFillHandler.getFieldFillColumn();
|
||||||
|
if (columns.stream().map(Column::getColumnName).anyMatch(i -> i.equals(FieldFillColumn))) {
|
||||||
|
// 针对已给出操作人列的insert 不处理 防止重复字段
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
columns.add(new Column(fieldFillHandler.getFieldFillColumn()));
|
||||||
|
|
||||||
|
//获取重复表达式 列表
|
||||||
|
List<Expression> duplicateUpdateColumns = insert.getDuplicateUpdateExpressionList();
|
||||||
|
if (CollectionUtils.isNotEmpty(duplicateUpdateColumns)) {
|
||||||
|
EqualsTo equalsTo = new EqualsTo();
|
||||||
|
equalsTo.setLeftExpression(new StringValue(fieldFillHandler.getFieldFillColumn()));
|
||||||
|
equalsTo.setRightExpression(fieldFillHandler.getFieldFillValue());
|
||||||
|
duplicateUpdateColumns.add(equalsTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
Select select = insert.getSelect();
|
||||||
|
if (select != null) {
|
||||||
|
this.processInsertSelect(select.getSelectBody());
|
||||||
|
} else if (insert.getItemsList() != null) {
|
||||||
|
ItemsList itemsList = insert.getItemsList();
|
||||||
|
if (itemsList instanceof MultiExpressionList) {
|
||||||
|
// 支持批量操作
|
||||||
|
((MultiExpressionList) itemsList).getExprList()
|
||||||
|
.forEach(el -> el.getExpressions().add(fieldFillHandler.getFieldFillValue()));
|
||||||
|
} else {
|
||||||
|
((ExpressionList) itemsList).getExpressions().add(fieldFillHandler.getFieldFillValue());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw ExceptionUtils.mpe("Failed to process multiple-table update, please exclude the tableName or statementId");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update 语句处理
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void processUpdate(Update update, int index, String sql, Object obj) {
|
||||||
|
final Table table = update.getTable();
|
||||||
|
if (fieldFillHandler.updateIgnore(table.getName())) {
|
||||||
|
// 过滤退出执行
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<Column> columns = update.getColumns();
|
||||||
|
if (CollectionUtils.isEmpty(columns)) {
|
||||||
|
// 针对没有任何列的 update 不处理
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String FieldFillColumn = fieldFillHandler.getFieldFillColumn();
|
||||||
|
|
||||||
|
if (columns.stream().map(Column::getColumnName).anyMatch(i -> i.equals(FieldFillColumn))) {
|
||||||
|
// 针对已给出操作人列的 update 不处理 防止重复字段
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//这里出问题了,已修复,使用addUpdateSet()实现动态添加更新人和更新时间
|
||||||
|
//columns.add(new Column(fieldFillHandler.getFieldFillColumn()));
|
||||||
|
//update.getExpressions().add(fieldFillHandler.getFieldFillValue());
|
||||||
|
update.addUpdateSet(new Column(fieldFillHandler.getFieldFillColumn()), fieldFillHandler.getFieldFillValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理 insert into select
|
||||||
|
* <p>
|
||||||
|
* 进入这里表示需要 insert 的表启用了操作人插件,则 select 的表都启动了
|
||||||
|
*
|
||||||
|
* @param selectBody SelectBody
|
||||||
|
*/
|
||||||
|
protected void processInsertSelect(SelectBody selectBody) {
|
||||||
|
PlainSelect plainSelect = (PlainSelect) selectBody;
|
||||||
|
FromItem fromItem = plainSelect.getFromItem();
|
||||||
|
if (fromItem instanceof Table) {
|
||||||
|
processPlainSelect(plainSelect);
|
||||||
|
appendSelectItem(plainSelect.getSelectItems());
|
||||||
|
} else if (fromItem instanceof SubSelect) {
|
||||||
|
SubSelect subSelect = (SubSelect) fromItem;
|
||||||
|
appendSelectItem(plainSelect.getSelectItems());
|
||||||
|
processInsertSelect(subSelect.getSelectBody());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 追加 SelectItem
|
||||||
|
*
|
||||||
|
* @param selectItems SelectItem
|
||||||
|
*/
|
||||||
|
protected void appendSelectItem(List<SelectItem> selectItems) {
|
||||||
|
if (CollectionUtils.isEmpty(selectItems)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (selectItems.size() == 1) {
|
||||||
|
SelectItem item = selectItems.get(0);
|
||||||
|
if (item instanceof AllColumns || item instanceof AllTableColumns) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selectItems.add(new SelectExpressionItem(new Column(fieldFillHandler.getFieldFillColumn())));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理 PlainSelect
|
||||||
|
*/
|
||||||
|
protected void processPlainSelect(PlainSelect plainSelect) {
|
||||||
|
FromItem fromItem = plainSelect.getFromItem();
|
||||||
|
Expression where = plainSelect.getWhere();
|
||||||
|
processWhereSubSelect(where);
|
||||||
|
if (fromItem instanceof Table) {
|
||||||
|
Table fromTable = (Table) fromItem;
|
||||||
|
if (!fieldFillHandler.createIgnore(fromTable.getName())) {
|
||||||
|
plainSelect.setWhere(builderExpression(where, fromTable));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
processFromItem(fromItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SelectItem> selectItems = plainSelect.getSelectItems();
|
||||||
|
if (CollectionUtils.isNotEmpty(selectItems)) {
|
||||||
|
selectItems.forEach(this::processSelectItem);
|
||||||
|
}
|
||||||
|
List<Join> joins = plainSelect.getJoins();
|
||||||
|
if (CollectionUtils.isNotEmpty(joins)) {
|
||||||
|
joins.forEach(j -> {
|
||||||
|
processJoin(j);
|
||||||
|
processFromItem(j.getRightItem());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理where条件内的子查询
|
||||||
|
* <p>
|
||||||
|
* 支持如下:
|
||||||
|
* 1. in
|
||||||
|
* 2. =
|
||||||
|
* 3. >
|
||||||
|
* 4. <
|
||||||
|
* 5. >=
|
||||||
|
* 6. <=
|
||||||
|
* 7. <>
|
||||||
|
* 8. EXISTS
|
||||||
|
* 9. NOT EXISTS
|
||||||
|
* <p>
|
||||||
|
* 前提条件:
|
||||||
|
* 1. 子查询必须放在小括号中
|
||||||
|
* 2. 子查询一般放在比较操作符的右边
|
||||||
|
*
|
||||||
|
* @param where where 条件
|
||||||
|
*/
|
||||||
|
protected void processWhereSubSelect(Expression where) {
|
||||||
|
if (where == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (where instanceof FromItem) {
|
||||||
|
processFromItem((FromItem) where);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (where.toString().indexOf("SELECT") > 0) {
|
||||||
|
// 有子查询
|
||||||
|
if (where instanceof BinaryExpression) {
|
||||||
|
// 比较符号 , and , or , 等等
|
||||||
|
BinaryExpression expression = (BinaryExpression) where;
|
||||||
|
processWhereSubSelect(expression.getLeftExpression());
|
||||||
|
processWhereSubSelect(expression.getRightExpression());
|
||||||
|
} else if (where instanceof InExpression) {
|
||||||
|
// in
|
||||||
|
InExpression expression = (InExpression) where;
|
||||||
|
ItemsList itemsList = expression.getRightItemsList();
|
||||||
|
if (itemsList instanceof SubSelect) {
|
||||||
|
processSelectBody(((SubSelect) itemsList).getSelectBody());
|
||||||
|
}
|
||||||
|
} else if (where instanceof ExistsExpression) {
|
||||||
|
// exists
|
||||||
|
ExistsExpression expression = (ExistsExpression) where;
|
||||||
|
processWhereSubSelect(expression.getRightExpression());
|
||||||
|
} else if (where instanceof NotExpression) {
|
||||||
|
// not exists
|
||||||
|
NotExpression expression = (NotExpression) where;
|
||||||
|
processWhereSubSelect(expression.getExpression());
|
||||||
|
} else if (where instanceof Parenthesis) {
|
||||||
|
Parenthesis expression = (Parenthesis) where;
|
||||||
|
processWhereSubSelect(expression.getExpression());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void processSelectItem(SelectItem selectItem) {
|
||||||
|
if (selectItem instanceof SelectExpressionItem) {
|
||||||
|
SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem;
|
||||||
|
if (selectExpressionItem.getExpression() instanceof SubSelect) {
|
||||||
|
processSelectBody(((SubSelect) selectExpressionItem.getExpression()).getSelectBody());
|
||||||
|
} else if (selectExpressionItem.getExpression() instanceof Function) {
|
||||||
|
processFunction((Function) selectExpressionItem.getExpression());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理函数
|
||||||
|
* <p>支持: 1. select fun(args..) 2. select fun1(fun2(args..),args..)<p>
|
||||||
|
*
|
||||||
|
* @param function
|
||||||
|
*/
|
||||||
|
protected void processFunction(Function function) {
|
||||||
|
ExpressionList parameters = function.getParameters();
|
||||||
|
if (parameters != null) {
|
||||||
|
parameters.getExpressions().forEach(expression -> {
|
||||||
|
if (expression instanceof SubSelect) {
|
||||||
|
processSelectBody(((SubSelect) expression).getSelectBody());
|
||||||
|
} else if (expression instanceof Function) {
|
||||||
|
processFunction((Function) expression);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理子查询等
|
||||||
|
*/
|
||||||
|
protected void processFromItem(FromItem fromItem) {
|
||||||
|
if (fromItem instanceof SubJoin) {
|
||||||
|
SubJoin subJoin = (SubJoin) fromItem;
|
||||||
|
if (subJoin.getJoinList() != null) {
|
||||||
|
subJoin.getJoinList().forEach(this::processJoin);
|
||||||
|
}
|
||||||
|
if (subJoin.getLeft() != null) {
|
||||||
|
processFromItem(subJoin.getLeft());
|
||||||
|
}
|
||||||
|
} else if (fromItem instanceof SubSelect) {
|
||||||
|
SubSelect subSelect = (SubSelect) fromItem;
|
||||||
|
if (subSelect.getSelectBody() != null) {
|
||||||
|
processSelectBody(subSelect.getSelectBody());
|
||||||
|
}
|
||||||
|
} else if (fromItem instanceof ValuesList) {
|
||||||
|
logger.debug("Perform a subquery, if you do not give us feedback");
|
||||||
|
} else if (fromItem instanceof LateralSubSelect) {
|
||||||
|
LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem;
|
||||||
|
if (lateralSubSelect.getSubSelect() != null) {
|
||||||
|
SubSelect subSelect = lateralSubSelect.getSubSelect();
|
||||||
|
if (subSelect.getSelectBody() != null) {
|
||||||
|
processSelectBody(subSelect.getSelectBody());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理联接语句
|
||||||
|
*/
|
||||||
|
protected void processJoin(Join join) {
|
||||||
|
if (join.getRightItem() instanceof Table) {
|
||||||
|
Table fromTable = (Table) join.getRightItem();
|
||||||
|
if (fieldFillHandler.createIgnore(fromTable.getName())) {
|
||||||
|
// 过滤退出执行
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
join.setOnExpression(builderExpression(join.getOnExpression(), fromTable));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理条件
|
||||||
|
*/
|
||||||
|
protected Expression builderExpression(Expression currentExpression, Table table) {
|
||||||
|
EqualsTo equalsTo = new EqualsTo();
|
||||||
|
equalsTo.setLeftExpression(this.getAliasColumn(table));
|
||||||
|
equalsTo.setRightExpression(fieldFillHandler.getFieldFillValue());
|
||||||
|
if (currentExpression == null) {
|
||||||
|
return equalsTo;
|
||||||
|
}
|
||||||
|
if (currentExpression instanceof OrExpression) {
|
||||||
|
return new AndExpression(new Parenthesis(currentExpression), equalsTo);
|
||||||
|
} else {
|
||||||
|
return new AndExpression(currentExpression, equalsTo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段别名设置
|
||||||
|
*
|
||||||
|
* @param table 表对象
|
||||||
|
* @return 字段
|
||||||
|
*/
|
||||||
|
protected Column getAliasColumn(Table table) {
|
||||||
|
StringBuilder column = new StringBuilder();
|
||||||
|
if (table.getAlias() != null) {
|
||||||
|
column.append(table.getAlias().getName()).append(StringPool.DOT);
|
||||||
|
}
|
||||||
|
column.append(fieldFillHandler.getFieldFillColumn());
|
||||||
|
return new Column(column.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProperties(Properties properties) {
|
||||||
|
PropertyMapper.newInstance(properties).whenNotBlank("fieldFillHandler", ClassUtils::newInstance, this::setFieldFillHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
ai.remi.comm.jdbc.config.AutoConfig,\
|
||||||
|
ai.remi.comm.jdbc.config.DruidConfig,\
|
||||||
|
ai.remi.comm.jdbc.config.FieldFillConfig,\
|
||||||
|
ai.remi.comm.jdbc.config.InterceptConfig,\
|
||||||
|
ai.remi.comm.jdbc.config.MybatisPlusConfig,\
|
||||||
|
ai.remi.comm.jdbc.config.TenantConfig
|
||||||
|
|
||||||
|
|
||||||
51
remi-comm/remi-comm-job/pom.xml
Normal file
51
remi-comm/remi-comm-job/pom.xml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>remi-comm-job</artifactId>
|
||||||
|
<name>remi-comm-job</name>
|
||||||
|
<description>remi-comm-job</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm</artifactId>
|
||||||
|
<version>3.1.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<!-- 打包上传到私服, 需要和配置文件中的server节点配合使用 -->
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>maven-releases</id>
|
||||||
|
<name>release</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-releases/</url>
|
||||||
|
</repository>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>maven-snapshots</id>
|
||||||
|
<name>snapshot</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-snapshots/</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!--remi-comm-core-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- xxl-job 核心包-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.xuxueli</groupId>
|
||||||
|
<artifactId>xxl-job-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--slf4j-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package ai.remi.comm.job.config;
|
||||||
|
|
||||||
|
import ai.remi.comm.job.properties.XxlJobProperties;
|
||||||
|
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时任务配置
|
||||||
|
*
|
||||||
|
* @author dianjiu
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties(value = XxlJobProperties.class)
|
||||||
|
@ConditionalOnProperty(value = "xxl-job.enabled", havingValue = "true")
|
||||||
|
public class XxlJobConfiguration {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private XxlJobProperties xxlJobProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 针对多网卡、容器内部署等情况,可借助 "spring-cloud-commons" 提供的 "InetUtils" 组件灵活定制注册IP;
|
||||||
|
* <p>
|
||||||
|
* 1、引入依赖:
|
||||||
|
* <dependency>
|
||||||
|
* <groupId>org.springframework.cloud</groupId>
|
||||||
|
* <artifactId>spring-cloud-commons</artifactId>
|
||||||
|
* <version>${version}</version>
|
||||||
|
* </dependency>
|
||||||
|
* <p>
|
||||||
|
* 2、配置文件,或者容器启动变量
|
||||||
|
* spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.'
|
||||||
|
* <p>
|
||||||
|
* 3、获取IP
|
||||||
|
* String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public XxlJobSpringExecutor xxlJobExecutor() {
|
||||||
|
log.info(">>>>>>>>>>> xxl-job config init start.");
|
||||||
|
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
|
||||||
|
xxlJobSpringExecutor.setAdminAddresses(xxlJobProperties.getAdminAddresses());
|
||||||
|
xxlJobSpringExecutor.setAppname(xxlJobProperties.getExecutor().getAppname());
|
||||||
|
xxlJobSpringExecutor.setAddress(xxlJobProperties.getExecutor().getAddress());
|
||||||
|
xxlJobSpringExecutor.setIp(xxlJobProperties.getExecutor().getIp());
|
||||||
|
xxlJobSpringExecutor.setPort(xxlJobProperties.getExecutor().getPort());
|
||||||
|
xxlJobSpringExecutor.setAccessToken(xxlJobProperties.getAccessToken());
|
||||||
|
xxlJobSpringExecutor.setLogPath(xxlJobProperties.getExecutor().getLogPath());
|
||||||
|
xxlJobSpringExecutor.setLogRetentionDays(xxlJobProperties.getExecutor().getLogRetentionDays());
|
||||||
|
log.info(">>>>>>>>>>> xxl-job config init end.");
|
||||||
|
return xxlJobSpringExecutor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package ai.remi.comm.job.properties;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xxl-job的配置属性
|
||||||
|
*
|
||||||
|
* @author dianjiu
|
||||||
|
* 2021-12-28 09:40:38
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ConfigurationProperties(prefix = "xxl-job")
|
||||||
|
public class XxlJobProperties {
|
||||||
|
/**
|
||||||
|
* 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
|
||||||
|
* eg:http://127.0.0.1:8080/xxl-job-admin
|
||||||
|
*/
|
||||||
|
private String adminAddresses;
|
||||||
|
/**
|
||||||
|
* 执行器通讯TOKEN [选填]:非空时启用;
|
||||||
|
*/
|
||||||
|
private String accessToken;
|
||||||
|
|
||||||
|
private Boolean enabled;
|
||||||
|
|
||||||
|
private Executor executor;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public static class Executor {
|
||||||
|
/**
|
||||||
|
* 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
|
||||||
|
* eg:remi-boot-job
|
||||||
|
*/
|
||||||
|
private String appname;
|
||||||
|
/**
|
||||||
|
* 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
|
||||||
|
*/
|
||||||
|
private String address;
|
||||||
|
/**
|
||||||
|
* 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
|
||||||
|
*/
|
||||||
|
private String ip;
|
||||||
|
/**
|
||||||
|
* 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
|
||||||
|
*/
|
||||||
|
private int port;
|
||||||
|
/**
|
||||||
|
* 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
|
||||||
|
*/
|
||||||
|
private String logPath;
|
||||||
|
/**
|
||||||
|
* 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
|
||||||
|
*/
|
||||||
|
private int logRetentionDays;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
ai.remi.comm.job.config.XxlJobConfiguration
|
||||||
69
remi-comm/remi-comm-log/README.md
Normal file
69
remi-comm/remi-comm-log/README.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# 工程简介
|
||||||
|
瑞米平台公共的日志模块
|
||||||
|
|
||||||
|
## 操作日志
|
||||||
|
主要面向用户的,要求简单易懂,反映出用户所做的动作。
|
||||||
|
|
||||||
|
### 核心功能
|
||||||
|
- 要实现以下功能:
|
||||||
|
|
||||||
|
- 自定义spring boot starter
|
||||||
|
- 定义日志注解
|
||||||
|
- AOP拦截日志注解方法
|
||||||
|
- 定义日志动态内容模板
|
||||||
|
|
||||||
|
- 模板中又需要实现:
|
||||||
|
- 动态模板表达式解析:用强大的SpEL来解析表达式
|
||||||
|
- 自定义函数:支持目标方法前置/后置的自定义函数
|
||||||
|
|
||||||
|
##
|
||||||
|
|
||||||
|
### SQL脚本
|
||||||
|
```sql
|
||||||
|
DROP TABLE IF EXISTS t_system_log;
|
||||||
|
CREATE TABLE t_system_log
|
||||||
|
(
|
||||||
|
id VARCHAR(32) NOT NULL COMMENT '日志编号',
|
||||||
|
user_id VARCHAR(32) COMMENT '用户ID',
|
||||||
|
user_name VARCHAR(255) COMMENT '用户名称',
|
||||||
|
app_code VARCHAR(255) COMMENT '应用编码',
|
||||||
|
app_name VARCHAR(255) COMMENT '应用名称',
|
||||||
|
business_no VARCHAR(255) COMMENT '业务流水号',
|
||||||
|
business_type VARCHAR(255) COMMENT '业务类型(新增、修改、删除、查询、导入、导出、其他)',
|
||||||
|
log_content LONGTEXT COMMENT '日志模板内容',
|
||||||
|
log_extras LONGTEXT COMMENT '额外的日志内容',
|
||||||
|
request_url VARCHAR(255) COMMENT '请求地址',
|
||||||
|
request_ip VARCHAR(255) COMMENT '请求IP',
|
||||||
|
request_type VARCHAR(255) COMMENT '请求类型(POST、PUT、OPTIONS、DELETE)',
|
||||||
|
content_type VARCHAR(255) COMMENT '请求报文类型(map、json)',
|
||||||
|
request_body LONGTEXT COMMENT '请求报文',
|
||||||
|
response_body LONGTEXT COMMENT '响应报文',
|
||||||
|
request_time DATETIME COMMENT '请求时间',
|
||||||
|
response_time DATETIME COMMENT '响应时间',
|
||||||
|
execute_time BIGINT COMMENT '请求耗时',
|
||||||
|
trace_id VARCHAR(255) COMMENT '链路追踪ID',
|
||||||
|
error_info LONGTEXT COMMENT '异常信息',
|
||||||
|
user_agent VARCHAR(255) COMMENT '浏览器、操作系统、UI引擎标识',
|
||||||
|
revision INTEGER(11) COMMENT '乐观锁',
|
||||||
|
is_deleted INTEGER(1) COMMENT '逻辑删除;0-未删除 1-已删除',
|
||||||
|
group_tenant_id VARCHAR(32) COMMENT '部门租户ID',
|
||||||
|
company_tenant_id VARCHAR(32) COMMENT '公司租户ID',
|
||||||
|
created_by VARCHAR(32) COMMENT '创建人',
|
||||||
|
created_at DATETIME COMMENT '创建时间',
|
||||||
|
updated_by VARCHAR(32) COMMENT '更新人',
|
||||||
|
updated_at DATETIME COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
) COMMENT = '系统日志表';
|
||||||
|
```
|
||||||
|
## 系统日志
|
||||||
|
主要用于开发者调试排查系统问题的,不要求固定格式和可读性。
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
## 延伸阅读
|
||||||
|
https://tech.meituan.com/2021/09/16/operational-logbook.html
|
||||||
|
|
||||||
|
https://juejin.cn/post/7075184311397253128
|
||||||
|
|
||||||
|
http://mysql.taobao.org/monthly/2017/09/08/
|
||||||
|
|
||||||
69
remi-comm/remi-comm-log/pom.xml
Normal file
69
remi-comm/remi-comm-log/pom.xml
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>remi-comm-log</artifactId>
|
||||||
|
<name>remi-comm-log</name>
|
||||||
|
<description>remi-comm-log</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm</artifactId>
|
||||||
|
<version>3.1.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<!-- 打包上传到私服, 需要和配置文件中的server节点配合使用 -->
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>maven-releases</id>
|
||||||
|
<name>release</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-releases/</url>
|
||||||
|
</repository>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>maven-snapshots</id>
|
||||||
|
<name>snapshot</name>
|
||||||
|
<url>https://repository.njydsz.com/repository/maven-snapshots/</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!--spring-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-aop</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--nacos-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--公共依赖-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm-util</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-comm-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--项目依赖-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ai.remi.top.cloud</groupId>
|
||||||
|
<artifactId>remi-sys-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--lombok-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package ai.remi.comm.log.annotation;
|
||||||
|
|
||||||
|
import ai.remi.comm.log.config.LogRecordAutoConfigure;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author DianJiu 【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @date 2022-07-19
|
||||||
|
* @desc 日志记录开启注解
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Inherited
|
||||||
|
@Order(Integer.MIN_VALUE)
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Import(LogRecordAutoConfigure.class)
|
||||||
|
public @interface EnableLogRecord {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package ai.remi.comm.log.annotation;
|
||||||
|
|
||||||
|
|
||||||
|
import ai.remi.comm.log.enums.BusinessType;
|
||||||
|
import ai.remi.comm.log.enums.OperatorType;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author DianJiu 【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @date 2022-07-19
|
||||||
|
* @desc 操作日志记录
|
||||||
|
*/
|
||||||
|
@Inherited
|
||||||
|
@Documented
|
||||||
|
@Order(Integer.MIN_VALUE)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface LogRecord {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接口名称
|
||||||
|
*/
|
||||||
|
String content() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能操作类型
|
||||||
|
*/
|
||||||
|
BusinessType businessType() default BusinessType.OTHER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作人类别
|
||||||
|
*/
|
||||||
|
OperatorType operatorType() default OperatorType.MANAGE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否保存请求的参数
|
||||||
|
*/
|
||||||
|
boolean isSaveRequestData() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否保存响应的参数
|
||||||
|
*/
|
||||||
|
boolean isSaveResponseData() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否保存异常的信息
|
||||||
|
*/
|
||||||
|
boolean isSaveErrorInfo() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在方法成功执行后打点,记录方法的执行时间发送到指标系统,默认关闭
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean recordSuccessMetrics() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在方法成功失败后打点,记录方法的执行时间发送到指标系统,默认关闭
|
||||||
|
*/
|
||||||
|
boolean recordFailMetrics() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 出现异常后忽略异常返回默认值,默认关闭
|
||||||
|
*/
|
||||||
|
boolean ignoreException() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排除指定的请求参数
|
||||||
|
*/
|
||||||
|
public String[] excludeParamNames() default {};
|
||||||
|
}
|
||||||
@@ -0,0 +1,399 @@
|
|||||||
|
package ai.remi.comm.log.aspect;
|
||||||
|
|
||||||
|
import ai.remi.comm.core.spring.SpringProperties;
|
||||||
|
import ai.remi.comm.log.annotation.LogRecord;
|
||||||
|
import ai.remi.comm.log.domain.OperateLog;
|
||||||
|
import ai.remi.comm.log.enums.BusinessStatus;
|
||||||
|
import ai.remi.comm.log.filter.PropertyPreExcludeFilter;
|
||||||
|
import ai.remi.comm.log.service.AsyncLogService;
|
||||||
|
import ai.remi.comm.redis.service.RedisService;
|
||||||
|
import ai.remi.comm.util.ip.IpAddrUtils;
|
||||||
|
import ai.remi.comm.util.ip.IpInfoUtils;
|
||||||
|
import ai.remi.comm.util.string.StringUtils;
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import ai.remi.comm.log.enums.RedisKeyEnum;
|
||||||
|
import eu.bitwalker.useragentutils.UserAgent;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections.MapUtils;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
import org.aspectj.lang.annotation.AfterThrowing;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Before;
|
||||||
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
import org.springframework.core.NamedThreadLocal;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
|
import org.springframework.web.context.request.RequestAttributes;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作日志记录处理
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Aspect
|
||||||
|
public class LogRecordAspect {
|
||||||
|
/**
|
||||||
|
* 排除敏感属性字段
|
||||||
|
*/
|
||||||
|
public static final String[] EXCLUDE_PROPERTIES = {"password", "oldPassword", "newPassword", "confirmPassword"};
|
||||||
|
|
||||||
|
private final ThreadLocal<Map<String, Object>> INFO_THREADLOCAL = new ThreadLocal<Map<String, Object>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算操作消耗时间
|
||||||
|
*/
|
||||||
|
private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<>("Cost Time");
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AsyncLogService asyncLogService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisService redisService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理请求前执行
|
||||||
|
*/
|
||||||
|
@Before(value = "@annotation(logRecord)")
|
||||||
|
public void boBefore(JoinPoint joinPoint, LogRecord logRecord) {
|
||||||
|
TIME_THREADLOCAL.set(System.currentTimeMillis());
|
||||||
|
//登出接口需要前置储存用户信息
|
||||||
|
handleLog(joinPoint, logRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理完请求后执行
|
||||||
|
*
|
||||||
|
* @param joinPoint 切点
|
||||||
|
*/
|
||||||
|
@AfterReturning(pointcut = "@annotation(logRecord)", returning = "jsonResult")
|
||||||
|
public void doAfterReturning(JoinPoint joinPoint, LogRecord logRecord, Object jsonResult) {
|
||||||
|
handleLog(joinPoint, logRecord, null, jsonResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拦截异常操作
|
||||||
|
*
|
||||||
|
* @param joinPoint 切点
|
||||||
|
* @param e 异常
|
||||||
|
*/
|
||||||
|
@AfterThrowing(value = "@annotation(logRecord)", throwing = "e")
|
||||||
|
public void doAfterThrowing(JoinPoint joinPoint, LogRecord logRecord, Exception e) {
|
||||||
|
handleLog(joinPoint, logRecord, e, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void handleLog(final JoinPoint joinPoint, LogRecord logRecord) {
|
||||||
|
// 传递线程信息
|
||||||
|
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
|
RequestContextHolder.setRequestAttributes(requestAttributes, true);
|
||||||
|
HttpServletRequest request = requestAttributes.getRequest();
|
||||||
|
// 记录请求内容,threadInfo存储所有内容
|
||||||
|
Map<String, Object> threadInfo = new HashMap<>();
|
||||||
|
//该方法用于获取客户端发出请求时的完整URL,包括协议、服务器名、端口号、资源路径等信息,但不包括后面的查询参数部分。
|
||||||
|
// 注意,getRequestRUL()方法返回的时StringBuffer类型,而不是String类型。
|
||||||
|
threadInfo.put("url", request.getRequestURL());
|
||||||
|
//该方法用于获取请求行中资源名称部分,即位于URL的主机和端口之后、参数部分之前的部分
|
||||||
|
threadInfo.put("uri", request.getRequestURI());
|
||||||
|
//该方法用于获取HTTP请求消息中的请求方式(如GET、POST等)
|
||||||
|
threadInfo.put("httpMethod", request.getMethod());
|
||||||
|
//该方法用于获取请求的协议名,例如http、https或ftp
|
||||||
|
threadInfo.put("scheme", request.getScheme());
|
||||||
|
//该方法用于获取请求客户端的IP地址,其格式类似于"192.168.0.1"
|
||||||
|
//threadInfo.put("ip", request.getRemoteAddr());
|
||||||
|
threadInfo.put("ip", IpAddrUtils.getIpAddr(request));
|
||||||
|
//检查是否为内网IP
|
||||||
|
String ipAddress = IpAddrUtils.internalIp(IpAddrUtils.getIpAddr(request)) ? "内网IP" : IpInfoUtils.getInfo(IpAddrUtils.getIpAddr(request)).getProvince() + "-" + IpInfoUtils.getInfo(IpAddrUtils.getIpAddr(request)).getCity();
|
||||||
|
threadInfo.put("ipAddress", ipAddress);
|
||||||
|
//该方法用于获取Content-Type头字段的值,结果为String类型
|
||||||
|
threadInfo.put("contentType", request.getContentType());
|
||||||
|
//包含了一个特征字符串,用来让网络协议的对端来识别发起请求的用户代理软件的应用类型、操作系统、软件开发商以及版本号。
|
||||||
|
//UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
|
||||||
|
UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
|
||||||
|
threadInfo.put("platform", userAgent.getOperatingSystem().getName());
|
||||||
|
threadInfo.put("browser", userAgent.getBrowser().getName());
|
||||||
|
//从请求头获取操作人
|
||||||
|
threadInfo.put("operator", request.getHeader("X-Unique-Id"));
|
||||||
|
//从请求头获取部门租户
|
||||||
|
threadInfo.put("deptTenantId", request.getHeader("X-Dept-Tenant-Id"));
|
||||||
|
//从请求头获取公司租户
|
||||||
|
threadInfo.put("companyTenantId", request.getHeader("X-Company-Tenant-Id"));
|
||||||
|
//从请求头获取操作人
|
||||||
|
String accessToken = request.getHeader("X-Access-Token");
|
||||||
|
threadInfo.put("token", accessToken);
|
||||||
|
threadInfo.put("userId", redisService.hget(RedisKeyEnum.USER_INFO.getKey(accessToken), "id"));
|
||||||
|
threadInfo.put("userCode", redisService.hget(RedisKeyEnum.USER_INFO.getKey(accessToken), "userCode"));
|
||||||
|
threadInfo.put("userName", redisService.hget(RedisKeyEnum.USER_INFO.getKey(accessToken), "userName"));
|
||||||
|
threadInfo.put("userNameEn", redisService.hget(RedisKeyEnum.USER_INFO.getKey(accessToken), "userNameEn"));
|
||||||
|
//从请求头获取系统语言
|
||||||
|
threadInfo.put("language", request.getHeader("X-USER-LANGUAGE"));
|
||||||
|
//从请求头获取业务流水号
|
||||||
|
threadInfo.put("businessNo", request.getHeader("X-Business-No"));
|
||||||
|
INFO_THREADLOCAL.set(threadInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void handleLog(final JoinPoint joinPoint, LogRecord logRecord, final Exception e, Object jsonResult) {
|
||||||
|
try {
|
||||||
|
// *========解析请求信息=========*//
|
||||||
|
OperateLog operateLog = new OperateLog();
|
||||||
|
|
||||||
|
// *========获取注解信息=========*//
|
||||||
|
//获取方法签名
|
||||||
|
//MethodSignature signature = getSignature(joinPoint);
|
||||||
|
//获取注解方法
|
||||||
|
Method method = getMethod(joinPoint);
|
||||||
|
//获取注解对象
|
||||||
|
//LogRecord logRecord = getAnnotation(joinPoint, LogRecord.class);
|
||||||
|
// 获取连接点所在类名
|
||||||
|
String classname = joinPoint.getTarget().getClass().getSimpleName();
|
||||||
|
// 获取连接点所在方法名称
|
||||||
|
String methodName = method.getName();
|
||||||
|
String name = String.format("%s.%s()", classname, methodName);
|
||||||
|
// 保存请求方法
|
||||||
|
operateLog.setRequestMethod(name);
|
||||||
|
|
||||||
|
// 处理设置注解上的参数
|
||||||
|
getControllerMethodDescription(joinPoint, logRecord, operateLog, jsonResult);
|
||||||
|
|
||||||
|
// 是否需要保存request,参数和值
|
||||||
|
if (logRecord.isSaveRequestData()) {
|
||||||
|
// 获取参数的信息,传入到数据库中
|
||||||
|
setRequestValue(joinPoint, operateLog, logRecord.excludeParamNames());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否需要保存response,参数和值
|
||||||
|
if (logRecord.isSaveResponseData() && ObjectUtil.isNotNull(jsonResult)) {
|
||||||
|
String result = JSON.toJSONString(jsonResult);
|
||||||
|
// 对登录日志的特殊处理
|
||||||
|
if (operateLog.getBusinessType()== 9) {
|
||||||
|
Object data = JSON.parseObject(result).get("data");
|
||||||
|
String accessToken = String.valueOf(JSON.parseObject(JSON.toJSONString(data)).get("accessToken"));
|
||||||
|
setOperateUser(accessToken, operateLog);
|
||||||
|
}
|
||||||
|
operateLog.setStatus(String.valueOf(JSON.parseObject(result).get("code")));
|
||||||
|
operateLog.setResponseBody(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
//请求的成功或失败
|
||||||
|
if (e != null) {
|
||||||
|
operateLog.setStatus(BusinessStatus.FAIL.getCode());
|
||||||
|
// 是否需要保存errorMsg,参数和值
|
||||||
|
if (logRecord.isSaveErrorInfo()) {
|
||||||
|
operateLog.setStatus("111111");
|
||||||
|
operateLog.setErrorInfo(StrUtil.sub(e.getMessage(), 0, 5000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存数据库
|
||||||
|
//asyncLogService.saveOperateLog(operateLog);
|
||||||
|
} catch (Exception exp) {
|
||||||
|
// 记录本地异常日志
|
||||||
|
log.error("异常信息:{}", exp.getMessage());
|
||||||
|
exp.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
TIME_THREADLOCAL.remove();
|
||||||
|
INFO_THREADLOCAL.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取注解中对方法的描述信息 用于Controller层注解
|
||||||
|
*
|
||||||
|
* @param logRecord 日志切面
|
||||||
|
* @param operateLog 操作日志
|
||||||
|
*/
|
||||||
|
public void getControllerMethodDescription(JoinPoint joinPoint, LogRecord logRecord, OperateLog operateLog, Object jsonResult) throws Exception {
|
||||||
|
Map<String, Object> objectMap = INFO_THREADLOCAL.get();
|
||||||
|
// 业务模块
|
||||||
|
operateLog.setAppId(SpringProperties.getString("log.record.appId"));
|
||||||
|
operateLog.setAppCode(SpringProperties.getString("log.record.appCode"));
|
||||||
|
// 操作方法名称或描述
|
||||||
|
operateLog.setContent(logRecord.content());
|
||||||
|
// 业务操作类型
|
||||||
|
operateLog.setBusinessType(logRecord.businessType().getCode());
|
||||||
|
// 操作人类别
|
||||||
|
operateLog.setOperatorType(logRecord.operatorType().getCode());
|
||||||
|
// 操作人IP
|
||||||
|
operateLog.setUserIp(String.valueOf(objectMap.get("ip")));
|
||||||
|
operateLog.setIpAddress(String.valueOf(objectMap.get("ipAddress")));
|
||||||
|
// 操作人Id
|
||||||
|
//operateLog.setUserId(Objects.nonNull(objectMap.get("operator")) ? String.valueOf(objectMap.get("operator")) : null);
|
||||||
|
// 操作人信息
|
||||||
|
operateLog.setUserId(Objects.nonNull(objectMap.get("userId")) ? String.valueOf(objectMap.get("userId")) : null);
|
||||||
|
operateLog.setUserCode(Objects.nonNull(objectMap.get("userCode")) ? String.valueOf(objectMap.get("userCode")) : null);
|
||||||
|
operateLog.setUserName(Objects.nonNull(objectMap.get("userName")) ? String.valueOf(objectMap.get("userName")) : null);
|
||||||
|
operateLog.setUserNameEn(Objects.nonNull(objectMap.get("userNameEn")) ? String.valueOf(objectMap.get("userNameEn")) : null);
|
||||||
|
// 用户系统语言
|
||||||
|
operateLog.setUserLanguage(Objects.nonNull(objectMap.get("language")) ? String.valueOf(objectMap.get("language")) : null);
|
||||||
|
// 请求地址
|
||||||
|
operateLog.setRequestUrl(String.valueOf(objectMap.get("url")));
|
||||||
|
// 请求类型
|
||||||
|
operateLog.setRequestType(String.valueOf(objectMap.get("httpMethod")));
|
||||||
|
// 请求报文类型
|
||||||
|
operateLog.setContentType(Objects.nonNull(objectMap.get("contentType")) ? String.valueOf(objectMap.get("contentType")) : null);
|
||||||
|
// 业务流水号
|
||||||
|
operateLog.setBusinessNo(Objects.nonNull(objectMap.get("businessNo")) ? String.valueOf(objectMap.get("businessNo")) : null);
|
||||||
|
// 链路追踪ID
|
||||||
|
//logRecordDTO.setTraceId();
|
||||||
|
// 浏览器、操作系统、UI引擎标识
|
||||||
|
operateLog.setPlatform(String.valueOf(objectMap.get("platform")));
|
||||||
|
operateLog.setBrowser(String.valueOf(objectMap.get("browser")));
|
||||||
|
// 部门租户
|
||||||
|
operateLog.setDeptTenantId(String.valueOf(objectMap.get("deptTenantId")));
|
||||||
|
// 公司租户
|
||||||
|
operateLog.setCompanyTenantId(String.valueOf(objectMap.get("companyTenantId")));
|
||||||
|
// 设置消耗时间
|
||||||
|
operateLog.setRequestTime(LocalDateTime.ofEpochSecond(TIME_THREADLOCAL.get() / 1000, 0, ZoneOffset.ofHours(8)));
|
||||||
|
operateLog.setResponseTime(LocalDateTime.ofEpochSecond(System.currentTimeMillis() / 1000, 0, ZoneOffset.ofHours(8)));
|
||||||
|
operateLog.setExecuteTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存操作人信息
|
||||||
|
*
|
||||||
|
* @param accessToken
|
||||||
|
* @param operateLog
|
||||||
|
*/
|
||||||
|
private void setOperateUser(String accessToken, OperateLog operateLog) {
|
||||||
|
if (StringUtils.isNotBlank(accessToken)) {
|
||||||
|
String id = String.valueOf(redisService.hget(RedisKeyEnum.USER_INFO.getKey(accessToken), "id"));
|
||||||
|
operateLog.setUserId(id);
|
||||||
|
String userCode = String.valueOf(redisService.hget(RedisKeyEnum.USER_INFO.getKey(accessToken), "userCode"));
|
||||||
|
operateLog.setUserCode(userCode);
|
||||||
|
String userName = String.valueOf(redisService.hget(RedisKeyEnum.USER_INFO.getKey(accessToken), "userName"));
|
||||||
|
operateLog.setUserName(userName);
|
||||||
|
String userNameEn = String.valueOf(redisService.hget(RedisKeyEnum.USER_INFO.getKey(accessToken), "userNameEn"));
|
||||||
|
operateLog.setUserNameEn(userNameEn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取请求的参数,放到log中
|
||||||
|
*
|
||||||
|
* @param operateLog 操作日志
|
||||||
|
* @param excludeParamNames 排除指定的请求参数
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
private void setRequestValue(JoinPoint joinPoint, OperateLog operateLog, String[] excludeParamNames) throws Exception {
|
||||||
|
// 获取RequestAttributes
|
||||||
|
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||||
|
// 从获取RequestAttributes中获取HttpServletRequest的信息
|
||||||
|
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
|
||||||
|
// 获取请求类型
|
||||||
|
// String requestType = operateLog.getRequestType();
|
||||||
|
String requestType = request.getMethod();
|
||||||
|
// 获取请求参数
|
||||||
|
Map<String, String> paramsMap = converMap(request.getParameterMap());
|
||||||
|
// 组装请求参数
|
||||||
|
if (MapUtils.isEmpty(paramsMap) && (HttpMethod.PUT.name().equals(requestType) || HttpMethod.POST.name().equals(requestType))) {
|
||||||
|
String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
|
||||||
|
operateLog.setRequestBody(params);
|
||||||
|
} else {
|
||||||
|
operateLog.setRequestBody(JSON.toJSONString(paramsMap, excludePropertyPreFilter(excludeParamNames)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求参数 转换
|
||||||
|
*
|
||||||
|
* @param paramMap request获取的参数数组
|
||||||
|
*/
|
||||||
|
public Map<String, String> converMap(Map<String, String[]> paramMap) {
|
||||||
|
Map<String, String> returnMap = new HashMap<>();
|
||||||
|
for (String key : paramMap.keySet()) {
|
||||||
|
returnMap.put(key, paramMap.get(key)[0]);
|
||||||
|
}
|
||||||
|
return returnMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数拼装
|
||||||
|
*/
|
||||||
|
private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) {
|
||||||
|
StringBuilder params = new StringBuilder();
|
||||||
|
if (ArrayUtil.isNotEmpty(paramsArray)) {
|
||||||
|
for (Object o : paramsArray) {
|
||||||
|
if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) {
|
||||||
|
try {
|
||||||
|
String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter(excludeParamNames));
|
||||||
|
params.append(jsonObj).append(StrUtil.SPACE);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return params.toString().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 忽略敏感属性
|
||||||
|
*/
|
||||||
|
public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames) {
|
||||||
|
return new PropertyPreExcludeFilter().addExcludes(ArrayUtil.addAll(EXCLUDE_PROPERTIES, excludeParamNames));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否需要过滤的对象
|
||||||
|
*
|
||||||
|
* @param o 对象信息。
|
||||||
|
* @return 如果是需要过滤的对象,则返回true;否则返回false。
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public boolean isFilterObject(final Object o) {
|
||||||
|
Class<?> clazz = o.getClass();
|
||||||
|
if (clazz.isArray()) {
|
||||||
|
return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
|
||||||
|
} else if (Collection.class.isAssignableFrom(clazz)) {
|
||||||
|
Collection collection = (Collection) o;
|
||||||
|
for (Object value : collection) {
|
||||||
|
return value instanceof MultipartFile;
|
||||||
|
}
|
||||||
|
} else if (Map.class.isAssignableFrom(clazz)) {
|
||||||
|
Map map = (Map) o;
|
||||||
|
for (Object value : map.entrySet()) {
|
||||||
|
Map.Entry entry = (Map.Entry) value;
|
||||||
|
return entry.getValue() instanceof MultipartFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
|
||||||
|
|| o instanceof BindingResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodSignature getSignature(JoinPoint joinPoint) {
|
||||||
|
//通过连接点获取方法签名
|
||||||
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Method getMethod(JoinPoint joinPoint) {
|
||||||
|
//通过连接点获取方法签名
|
||||||
|
MethodSignature signature = getSignature(joinPoint);
|
||||||
|
//获取注解服务的方法
|
||||||
|
Method method = signature.getMethod();
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Annotation> T getAnnotation(JoinPoint joinPoint, Class<T> annotationClass) {
|
||||||
|
Method method = getMethod(joinPoint);
|
||||||
|
//获取注解类
|
||||||
|
T annotation = method.getAnnotation(annotationClass);
|
||||||
|
return annotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package ai.remi.comm.log.config;
|
||||||
|
|
||||||
|
import ai.remi.comm.log.aspect.LogRecordAspect;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author DianJiu 【公众号 点九开源】
|
||||||
|
* @email dianjiuxyz@gmail.com
|
||||||
|
* @date 2022-07-19
|
||||||
|
* @desc
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RefreshScope
|
||||||
|
@Configuration
|
||||||
|
public class LogRecordAutoConfigure {
|
||||||
|
/**
|
||||||
|
* 是否开启监控配置参数
|
||||||
|
*/
|
||||||
|
@Value("${remi-log.record.enabled}")
|
||||||
|
private Boolean enabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志监控的应用名称
|
||||||
|
*/
|
||||||
|
@Value("${remi-log.record.appName}")
|
||||||
|
private String appName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在方法成功执行后打点,记录方法的执行时间发送到指标系统,默认关闭
|
||||||
|
* 在方法成功失败后打点,记录方法的执行时间发送到指标系统,默认关闭
|
||||||
|
*/
|
||||||
|
@Value("${remi-log.record.pushUrl}")
|
||||||
|
private String pushUrl;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据运行环境决定是否开启日志记录监控
|
||||||
|
*/
|
||||||
|
@PostConstruct
|
||||||
|
protected LogRecordAspect init() {
|
||||||
|
if(!enabled){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (enabled && StringUtils.isBlank(appName)) {
|
||||||
|
log.error("Please config the remi-log.record property in application.yml file to enabled log record, but appName is null.");
|
||||||
|
throw new RuntimeException("Please config the remi-log.record property in application.yml file to config log record appName.");
|
||||||
|
}
|
||||||
|
return new LogRecordAspect();
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user