commit
e73311d074
4
pom.xml
4
pom.xml
|
@ -32,8 +32,8 @@
|
||||||
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
|
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
|
||||||
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
|
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
|
||||||
<!-- 看看咋放到 bom 里 -->
|
<!-- 看看咋放到 bom 里 -->
|
||||||
<lombok.version>1.18.20</lombok.version>
|
<lombok.version>1.18.24</lombok.version>
|
||||||
<mapstruct.version>1.4.1.Final</mapstruct.version>
|
<mapstruct.version>1.5.3.Final</mapstruct.version>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|
|
@ -16,19 +16,19 @@
|
||||||
<properties>
|
<properties>
|
||||||
<revision>1.6.2-snapshot</revision>
|
<revision>1.6.2-snapshot</revision>
|
||||||
<!-- 统一依赖管理 -->
|
<!-- 统一依赖管理 -->
|
||||||
<spring.boot.version>2.6.9</spring.boot.version>
|
<spring.boot.version>2.6.13</spring.boot.version>
|
||||||
<spring.cloud.version>2021.0.1</spring.cloud.version>
|
<spring.cloud.version>2021.0.1</spring.cloud.version>
|
||||||
<spring.cloud.alibaba.version>2021.0.1.0</spring.cloud.alibaba.version>
|
<spring.cloud.alibaba.version>2021.0.1.0</spring.cloud.alibaba.version>
|
||||||
<!-- Web 相关 -->
|
<!-- Web 相关 -->
|
||||||
<knife4j.version>3.0.3</knife4j.version>
|
<knife4j.version>3.0.3</knife4j.version>
|
||||||
<swagger-annotations.version>1.6.6</swagger-annotations.version>
|
<swagger-annotations.version>1.6.7</swagger-annotations.version>
|
||||||
<servlet.versoin>2.5</servlet.versoin>
|
<servlet.versoin>2.5</servlet.versoin>
|
||||||
<!-- DB 相关 -->
|
<!-- DB 相关 -->
|
||||||
<druid.version>1.2.11</druid.version>
|
<druid.version>1.2.14</druid.version>
|
||||||
<mybatis-plus.version>3.4.3.4</mybatis-plus.version>
|
<mybatis-plus.version>3.5.2</mybatis-plus.version>
|
||||||
<mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version>
|
<mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version>
|
||||||
<dynamic-datasource.version>3.5.0</dynamic-datasource.version>
|
<dynamic-datasource.version>3.5.2</dynamic-datasource.version>
|
||||||
<redisson.version>3.17.3</redisson.version>
|
<redisson.version>3.17.7</redisson.version>
|
||||||
<!-- RPC 相关 -->
|
<!-- RPC 相关 -->
|
||||||
<dubbo.version>2.7.15</dubbo.version>
|
<dubbo.version>2.7.15</dubbo.version>
|
||||||
<!-- Config 配置中心相关 -->
|
<!-- Config 配置中心相关 -->
|
||||||
|
@ -36,37 +36,38 @@
|
||||||
<!-- Job 定时任务相关 -->
|
<!-- Job 定时任务相关 -->
|
||||||
<xxl-job.version>2.3.1</xxl-job.version>
|
<xxl-job.version>2.3.1</xxl-job.version>
|
||||||
<!-- 服务保障相关 -->
|
<!-- 服务保障相关 -->
|
||||||
<lock4j.version>2.2.0</lock4j.version>
|
<lock4j.version>2.2.2</lock4j.version>
|
||||||
<resilience4j.version>1.7.1</resilience4j.version>
|
<resilience4j.version>1.7.1</resilience4j.version>
|
||||||
<!-- 监控相关 -->
|
<!-- 监控相关 -->
|
||||||
<skywalking.version>8.7.0</skywalking.version>
|
<skywalking.version>8.12.0</skywalking.version>
|
||||||
<spring-boot-admin.version>2.6.7</spring-boot-admin.version>
|
<spring-boot-admin.version>2.6.9</spring-boot-admin.version>
|
||||||
<opentracing.version>0.31.0</opentracing.version>
|
<opentracing.version>0.33.0</opentracing.version>
|
||||||
<!-- Test 测试相关 -->
|
<!-- Test 测试相关 -->
|
||||||
<podam.version>7.2.6.RELEASE</podam.version>
|
<podam.version>7.2.9.RELEASE</podam.version>
|
||||||
<jedis-mock.version>0.1.16</jedis-mock.version>
|
<jedis-mock.version>1.0.4</jedis-mock.version>
|
||||||
<mockito-inline.version>4.0.0</mockito-inline.version>
|
<mockito-inline.version>4.8.0</mockito-inline.version>
|
||||||
<!-- Bpm 工作流相关 -->
|
<!-- Bpm 工作流相关 -->
|
||||||
<flowable.version>6.7.2</flowable.version>
|
<flowable.version>6.7.2</flowable.version>
|
||||||
<!-- 工具类相关 -->
|
<!-- 工具类相关 -->
|
||||||
<jasypt-spring-boot-starter.version>3.0.4</jasypt-spring-boot-starter.version>
|
<jasypt-spring-boot-starter.version>3.0.4</jasypt-spring-boot-starter.version>
|
||||||
<lombok.version>1.18.20</lombok.version>
|
<lombok.version>1.18.24</lombok.version>
|
||||||
<mapstruct.version>1.4.1.Final</mapstruct.version>
|
<mapstruct.version>1.5.3.Final</mapstruct.version>
|
||||||
<hutool.version>5.8.5</hutool.version>
|
<hutool.version>5.8.9</hutool.version>
|
||||||
<easyexcel.verion>2.2.7</easyexcel.verion>
|
<easyexcel.verion>3.1.2</easyexcel.verion>
|
||||||
<velocity.version>2.3</velocity.version>
|
<velocity.version>2.3</velocity.version>
|
||||||
<screw.version>1.0.5</screw.version>
|
<screw.version>1.0.5</screw.version>
|
||||||
<fastjson.version>2.0.5</fastjson.version>
|
<fastjson.version>1.2.83</fastjson.version>
|
||||||
<guava.version>30.1.1-jre</guava.version>
|
<guava.version>30.1.1-jre</guava.version>
|
||||||
<guice.version>5.1.0</guice.version>
|
<guice.version>5.1.0</guice.version>
|
||||||
<transmittable-thread-local.version>2.12.2</transmittable-thread-local.version>
|
<transmittable-thread-local.version>2.14.0</transmittable-thread-local.version>
|
||||||
<commons-net.version>3.8.0</commons-net.version>
|
<commons-net.version>3.8.0</commons-net.version>
|
||||||
<jsch.version>0.1.55</jsch.version>
|
<jsch.version>0.1.55</jsch.version>
|
||||||
<tika-core.version>2.4.1</tika-core.version>
|
<tika-core.version>2.5.0</tika-core.version>
|
||||||
<aj-captcha.version>1.3.0</aj-captcha.version>
|
<aj-captcha.version>1.3.0</aj-captcha.version>
|
||||||
|
<netty-all.version>4.1.82.Final</netty-all.version>
|
||||||
<!-- 三方云服务相关 -->
|
<!-- 三方云服务相关 -->
|
||||||
<minio.version>8.2.2</minio.version>
|
<minio.version>8.2.2</minio.version>
|
||||||
<aliyun-java-sdk-core.version>4.6.0</aliyun-java-sdk-core.version>
|
<aliyun-java-sdk-core.version>4.6.2</aliyun-java-sdk-core.version>
|
||||||
<aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version>
|
<aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version>
|
||||||
<tencentcloud-sdk-java.version>3.1.561</tencentcloud-sdk-java.version>
|
<tencentcloud-sdk-java.version>3.1.561</tencentcloud-sdk-java.version>
|
||||||
<yunpian-java-sdk.version>1.2.7</yunpian-java-sdk.version>
|
<yunpian-java-sdk.version>1.2.7</yunpian-java-sdk.version>
|
||||||
|
@ -563,6 +564,12 @@
|
||||||
<version>${jsch.version}</version>
|
<version>${jsch.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-all</artifactId>
|
||||||
|
<version>${netty-all.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 三方云服务相关 -->
|
<!-- 三方云服务相关 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.iocoder.cloud</groupId>
|
<groupId>cn.iocoder.cloud</groupId>
|
||||||
|
|
|
@ -105,6 +105,11 @@
|
||||||
<artifactId>jackson-core</artifactId>
|
<artifactId>jackson-core</artifactId>
|
||||||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||||
|
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||||
|
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
|
|
|
@ -12,7 +12,8 @@ import lombok.Getter;
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum DocumentEnum {
|
public enum DocumentEnum {
|
||||||
|
|
||||||
REDIS_INSTALL("https://gitee.com/zhijiantianya/ruoyi-vue-pro/issues/I4VCSJ", "Redis 安装文档");
|
REDIS_INSTALL("https://gitee.com/zhijiantianya/ruoyi-vue-pro/issues/I4VCSJ", "Redis 安装文档"),
|
||||||
|
TENANT("https://doc.iocoder.cn", "SaaS 多租户文档");
|
||||||
|
|
||||||
private final String url;
|
private final String url;
|
||||||
private final String memo;
|
private final String memo;
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package cn.iocoder.yudao.framework.common.util.date;
|
package cn.iocoder.yudao.framework.common.util.date;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.*;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
@ -25,6 +26,34 @@ public class DateUtils {
|
||||||
|
|
||||||
public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";
|
public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 LocalDateTime 转换成 Date
|
||||||
|
*
|
||||||
|
* @param date LocalDateTime
|
||||||
|
* @return LocalDateTime
|
||||||
|
*/
|
||||||
|
public static Date of(LocalDateTime date) {
|
||||||
|
// 将此日期时间与时区相结合以创建 ZonedDateTime
|
||||||
|
ZonedDateTime zonedDateTime = date.atZone(ZoneId.systemDefault());
|
||||||
|
// 本地时间线 LocalDateTime 到即时时间线 Instant 时间戳
|
||||||
|
Instant instant = zonedDateTime.toInstant();
|
||||||
|
// UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
|
||||||
|
return Date.from(instant);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 Date 转换成 LocalDateTime
|
||||||
|
*
|
||||||
|
* @param date Date
|
||||||
|
* @return LocalDateTime
|
||||||
|
*/
|
||||||
|
public static LocalDateTime of(Date date) {
|
||||||
|
// 转为时间戳
|
||||||
|
Instant instant = date.toInstant();
|
||||||
|
// UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
|
||||||
|
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||||
|
}
|
||||||
|
|
||||||
public static Date addTime(Duration duration) {
|
public static Date addTime(Duration duration) {
|
||||||
return new Date(System.currentTimeMillis() + duration.toMillis());
|
return new Date(System.currentTimeMillis() + duration.toMillis());
|
||||||
}
|
}
|
||||||
|
@ -33,6 +62,11 @@ public class DateUtils {
|
||||||
return System.currentTimeMillis() > time.getTime();
|
return System.currentTimeMillis() > time.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isExpired(LocalDateTime time) {
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
return now.isAfter(time);
|
||||||
|
}
|
||||||
|
|
||||||
public static long diff(Date endTime, Date startTime) {
|
public static long diff(Date endTime, Date startTime) {
|
||||||
return endTime.getTime() - startTime.getTime();
|
return endTime.getTime() - startTime.getTime();
|
||||||
}
|
}
|
||||||
|
@ -49,6 +83,10 @@ public class DateUtils {
|
||||||
return buildTime(year, mouth, day, 0, 0, 0);
|
return buildTime(year, mouth, day, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static LocalDateTime buildLocalDateTime(int year, int mouth, int day) {
|
||||||
|
return LocalDateTime.of(year, mouth, day, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建指定时间
|
* 创建指定时间
|
||||||
*
|
*
|
||||||
|
@ -83,6 +121,16 @@ public class DateUtils {
|
||||||
return a.compareTo(b) > 0 ? a : b;
|
return a.compareTo(b) > 0 ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static LocalDateTime max(LocalDateTime a, LocalDateTime b) {
|
||||||
|
if (a == null) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
if (b == null) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return a.isAfter(b) ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean beforeNow(Date date) {
|
public static boolean beforeNow(Date date) {
|
||||||
return date.getTime() < System.currentTimeMillis();
|
return date.getTime() < System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
@ -91,6 +139,10 @@ public class DateUtils {
|
||||||
return date.getTime() >= System.currentTimeMillis();
|
return date.getTime() >= System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean afterNow(LocalDateTime localDateTime) {
|
||||||
|
return localDateTime.isAfter(LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算当期时间相差的日期
|
* 计算当期时间相差的日期
|
||||||
*
|
*
|
||||||
|
@ -135,4 +187,14 @@ public class DateUtils {
|
||||||
return DateUtil.isSameDay(date, new Date());
|
return DateUtil.isSameDay(date, new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否今天
|
||||||
|
*
|
||||||
|
* @param date 日期
|
||||||
|
* @return 是否
|
||||||
|
*/
|
||||||
|
public static boolean isToday(LocalDateTime date) {
|
||||||
|
return LocalDateTimeUtil.isSameDay(date, LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
@ -28,6 +29,7 @@ public class JsonUtils {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||||
|
objectMapper.registerModules(new JavaTimeModule()); // 解决 LocalDateTime 的序列化
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,7 +18,6 @@ import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
||||||
import net.sf.jsqlparser.expression.operators.relational.ExistsExpression;
|
import net.sf.jsqlparser.expression.operators.relational.ExistsExpression;
|
||||||
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
||||||
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
||||||
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
|
|
||||||
import net.sf.jsqlparser.schema.Table;
|
import net.sf.jsqlparser.schema.Table;
|
||||||
import net.sf.jsqlparser.statement.delete.Delete;
|
import net.sf.jsqlparser.statement.delete.Delete;
|
||||||
import net.sf.jsqlparser.statement.select.*;
|
import net.sf.jsqlparser.statement.select.*;
|
||||||
|
@ -37,7 +36,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据权限拦截器,通过 {@link DataPermissionRule} 数据权限规则,重写 SQL 的方式来实现
|
* 数据权限拦截器,通过 {@link DataPermissionRule} 数据权限规则,重写 SQL 的方式来实现
|
||||||
* 主要的 SQL 重写方法,可见 {@link #builderExpression(Expression, Table)} 方法
|
* 主要的 SQL 重写方法,可见 {@link #builderExpression(Expression, List)} 方法
|
||||||
*
|
*
|
||||||
* 整体的代码实现上,参考 {@link com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor} 实现。
|
* 整体的代码实现上,参考 {@link com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor} 实现。
|
||||||
* 所以每次 MyBatis Plus 升级时,需要 Review 下其具体的实现是否有变更!
|
* 所以每次 MyBatis Plus 升级时,需要 Review 下其具体的实现是否有变更!
|
||||||
|
@ -53,8 +52,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||||
private final MappedStatementCache mappedStatementCache = new MappedStatementCache();
|
private final MappedStatementCache mappedStatementCache = new MappedStatementCache();
|
||||||
|
|
||||||
@Override // SELECT 场景
|
@Override // SELECT 场景
|
||||||
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter,
|
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
|
||||||
RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
|
|
||||||
// 获得 Mapper 对应的数据权限的规则
|
// 获得 Mapper 对应的数据权限的规则
|
||||||
List<DataPermissionRule> rules = ruleFactory.getDataPermissionRule(ms.getId());
|
List<DataPermissionRule> rules = ruleFactory.getDataPermissionRule(ms.getId());
|
||||||
if (mappedStatementCache.noRewritable(ms, rules)) { // 如果无需重写,则跳过
|
if (mappedStatementCache.noRewritable(ms, rules)) { // 如果无需重写,则跳过
|
||||||
|
@ -68,12 +66,14 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||||
// 处理 SQL
|
// 处理 SQL
|
||||||
mpBs.sql(parserSingle(mpBs.sql(), null));
|
mpBs.sql(parserSingle(mpBs.sql(), null));
|
||||||
} finally {
|
} finally {
|
||||||
|
// 添加是否需要重写的缓存
|
||||||
addMappedStatementCache(ms);
|
addMappedStatementCache(ms);
|
||||||
|
// 清空上下文
|
||||||
ContextHolder.clear();
|
ContextHolder.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override // 只处理 UPDATE / DELETE 场景,不处理 INSERT 场景
|
@Override // 只处理 UPDATE / DELETE 场景,不处理 INSERT 场景(因为 INSERT 不需要数据权限)
|
||||||
public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
|
public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
|
||||||
PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
|
PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
|
||||||
MappedStatement ms = mpSh.mappedStatement();
|
MappedStatement ms = mpSh.mappedStatement();
|
||||||
|
@ -92,7 +92,9 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||||
// 处理 SQL
|
// 处理 SQL
|
||||||
mpBs.sql(parserMulti(mpBs.sql(), null));
|
mpBs.sql(parserMulti(mpBs.sql(), null));
|
||||||
} finally {
|
} finally {
|
||||||
|
// 添加是否需要重写的缓存
|
||||||
addMappedStatementCache(ms);
|
addMappedStatementCache(ms);
|
||||||
|
// 清空上下文
|
||||||
ContextHolder.clear();
|
ContextHolder.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,24 +109,6 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* update 语句处理
|
* update 语句处理
|
||||||
*/
|
*/
|
||||||
|
@ -142,28 +126,77 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||||
delete.setWhere(this.builderExpression(delete.getWhere(), delete.getTable()));
|
delete.setWhere(this.builderExpression(delete.getWhere(), delete.getTable()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== 和 TenantLineInnerInterceptor 一致的逻辑 ==========
|
||||||
|
|
||||||
|
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> selectBodyList = operationList.getSelects();
|
||||||
|
if (CollectionUtils.isNotEmpty(selectBodyList)) {
|
||||||
|
selectBodyList.forEach(this::processSelectBody);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理 PlainSelect
|
* 处理 PlainSelect
|
||||||
*/
|
*/
|
||||||
protected void processPlainSelect(PlainSelect plainSelect) {
|
protected void processPlainSelect(PlainSelect plainSelect) {
|
||||||
FromItem fromItem = plainSelect.getFromItem();
|
|
||||||
Expression where = plainSelect.getWhere();
|
|
||||||
processWhereSubSelect(where);
|
|
||||||
if (fromItem instanceof Table) {
|
|
||||||
Table fromTable = (Table) fromItem;
|
|
||||||
plainSelect.setWhere(builderExpression(where, fromTable));
|
|
||||||
} else {
|
|
||||||
processFromItem(fromItem);
|
|
||||||
}
|
|
||||||
//#3087 github
|
//#3087 github
|
||||||
List<SelectItem> selectItems = plainSelect.getSelectItems();
|
List<SelectItem> selectItems = plainSelect.getSelectItems();
|
||||||
if (CollectionUtils.isNotEmpty(selectItems)) {
|
if (CollectionUtils.isNotEmpty(selectItems)) {
|
||||||
selectItems.forEach(this::processSelectItem);
|
selectItems.forEach(this::processSelectItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理 where 中的子查询
|
||||||
|
Expression where = plainSelect.getWhere();
|
||||||
|
processWhereSubSelect(where);
|
||||||
|
|
||||||
|
// 处理 fromItem
|
||||||
|
FromItem fromItem = plainSelect.getFromItem();
|
||||||
|
List<Table> list = processFromItem(fromItem);
|
||||||
|
List<Table> mainTables = new ArrayList<>(list);
|
||||||
|
|
||||||
|
// 处理 join
|
||||||
List<Join> joins = plainSelect.getJoins();
|
List<Join> joins = plainSelect.getJoins();
|
||||||
if (CollectionUtils.isNotEmpty(joins)) {
|
if (CollectionUtils.isNotEmpty(joins)) {
|
||||||
processJoins(joins);
|
mainTables = processJoins(mainTables, joins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 当有 mainTable 时,进行 where 条件追加
|
||||||
|
if (CollectionUtils.isNotEmpty(mainTables)) {
|
||||||
|
plainSelect.setWhere(builderExpression(where, mainTables));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Table> processFromItem(FromItem fromItem) {
|
||||||
|
// 处理括号括起来的表达式
|
||||||
|
while (fromItem instanceof ParenthesisFromItem) {
|
||||||
|
fromItem = ((ParenthesisFromItem) fromItem).getFromItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Table> mainTables = new ArrayList<>();
|
||||||
|
// 无 join 时的处理逻辑
|
||||||
|
if (fromItem instanceof Table) {
|
||||||
|
Table fromTable = (Table) fromItem;
|
||||||
|
mainTables.add(fromTable);
|
||||||
|
} else if (fromItem instanceof SubJoin) {
|
||||||
|
// SubJoin 类型则还需要添加上 where 条件
|
||||||
|
List<Table> tables = processSubJoin((SubJoin) fromItem);
|
||||||
|
mainTables.addAll(tables);
|
||||||
|
} else {
|
||||||
|
// 处理下 fromItem
|
||||||
|
processOtherFromItem(fromItem);
|
||||||
|
}
|
||||||
|
return mainTables;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -191,7 +224,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (where instanceof FromItem) {
|
if (where instanceof FromItem) {
|
||||||
processFromItem((FromItem) where);
|
processOtherFromItem((FromItem) where);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (where.toString().indexOf("SELECT") > 0) {
|
if (where.toString().indexOf("SELECT") > 0) {
|
||||||
|
@ -204,9 +237,9 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||||
} else if (where instanceof InExpression) {
|
} else if (where instanceof InExpression) {
|
||||||
// in
|
// in
|
||||||
InExpression expression = (InExpression) where;
|
InExpression expression = (InExpression) where;
|
||||||
ItemsList itemsList = expression.getRightItemsList();
|
Expression inExpression = expression.getRightExpression();
|
||||||
if (itemsList instanceof SubSelect) {
|
if (inExpression instanceof SubSelect) {
|
||||||
processSelectBody(((SubSelect) itemsList).getSelectBody());
|
processSelectBody(((SubSelect) inExpression).getSelectBody());
|
||||||
}
|
}
|
||||||
} else if (where instanceof ExistsExpression) {
|
} else if (where instanceof ExistsExpression) {
|
||||||
// exists
|
// exists
|
||||||
|
@ -239,7 +272,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||||
* <p>支持: 1. select fun(args..) 2. select fun1(fun2(args..),args..)<p>
|
* <p>支持: 1. select fun(args..) 2. select fun1(fun2(args..),args..)<p>
|
||||||
* <p> fixed gitee pulls/141</p>
|
* <p> fixed gitee pulls/141</p>
|
||||||
*
|
*
|
||||||
* @param function 函数
|
* @param function
|
||||||
*/
|
*/
|
||||||
protected void processFunction(Function function) {
|
protected void processFunction(Function function) {
|
||||||
ExpressionList parameters = function.getParameters();
|
ExpressionList parameters = function.getParameters();
|
||||||
|
@ -257,22 +290,19 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||||
/**
|
/**
|
||||||
* 处理子查询等
|
* 处理子查询等
|
||||||
*/
|
*/
|
||||||
protected void processFromItem(FromItem fromItem) {
|
protected void processOtherFromItem(FromItem fromItem) {
|
||||||
if (fromItem instanceof SubJoin) {
|
// 去除括号
|
||||||
SubJoin subJoin = (SubJoin) fromItem;
|
while (fromItem instanceof ParenthesisFromItem) {
|
||||||
if (subJoin.getJoinList() != null) {
|
fromItem = ((ParenthesisFromItem) fromItem).getFromItem();
|
||||||
processJoins(subJoin.getJoinList());
|
|
||||||
}
|
}
|
||||||
if (subJoin.getLeft() != null) {
|
|
||||||
processFromItem(subJoin.getLeft());
|
if (fromItem instanceof SubSelect) {
|
||||||
}
|
|
||||||
} else if (fromItem instanceof SubSelect) {
|
|
||||||
SubSelect subSelect = (SubSelect) fromItem;
|
SubSelect subSelect = (SubSelect) fromItem;
|
||||||
if (subSelect.getSelectBody() != null) {
|
if (subSelect.getSelectBody() != null) {
|
||||||
processSelectBody(subSelect.getSelectBody());
|
processSelectBody(subSelect.getSelectBody());
|
||||||
}
|
}
|
||||||
} else if (fromItem instanceof ValuesList) {
|
} else if (fromItem instanceof ValuesList) {
|
||||||
logger.debug("Perform a subquery, if you do not give us feedback");
|
logger.debug("Perform a subQuery, if you do not give us feedback");
|
||||||
} else if (fromItem instanceof LateralSubSelect) {
|
} else if (fromItem instanceof LateralSubSelect) {
|
||||||
LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem;
|
LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem;
|
||||||
if (lateralSubSelect.getSubSelect() != null) {
|
if (lateralSubSelect.getSubSelect() != null) {
|
||||||
|
@ -284,75 +314,176 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理 sub join
|
||||||
|
*
|
||||||
|
* @param subJoin subJoin
|
||||||
|
* @return Table subJoin 中的主表
|
||||||
|
*/
|
||||||
|
private List<Table> processSubJoin(SubJoin subJoin) {
|
||||||
|
List<Table> mainTables = new ArrayList<>();
|
||||||
|
if (subJoin.getJoinList() != null) {
|
||||||
|
List<Table> list = processFromItem(subJoin.getLeft());
|
||||||
|
mainTables.addAll(list);
|
||||||
|
mainTables = processJoins(mainTables, subJoin.getJoinList());
|
||||||
|
}
|
||||||
|
return mainTables;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理 joins
|
* 处理 joins
|
||||||
*
|
*
|
||||||
|
* @param mainTables 可以为 null
|
||||||
* @param joins join 集合
|
* @param joins join 集合
|
||||||
|
* @return List<Table> 右连接查询的 Table 列表
|
||||||
*/
|
*/
|
||||||
private void processJoins(List<Join> joins) {
|
private List<Table> processJoins(List<Table> mainTables, List<Join> joins) {
|
||||||
|
// join 表达式中最终的主表
|
||||||
|
Table mainTable = null;
|
||||||
|
// 当前 join 的左表
|
||||||
|
Table leftTable = null;
|
||||||
|
|
||||||
|
if (mainTables == null) {
|
||||||
|
mainTables = new ArrayList<>();
|
||||||
|
} else if (mainTables.size() == 1) {
|
||||||
|
mainTable = mainTables.get(0);
|
||||||
|
leftTable = mainTable;
|
||||||
|
}
|
||||||
|
|
||||||
//对于 on 表达式写在最后的 join,需要记录下前面多个 on 的表名
|
//对于 on 表达式写在最后的 join,需要记录下前面多个 on 的表名
|
||||||
Deque<Table> tables = new LinkedList<>();
|
Deque<List<Table>> onTableDeque = new LinkedList<>();
|
||||||
for (Join join : joins) {
|
for (Join join : joins) {
|
||||||
// 处理 on 表达式
|
// 处理 on 表达式
|
||||||
FromItem fromItem = join.getRightItem();
|
FromItem joinItem = join.getRightItem();
|
||||||
if (fromItem instanceof Table) {
|
|
||||||
Table fromTable = (Table) fromItem;
|
// 获取当前 join 的表,subJoint 可以看作是一张表
|
||||||
|
List<Table> joinTables = null;
|
||||||
|
if (joinItem instanceof Table) {
|
||||||
|
joinTables = new ArrayList<>();
|
||||||
|
joinTables.add((Table) joinItem);
|
||||||
|
} else if (joinItem instanceof SubJoin) {
|
||||||
|
joinTables = processSubJoin((SubJoin) joinItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joinTables != null) {
|
||||||
|
|
||||||
|
// 如果是隐式内连接
|
||||||
|
if (join.isSimple()) {
|
||||||
|
mainTables.addAll(joinTables);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当前表是否忽略
|
||||||
|
Table joinTable = joinTables.get(0);
|
||||||
|
|
||||||
|
List<Table> onTables = null;
|
||||||
|
// 如果不要忽略,且是右连接,则记录下当前表
|
||||||
|
if (join.isRight()) {
|
||||||
|
mainTable = joinTable;
|
||||||
|
if (leftTable != null) {
|
||||||
|
onTables = Collections.singletonList(leftTable);
|
||||||
|
}
|
||||||
|
} else if (join.isLeft()) {
|
||||||
|
onTables = Collections.singletonList(joinTable);
|
||||||
|
} else if (join.isInner()) {
|
||||||
|
if (mainTable == null) {
|
||||||
|
onTables = Collections.singletonList(joinTable);
|
||||||
|
} else {
|
||||||
|
onTables = Arrays.asList(mainTable, joinTable);
|
||||||
|
}
|
||||||
|
mainTable = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
mainTables = new ArrayList<>();
|
||||||
|
if (mainTable != null) {
|
||||||
|
mainTables.add(mainTable);
|
||||||
|
}
|
||||||
|
|
||||||
// 获取 join 尾缀的 on 表达式列表
|
// 获取 join 尾缀的 on 表达式列表
|
||||||
Collection<Expression> originOnExpressions = join.getOnExpressions();
|
Collection<Expression> originOnExpressions = join.getOnExpressions();
|
||||||
// 正常 join on 表达式只有一个,立刻处理
|
// 正常 join on 表达式只有一个,立刻处理
|
||||||
if (originOnExpressions.size() == 1) {
|
if (originOnExpressions.size() == 1 && onTables != null) {
|
||||||
processJoin(join);
|
List<Expression> onExpressions = new LinkedList<>();
|
||||||
|
onExpressions.add(builderExpression(originOnExpressions.iterator().next(), onTables));
|
||||||
|
join.setOnExpressions(onExpressions);
|
||||||
|
leftTable = joinTable;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tables.push(fromTable);
|
// 表名压栈,忽略的表压入 null,以便后续不处理
|
||||||
|
onTableDeque.push(onTables);
|
||||||
// 尾缀多个 on 表达式的时候统一处理
|
// 尾缀多个 on 表达式的时候统一处理
|
||||||
if (originOnExpressions.size() > 1) {
|
if (originOnExpressions.size() > 1) {
|
||||||
Collection<Expression> onExpressions = new LinkedList<>();
|
Collection<Expression> onExpressions = new LinkedList<>();
|
||||||
for (Expression originOnExpression : originOnExpressions) {
|
for (Expression originOnExpression : originOnExpressions) {
|
||||||
Table currentTable = tables.poll();
|
List<Table> currentTableList = onTableDeque.poll();
|
||||||
onExpressions.add(builderExpression(originOnExpression, currentTable));
|
if (CollectionUtils.isEmpty(currentTableList)) {
|
||||||
|
onExpressions.add(originOnExpression);
|
||||||
|
} else {
|
||||||
|
onExpressions.add(builderExpression(originOnExpression, currentTableList));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
join.setOnExpressions(onExpressions);
|
join.setOnExpressions(onExpressions);
|
||||||
}
|
}
|
||||||
|
leftTable = joinTable;
|
||||||
} else {
|
} else {
|
||||||
// 处理右边连接的子表达式
|
processOtherFromItem(joinItem);
|
||||||
processFromItem(fromItem);
|
leftTable = null;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return mainTables;
|
||||||
* 处理联接语句
|
|
||||||
*/
|
|
||||||
protected void processJoin(Join join) {
|
|
||||||
if (join.getRightItem() instanceof Table) {
|
|
||||||
Table fromTable = (Table) join.getRightItem();
|
|
||||||
Expression originOnExpression = CollUtil.getFirst(join.getOnExpressions());
|
|
||||||
originOnExpression = builderExpression(originOnExpression, fromTable);
|
|
||||||
join.setOnExpressions(CollUtil.newArrayList(originOnExpression));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== 和 TenantLineInnerInterceptor 存在差异的逻辑:关键,实现权限条件的拼接 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理条件
|
||||||
|
*
|
||||||
|
* @param currentExpression 当前 where 条件
|
||||||
|
* @param table 单个表
|
||||||
|
*/
|
||||||
|
protected Expression builderExpression(Expression currentExpression, Table table) {
|
||||||
|
return this.builderExpression(currentExpression, Collections.singletonList(table));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理条件
|
* 处理条件
|
||||||
|
*
|
||||||
|
* @param currentExpression 当前 where 条件
|
||||||
|
* @param tables 多个表
|
||||||
*/
|
*/
|
||||||
protected Expression builderExpression(Expression currentExpression, Table table) {
|
protected Expression builderExpression(Expression currentExpression, List<Table> tables) {
|
||||||
// 获得 Table 对应的数据权限条件
|
// 没有表需要处理直接返回
|
||||||
Expression equalsTo = buildDataPermissionExpression(table);
|
if (CollectionUtils.isEmpty(tables)) {
|
||||||
if (equalsTo == null) { // 如果没条件,则返回 currentExpression 默认
|
|
||||||
return currentExpression;
|
return currentExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 表达式为空,则直接返回 equalsTo
|
// 第一步,获得 Table 对应的数据权限条件
|
||||||
|
Expression dataPermissionExpression = null;
|
||||||
|
for (Table table : tables) {
|
||||||
|
// 构建每个表的权限 Expression 条件
|
||||||
|
Expression expression = buildDataPermissionExpression(table);
|
||||||
|
if (expression == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 合并到 dataPermissionExpression 中
|
||||||
|
dataPermissionExpression = dataPermissionExpression == null ? expression
|
||||||
|
: new AndExpression(dataPermissionExpression, expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第二步,合并多个 Expression 条件
|
||||||
|
if (dataPermissionExpression == null) {
|
||||||
|
return currentExpression;
|
||||||
|
}
|
||||||
if (currentExpression == null) {
|
if (currentExpression == null) {
|
||||||
return equalsTo;
|
return dataPermissionExpression;
|
||||||
}
|
}
|
||||||
// 如果表达式为 Or,则需要 (currentExpression) AND equalsTo
|
// ① 如果表达式为 Or,则需要 (currentExpression) AND dataPermissionExpression
|
||||||
if (currentExpression instanceof OrExpression) {
|
if (currentExpression instanceof OrExpression) {
|
||||||
return new AndExpression(new Parenthesis(currentExpression), equalsTo);
|
return new AndExpression(new Parenthesis(currentExpression), dataPermissionExpression);
|
||||||
}
|
}
|
||||||
// 如果表达式为 And,则直接返回 currentExpression AND equalsTo
|
// ② 如果表达式为 And,则直接返回 where AND dataPermissionExpression
|
||||||
return new AndExpression(currentExpression, equalsTo);
|
return new AndExpression(currentExpression, dataPermissionExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule;
|
import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule;
|
||||||
|
@ -106,7 +105,7 @@ public class DeptDataPermissionRule implements DataPermissionRule {
|
||||||
DeptDataPermissionRespDTO deptDataPermission = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class);
|
DeptDataPermissionRespDTO deptDataPermission = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class);
|
||||||
// 从上下文中拿不到,则调用逻辑进行获取
|
// 从上下文中拿不到,则调用逻辑进行获取
|
||||||
if (deptDataPermission == null) {
|
if (deptDataPermission == null) {
|
||||||
deptDataPermission = permissionApi.getDeptDataPermission(loginUser.getId()).getData();
|
deptDataPermission = permissionApi.getDeptDataPermission(loginUser.getId()).getCheckedData();
|
||||||
if (deptDataPermission == null) {
|
if (deptDataPermission == null) {
|
||||||
log.error("[getExpression][LoginUser({}) 获取数据权限为 null]", JsonUtils.toJsonString(loginUser));
|
log.error("[getExpression][LoginUser({}) 获取数据权限为 null]", JsonUtils.toJsonString(loginUser));
|
||||||
throw new NullPointerException(String.format("LoginUser(%d) Table(%s/%s) 未返回数据权限",
|
throw new NullPointerException(String.format("LoginUser(%d) Table(%s/%s) 未返回数据权限",
|
||||||
|
|
|
@ -87,7 +87,7 @@ public class DataPermissionDatabaseInterceptorTest extends BaseMockitoUnitTest {
|
||||||
interceptor.beforeQuery(null, mappedStatement, null, null, null, boundSql);
|
interceptor.beforeQuery(null, mappedStatement, null, null, null, boundSql);
|
||||||
// 断言
|
// 断言
|
||||||
verify(mpBs, times(1)).sql(
|
verify(mpBs, times(1)).sql(
|
||||||
eq("SELECT * FROM t_user WHERE id = 1 AND dept_id = 100"));
|
eq("SELECT * FROM t_user WHERE id = 1 AND t_user.dept_id = 100"));
|
||||||
// 断言缓存
|
// 断言缓存
|
||||||
assertTrue(interceptor.getMappedStatementCache().getNoRewritableMappedStatements().isEmpty());
|
assertTrue(interceptor.getMappedStatementCache().getNoRewritableMappedStatements().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getTableNames() {
|
public Set<String> getTableNames() {
|
||||||
return asSet("entity", "entity1", "entity2", "t1", "t2", // 支持 MyBatis Plus 的单元测试
|
return asSet("entity", "entity1", "entity2", "entity3", "t1", "t2", "sys_dict_item", // 支持 MyBatis Plus 的单元测试
|
||||||
"t_user", "t_role"); // 满足自己的单元测试
|
"t_user", "t_role"); // 满足自己的单元测试
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,30 +84,30 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||||
@Test
|
@Test
|
||||||
void delete() {
|
void delete() {
|
||||||
assertSql("delete from entity where id = ?",
|
assertSql("delete from entity where id = ?",
|
||||||
"DELETE FROM entity WHERE id = ? AND tenant_id = 1");
|
"DELETE FROM entity WHERE id = ? AND entity.tenant_id = 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void update() {
|
void update() {
|
||||||
assertSql("update entity set name = ? where id = ?",
|
assertSql("update entity set name = ? where id = ?",
|
||||||
"UPDATE entity SET name = ? WHERE id = ? AND tenant_id = 1");
|
"UPDATE entity SET name = ? WHERE id = ? AND entity.tenant_id = 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void selectSingle() {
|
void selectSingle() {
|
||||||
// 单表
|
// 单表
|
||||||
assertSql("select * from entity where id = ?",
|
assertSql("select * from entity where id = ?",
|
||||||
"SELECT * FROM entity WHERE id = ? AND tenant_id = 1");
|
"SELECT * FROM entity WHERE id = ? AND entity.tenant_id = 1");
|
||||||
|
|
||||||
assertSql("select * from entity where id = ? or name = ?",
|
assertSql("select * from entity where id = ? or name = ?",
|
||||||
"SELECT * FROM entity WHERE (id = ? OR name = ?) AND tenant_id = 1");
|
"SELECT * FROM entity WHERE (id = ? OR name = ?) AND entity.tenant_id = 1");
|
||||||
|
|
||||||
assertSql("SELECT * FROM entity WHERE (id = ? OR name = ?)",
|
assertSql("SELECT * FROM entity WHERE (id = ? OR name = ?)",
|
||||||
"SELECT * FROM entity WHERE (id = ? OR name = ?) AND tenant_id = 1");
|
"SELECT * FROM entity WHERE (id = ? OR name = ?) AND entity.tenant_id = 1");
|
||||||
|
|
||||||
/* not */
|
/* not */
|
||||||
assertSql("SELECT * FROM entity WHERE not (id = ? OR name = ?)",
|
assertSql("SELECT * FROM entity WHERE not (id = ? OR name = ?)",
|
||||||
"SELECT * FROM entity WHERE NOT (id = ? OR name = ?) AND tenant_id = 1");
|
"SELECT * FROM entity WHERE NOT (id = ? OR name = ?) AND entity.tenant_id = 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -167,10 +167,12 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||||
assertSql("SELECT * FROM entity e WHERE e.id >= (select e1.id from entity1 e1 where e1.id = ?)",
|
assertSql("SELECT * FROM entity e WHERE e.id >= (select e1.id from entity1 e1 where e1.id = ?)",
|
||||||
"SELECT * FROM entity e WHERE e.id >= (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1");
|
"SELECT * FROM entity e WHERE e.id >= (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1");
|
||||||
|
|
||||||
|
|
||||||
/* <= */
|
/* <= */
|
||||||
assertSql("SELECT * FROM entity e WHERE e.id <= (select e1.id from entity1 e1 where e1.id = ?)",
|
assertSql("SELECT * FROM entity e WHERE e.id <= (select e1.id from entity1 e1 where e1.id = ?)",
|
||||||
"SELECT * FROM entity e WHERE e.id <= (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1");
|
"SELECT * FROM entity e WHERE e.id <= (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1");
|
||||||
|
|
||||||
|
|
||||||
/* <> */
|
/* <> */
|
||||||
assertSql("SELECT * FROM entity e WHERE e.id <> (select e1.id from entity1 e1 where e1.id = ?)",
|
assertSql("SELECT * FROM entity e WHERE e.id <> (select e1.id from entity1 e1 where e1.id = ?)",
|
||||||
"SELECT * FROM entity e WHERE e.id <> (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1");
|
"SELECT * FROM entity e WHERE e.id <> (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1");
|
||||||
|
@ -204,6 +206,14 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||||
"SELECT * FROM entity e " +
|
"SELECT * FROM entity e " +
|
||||||
"LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
"LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
||||||
|
|
||||||
|
assertSql("SELECT * FROM entity e " +
|
||||||
|
"left join entity1 e1 on e1.id = e.id " +
|
||||||
|
"left join entity2 e2 on e1.id = e2.id",
|
||||||
|
"SELECT * FROM entity e " +
|
||||||
|
"LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||||
|
"LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1 " +
|
||||||
|
"WHERE e.tenant_id = 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -212,17 +222,125 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||||
assertSql("SELECT * FROM entity e " +
|
assertSql("SELECT * FROM entity e " +
|
||||||
"right join entity1 e1 on e1.id = e.id",
|
"right join entity1 e1 on e1.id = e.id",
|
||||||
"SELECT * FROM entity e " +
|
"SELECT * FROM entity e " +
|
||||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " +
|
||||||
"WHERE e.tenant_id = 1");
|
"WHERE e1.tenant_id = 1");
|
||||||
|
|
||||||
|
assertSql("SELECT * FROM with_as_1 e " +
|
||||||
|
"right join entity1 e1 on e1.id = e.id",
|
||||||
|
"SELECT * FROM with_as_1 e " +
|
||||||
|
"RIGHT JOIN entity1 e1 ON e1.id = e.id " +
|
||||||
|
"WHERE e1.tenant_id = 1");
|
||||||
|
|
||||||
assertSql("SELECT * FROM entity e " +
|
assertSql("SELECT * FROM entity e " +
|
||||||
"right join entity1 e1 on e1.id = e.id " +
|
"right join entity1 e1 on e1.id = e.id " +
|
||||||
"WHERE e.id = ? OR e.name = ?",
|
"WHERE e.id = ? OR e.name = ?",
|
||||||
"SELECT * FROM entity e " +
|
"SELECT * FROM entity e " +
|
||||||
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " +
|
||||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
"WHERE (e.id = ? OR e.name = ?) AND e1.tenant_id = 1");
|
||||||
|
|
||||||
|
assertSql("SELECT * FROM entity e " +
|
||||||
|
"right join entity1 e1 on e1.id = e.id " +
|
||||||
|
"right join entity2 e2 on e1.id = e2.id ",
|
||||||
|
"SELECT * FROM entity e " +
|
||||||
|
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " +
|
||||||
|
"RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1 " +
|
||||||
|
"WHERE e2.tenant_id = 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void selectMixJoin() {
|
||||||
|
assertSql("SELECT * FROM entity e " +
|
||||||
|
"right join entity1 e1 on e1.id = e.id " +
|
||||||
|
"left join entity2 e2 on e1.id = e2.id",
|
||||||
|
"SELECT * FROM entity e " +
|
||||||
|
"RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " +
|
||||||
|
"LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1 " +
|
||||||
|
"WHERE e1.tenant_id = 1");
|
||||||
|
|
||||||
|
assertSql("SELECT * FROM entity e " +
|
||||||
|
"left join entity1 e1 on e1.id = e.id " +
|
||||||
|
"right join entity2 e2 on e1.id = e2.id",
|
||||||
|
"SELECT * FROM entity e " +
|
||||||
|
"LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||||
|
"RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1 " +
|
||||||
|
"WHERE e2.tenant_id = 1");
|
||||||
|
|
||||||
|
assertSql("SELECT * FROM entity e " +
|
||||||
|
"left join entity1 e1 on e1.id = e.id " +
|
||||||
|
"inner join entity2 e2 on e1.id = e2.id",
|
||||||
|
"SELECT * FROM entity e " +
|
||||||
|
"LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
||||||
|
"INNER JOIN entity2 e2 ON e1.id = e2.id AND e.tenant_id = 1 AND e2.tenant_id = 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void selectJoinSubSelect() {
|
||||||
|
assertSql("select * from (select * from entity) e1 " +
|
||||||
|
"left join entity2 e2 on e1.id = e2.id",
|
||||||
|
"SELECT * FROM (SELECT * FROM entity WHERE entity.tenant_id = 1) e1 " +
|
||||||
|
"LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1");
|
||||||
|
|
||||||
|
assertSql("select * from entity1 e1 " +
|
||||||
|
"left join (select * from entity2) e2 " +
|
||||||
|
"on e1.id = e2.id",
|
||||||
|
"SELECT * FROM entity1 e1 " +
|
||||||
|
"LEFT JOIN (SELECT * FROM entity2 WHERE entity2.tenant_id = 1) e2 " +
|
||||||
|
"ON e1.id = e2.id " +
|
||||||
|
"WHERE e1.tenant_id = 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void selectSubJoin() {
|
||||||
|
|
||||||
|
assertSql("select * FROM " +
|
||||||
|
"(entity1 e1 right JOIN entity2 e2 ON e1.id = e2.id)",
|
||||||
|
"SELECT * FROM " +
|
||||||
|
"(entity1 e1 RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1) " +
|
||||||
|
"WHERE e2.tenant_id = 1");
|
||||||
|
|
||||||
|
assertSql("select * FROM " +
|
||||||
|
"(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id)",
|
||||||
|
"SELECT * FROM " +
|
||||||
|
"(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " +
|
||||||
|
"WHERE e1.tenant_id = 1");
|
||||||
|
|
||||||
|
|
||||||
|
assertSql("select * FROM " +
|
||||||
|
"(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id) " +
|
||||||
|
"right join entity3 e3 on e1.id = e3.id",
|
||||||
|
"SELECT * FROM " +
|
||||||
|
"(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " +
|
||||||
|
"RIGHT JOIN entity3 e3 ON e1.id = e3.id AND e1.tenant_id = 1 " +
|
||||||
|
"WHERE e3.tenant_id = 1");
|
||||||
|
|
||||||
|
|
||||||
|
assertSql("select * FROM entity e " +
|
||||||
|
"LEFT JOIN (entity1 e1 right join entity2 e2 ON e1.id = e2.id) " +
|
||||||
|
"on e.id = e2.id",
|
||||||
|
"SELECT * FROM entity e " +
|
||||||
|
"LEFT JOIN (entity1 e1 RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1) " +
|
||||||
|
"ON e.id = e2.id AND e2.tenant_id = 1 " +
|
||||||
|
"WHERE e.tenant_id = 1");
|
||||||
|
|
||||||
|
assertSql("select * FROM entity e " +
|
||||||
|
"LEFT JOIN (entity1 e1 left join entity2 e2 ON e1.id = e2.id) " +
|
||||||
|
"on e.id = e2.id",
|
||||||
|
"SELECT * FROM entity e " +
|
||||||
|
"LEFT JOIN (entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " +
|
||||||
|
"ON e.id = e2.id AND e1.tenant_id = 1 " +
|
||||||
|
"WHERE e.tenant_id = 1");
|
||||||
|
|
||||||
|
assertSql("select * FROM entity e " +
|
||||||
|
"RIGHT JOIN (entity1 e1 left join entity2 e2 ON e1.id = e2.id) " +
|
||||||
|
"on e.id = e2.id",
|
||||||
|
"SELECT * FROM entity e " +
|
||||||
|
"RIGHT JOIN (entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " +
|
||||||
|
"ON e.id = e2.id AND e.tenant_id = 1 " +
|
||||||
|
"WHERE e1.tenant_id = 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void selectLeftJoinMultipleTrailingOn() {
|
void selectLeftJoinMultipleTrailingOn() {
|
||||||
// 多个 on 尾缀的
|
// 多个 on 尾缀的
|
||||||
|
@ -256,51 +374,97 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||||
"inner join entity1 e1 on e1.id = e.id " +
|
"inner join entity1 e1 on e1.id = e.id " +
|
||||||
"WHERE e.id = ? OR e.name = ?",
|
"WHERE e.id = ? OR e.name = ?",
|
||||||
"SELECT * FROM entity e " +
|
"SELECT * FROM entity e " +
|
||||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
"INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e1.tenant_id = 1 " +
|
||||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
"WHERE e.id = ? OR e.name = ?");
|
||||||
|
|
||||||
assertSql("SELECT * FROM entity e " +
|
assertSql("SELECT * FROM entity e " +
|
||||||
"inner join entity1 e1 on e1.id = e.id " +
|
"inner join entity1 e1 on e1.id = e.id " +
|
||||||
"WHERE (e.id = ? OR e.name = ?)",
|
"WHERE (e.id = ? OR e.name = ?)",
|
||||||
"SELECT * FROM entity e " +
|
"SELECT * FROM entity e " +
|
||||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
"INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e1.tenant_id = 1 " +
|
||||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
"WHERE (e.id = ? OR e.name = ?)");
|
||||||
|
|
||||||
|
// 隐式内连接
|
||||||
|
assertSql("SELECT * FROM entity,entity1 " +
|
||||||
|
"WHERE entity.id = entity1.id",
|
||||||
|
"SELECT * FROM entity, entity1 " +
|
||||||
|
"WHERE entity.id = entity1.id AND entity.tenant_id = 1 AND entity1.tenant_id = 1");
|
||||||
|
|
||||||
|
// 隐式内连接
|
||||||
|
assertSql("SELECT * FROM entity a, with_as_entity1 b " +
|
||||||
|
"WHERE a.id = b.id",
|
||||||
|
"SELECT * FROM entity a, with_as_entity1 b " +
|
||||||
|
"WHERE a.id = b.id AND a.tenant_id = 1");
|
||||||
|
|
||||||
|
assertSql("SELECT * FROM with_as_entity a, with_as_entity1 b " +
|
||||||
|
"WHERE a.id = b.id",
|
||||||
|
"SELECT * FROM with_as_entity a, with_as_entity1 b " +
|
||||||
|
"WHERE a.id = b.id");
|
||||||
|
|
||||||
|
// SubJoin with 隐式内连接
|
||||||
|
assertSql("SELECT * FROM (entity,entity1) " +
|
||||||
|
"WHERE entity.id = entity1.id",
|
||||||
|
"SELECT * FROM (entity, entity1) " +
|
||||||
|
"WHERE entity.id = entity1.id " +
|
||||||
|
"AND entity.tenant_id = 1 AND entity1.tenant_id = 1");
|
||||||
|
|
||||||
|
assertSql("SELECT * FROM ((entity,entity1),entity2) " +
|
||||||
|
"WHERE entity.id = entity1.id and entity.id = entity2.id",
|
||||||
|
"SELECT * FROM ((entity, entity1), entity2) " +
|
||||||
|
"WHERE entity.id = entity1.id AND entity.id = entity2.id " +
|
||||||
|
"AND entity.tenant_id = 1 AND entity1.tenant_id = 1 AND entity2.tenant_id = 1");
|
||||||
|
|
||||||
|
assertSql("SELECT * FROM (entity,(entity1,entity2)) " +
|
||||||
|
"WHERE entity.id = entity1.id and entity.id = entity2.id",
|
||||||
|
"SELECT * FROM (entity, (entity1, entity2)) " +
|
||||||
|
"WHERE entity.id = entity1.id AND entity.id = entity2.id " +
|
||||||
|
"AND entity.tenant_id = 1 AND entity1.tenant_id = 1 AND entity2.tenant_id = 1");
|
||||||
|
|
||||||
|
// 沙雕的括号写法
|
||||||
|
assertSql("SELECT * FROM (((entity,entity1))) " +
|
||||||
|
"WHERE entity.id = entity1.id",
|
||||||
|
"SELECT * FROM (((entity, entity1))) " +
|
||||||
|
"WHERE entity.id = entity1.id " +
|
||||||
|
"AND entity.tenant_id = 1 AND entity1.tenant_id = 1");
|
||||||
|
|
||||||
// 垃圾 inner join todo
|
|
||||||
// assertSql("SELECT * FROM entity,entity1 " +
|
|
||||||
// "WHERE entity.id = entity1.id",
|
|
||||||
// "SELECT * FROM entity e " +
|
|
||||||
// "INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
|
||||||
// "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void selectWithAs() {
|
void selectWithAs() {
|
||||||
assertSql("with with_as_A as (select * from entity) select * from with_as_A",
|
assertSql("with with_as_A as (select * from entity) select * from with_as_A",
|
||||||
"WITH with_as_A AS (SELECT * FROM entity WHERE tenant_id = 1) SELECT * FROM with_as_A");
|
"WITH with_as_A AS (SELECT * FROM entity WHERE entity.tenant_id = 1) SELECT * FROM with_as_A");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void selectIgnoreTable() {
|
||||||
|
assertSql(" SELECT dict.dict_code, item.item_text AS \"text\", item.item_value AS \"value\" FROM sys_dict_item item INNER JOIN sys_dict dict ON dict.id = item.dict_id WHERE dict.dict_code IN (1, 2, 3) AND item.item_value IN (1, 2, 3)",
|
||||||
|
"SELECT dict.dict_code, item.item_text AS \"text\", item.item_value AS \"value\" FROM sys_dict_item item INNER JOIN sys_dict dict ON dict.id = item.dict_id AND item.tenant_id = 1 WHERE dict.dict_code IN (1, 2, 3) AND item.item_value IN (1, 2, 3)");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertSql(String sql, String targetSql) {
|
private void assertSql(String sql, String targetSql) {
|
||||||
assertEquals(targetSql, interceptor.parserSingle(sql, null));
|
assertEquals(targetSql, interceptor.parserSingle(sql, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ========== 额外的测试 ==========
|
// ========== 额外的测试 ==========
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSelectSingle() {
|
public void testSelectSingle() {
|
||||||
// 单表
|
// 单表
|
||||||
assertSql("select * from t_user where id = ?",
|
assertSql("select * from t_user where id = ?",
|
||||||
"SELECT * FROM t_user WHERE id = ? AND tenant_id = 1 AND dept_id IN (10, 20)");
|
"SELECT * FROM t_user WHERE id = ? AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)");
|
||||||
|
|
||||||
assertSql("select * from t_user where id = ? or name = ?",
|
assertSql("select * from t_user where id = ? or name = ?",
|
||||||
"SELECT * FROM t_user WHERE (id = ? OR name = ?) AND tenant_id = 1 AND dept_id IN (10, 20)");
|
"SELECT * FROM t_user WHERE (id = ? OR name = ?) AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)");
|
||||||
|
|
||||||
assertSql("SELECT * FROM t_user WHERE (id = ? OR name = ?)",
|
assertSql("SELECT * FROM t_user WHERE (id = ? OR name = ?)",
|
||||||
"SELECT * FROM t_user WHERE (id = ? OR name = ?) AND tenant_id = 1 AND dept_id IN (10, 20)");
|
"SELECT * FROM t_user WHERE (id = ? OR name = ?) AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)");
|
||||||
|
|
||||||
/* not */
|
/* not */
|
||||||
assertSql("SELECT * FROM t_user WHERE not (id = ? OR name = ?)",
|
assertSql("SELECT * FROM t_user WHERE not (id = ? OR name = ?)",
|
||||||
"SELECT * FROM t_user WHERE NOT (id = ? OR name = ?) AND tenant_id = 1 AND dept_id IN (10, 20)");
|
"SELECT * FROM t_user WHERE NOT (id = ? OR name = ?) AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -329,16 +493,16 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||||
"right join t_role e1 on e1.id = e.id " +
|
"right join t_role e1 on e1.id = e.id " +
|
||||||
"WHERE e.id = ? OR e.name = ?",
|
"WHERE e.id = ? OR e.name = ?",
|
||||||
"SELECT * FROM t_user e " +
|
"SELECT * FROM t_user e " +
|
||||||
"RIGHT JOIN t_role e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
"RIGHT JOIN t_role e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) " +
|
||||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)");
|
"WHERE (e.id = ? OR e.name = ?) AND e1.tenant_id = 1");
|
||||||
|
|
||||||
// 条件 e.id = ? OR e.name = ? 带括号
|
// 条件 e.id = ? OR e.name = ? 带括号
|
||||||
assertSql("SELECT * FROM t_user e " +
|
assertSql("SELECT * FROM t_user e " +
|
||||||
"right join t_role e1 on e1.id = e.id " +
|
"right join t_role e1 on e1.id = e.id " +
|
||||||
"WHERE (e.id = ? OR e.name = ?)",
|
"WHERE (e.id = ? OR e.name = ?)",
|
||||||
"SELECT * FROM t_user e " +
|
"SELECT * FROM t_user e " +
|
||||||
"RIGHT JOIN t_role e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
"RIGHT JOIN t_role e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) " +
|
||||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)");
|
"WHERE (e.id = ? OR e.name = ?) AND e1.tenant_id = 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -348,23 +512,22 @@ public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest
|
||||||
"inner join entity1 e1 on e1.id = e.id " +
|
"inner join entity1 e1 on e1.id = e.id " +
|
||||||
"WHERE e.id = ? OR e.name = ?",
|
"WHERE e.id = ? OR e.name = ?",
|
||||||
"SELECT * FROM t_user e " +
|
"SELECT * FROM t_user e " +
|
||||||
"INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
"INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) AND e1.tenant_id = 1 " +
|
||||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)");
|
"WHERE e.id = ? OR e.name = ?");
|
||||||
|
|
||||||
// 条件 e.id = ? OR e.name = ? 带括号
|
// 条件 e.id = ? OR e.name = ? 带括号
|
||||||
assertSql("SELECT * FROM t_user e " +
|
assertSql("SELECT * FROM t_user e " +
|
||||||
"inner join t_role e1 on e1.id = e.id " +
|
"inner join entity1 e1 on e1.id = e.id " +
|
||||||
"WHERE (e.id = ? OR e.name = ?)",
|
"WHERE (e.id = ? OR e.name = ?)",
|
||||||
"SELECT * FROM t_user e " +
|
"SELECT * FROM t_user e " +
|
||||||
"INNER JOIN t_role e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
"INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) AND e1.tenant_id = 1 " +
|
||||||
"WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)");
|
"WHERE (e.id = ? OR e.name = ?)");
|
||||||
|
|
||||||
// 垃圾 inner join todo
|
// 没有 On 的 inner join
|
||||||
// assertSql("SELECT * FROM entity,entity1 " +
|
assertSql("SELECT * FROM entity,entity1 " +
|
||||||
// "WHERE entity.id = entity1.id",
|
"WHERE entity.id = entity1.id",
|
||||||
// "SELECT * FROM entity e " +
|
"SELECT * FROM entity, entity1 " +
|
||||||
// "INNER JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " +
|
"WHERE entity.id = entity1.id AND entity.tenant_id = 1 AND entity1.tenant_id = 1");
|
||||||
// "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,12 @@ package cn.iocoder.yudao.framework.datapermission.core.rule.dept;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
|
||||||
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
|
|
||||||
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
|
|
||||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
||||||
|
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
|
||||||
import net.sf.jsqlparser.expression.Alias;
|
import net.sf.jsqlparser.expression.Alias;
|
||||||
import net.sf.jsqlparser.expression.Expression;
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
@ -25,6 +24,7 @@ import static cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataP
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.ArgumentMatchers.same;
|
import static org.mockito.ArgumentMatchers.same;
|
||||||
import static org.mockito.Mockito.mockStatic;
|
import static org.mockito.Mockito.mockStatic;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
@ -75,6 +75,8 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
|
||||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
|
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
|
||||||
.setUserType(UserTypeEnum.ADMIN.getValue()));
|
.setUserType(UserTypeEnum.ADMIN.getValue()));
|
||||||
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
|
||||||
|
// mock 方法(permissionApi 返回 null)
|
||||||
|
when(permissionApi.getDeptDataPermission(eq(loginUser.getId()))).thenReturn(success(null));
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
NullPointerException exception = assertThrows(NullPointerException.class,
|
NullPointerException exception = assertThrows(NullPointerException.class,
|
||||||
|
|
|
@ -10,7 +10,7 @@ import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,7 +41,7 @@ public class ErrorCodeLoaderImpl implements ErrorCodeLoader {
|
||||||
/**
|
/**
|
||||||
* 缓存错误码的最大更新时间,用于后续的增量轮询,判断是否有更新
|
* 缓存错误码的最大更新时间,用于后续的增量轮询,判断是否有更新
|
||||||
*/
|
*/
|
||||||
private Date maxUpdateTime;
|
private LocalDateTime maxUpdateTime;
|
||||||
|
|
||||||
@EventListener(ApplicationReadyEvent.class)
|
@EventListener(ApplicationReadyEvent.class)
|
||||||
public void loadErrorCodes() {
|
public void loadErrorCodes() {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cn.iocoder.yudao.framework.operatelog.core.aop;
|
package cn.iocoder.yudao.framework.operatelog.core.aop;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.hutool.core.exceptions.ExceptionUtil;
|
import cn.hutool.core.exceptions.ExceptionUtil;
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
@ -32,6 +33,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
@ -94,7 +96,7 @@ public class OperateLogAspect {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 记录开始时间
|
// 记录开始时间
|
||||||
Date startTime = new Date();
|
LocalDateTime startTime = LocalDateTime.now();
|
||||||
try {
|
try {
|
||||||
// 执行原有方法
|
// 执行原有方法
|
||||||
Object result = joinPoint.proceed();
|
Object result = joinPoint.proceed();
|
||||||
|
@ -128,7 +130,7 @@ public class OperateLogAspect {
|
||||||
private void log(ProceedingJoinPoint joinPoint,
|
private void log(ProceedingJoinPoint joinPoint,
|
||||||
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
|
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
|
||||||
ApiOperation apiOperation,
|
ApiOperation apiOperation,
|
||||||
Date startTime, Object result, Throwable exception) {
|
LocalDateTime startTime, Object result, Throwable exception) {
|
||||||
try {
|
try {
|
||||||
// 判断不记录的情况
|
// 判断不记录的情况
|
||||||
if (!isLogEnable(joinPoint, operateLog)) {
|
if (!isLogEnable(joinPoint, operateLog)) {
|
||||||
|
@ -145,7 +147,7 @@ public class OperateLogAspect {
|
||||||
private void log0(ProceedingJoinPoint joinPoint,
|
private void log0(ProceedingJoinPoint joinPoint,
|
||||||
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
|
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
|
||||||
ApiOperation apiOperation,
|
ApiOperation apiOperation,
|
||||||
Date startTime, Object result, Throwable exception) {
|
LocalDateTime startTime, Object result, Throwable exception) {
|
||||||
OperateLog operateLogObj = new OperateLog();
|
OperateLog operateLogObj = new OperateLog();
|
||||||
// 补全通用字段
|
// 补全通用字段
|
||||||
operateLogObj.setTraceId(TracerUtils.getTraceId());
|
operateLogObj.setTraceId(TracerUtils.getTraceId());
|
||||||
|
@ -226,7 +228,7 @@ public class OperateLogAspect {
|
||||||
private static void fillMethodFields(OperateLog operateLogObj,
|
private static void fillMethodFields(OperateLog operateLogObj,
|
||||||
ProceedingJoinPoint joinPoint,
|
ProceedingJoinPoint joinPoint,
|
||||||
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
|
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
|
||||||
Date startTime, Object result, Throwable exception) {
|
LocalDateTime startTime, Object result, Throwable exception) {
|
||||||
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
|
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
|
||||||
operateLogObj.setJavaMethod(methodSignature.toString());
|
operateLogObj.setJavaMethod(methodSignature.toString());
|
||||||
if (operateLog == null || operateLog.logArgs()) {
|
if (operateLog == null || operateLog.logArgs()) {
|
||||||
|
@ -235,7 +237,7 @@ public class OperateLogAspect {
|
||||||
if (operateLog == null || operateLog.logResultData()) {
|
if (operateLog == null || operateLog.logResultData()) {
|
||||||
operateLogObj.setResultData(obtainResultData(result));
|
operateLogObj.setResultData(obtainResultData(result));
|
||||||
}
|
}
|
||||||
operateLogObj.setDuration((int) (System.currentTimeMillis() - startTime.getTime()));
|
operateLogObj.setDuration((int) (LocalDateTimeUtil.between(startTime, LocalDateTime.now()).toMillis()));
|
||||||
// (正常)处理 resultCode 和 resultMsg 字段
|
// (正常)处理 resultCode 和 resultMsg 字段
|
||||||
if (result instanceof CommonResult) {
|
if (result instanceof CommonResult) {
|
||||||
CommonResult<?> commonResult = (CommonResult<?>) result;
|
CommonResult<?> commonResult = (CommonResult<?>) result;
|
||||||
|
|
|
@ -2,7 +2,7 @@ package cn.iocoder.yudao.framework.operatelog.core.service;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -85,7 +85,7 @@ public class OperateLog {
|
||||||
/**
|
/**
|
||||||
* 开始时间
|
* 开始时间
|
||||||
*/
|
*/
|
||||||
private Date startTime;
|
private LocalDateTime startTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行时长,单位:毫秒
|
* 执行时长,单位:毫秒
|
||||||
|
|
|
@ -5,7 +5,7 @@ import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付通知 Response DTO
|
* 支付通知 Response DTO
|
||||||
|
@ -33,7 +33,7 @@ public class PayOrderNotifyRespDTO {
|
||||||
/**
|
/**
|
||||||
* 支付成功时间
|
* 支付成功时间
|
||||||
*/
|
*/
|
||||||
private Date successTime;
|
private LocalDateTime successTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通知的原始数据
|
* 通知的原始数据
|
||||||
|
|
|
@ -7,7 +7,7 @@ import org.hibernate.validator.constraints.URL;
|
||||||
import javax.validation.constraints.DecimalMin;
|
import javax.validation.constraints.DecimalMin;
|
||||||
import javax.validation.constraints.NotEmpty;
|
import javax.validation.constraints.NotEmpty;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,7 +68,7 @@ public class PayOrderUnifiedReqDTO {
|
||||||
* 支付过期时间
|
* 支付过期时间
|
||||||
*/
|
*/
|
||||||
@NotNull(message = "支付过期时间不能为空")
|
@NotNull(message = "支付过期时间不能为空")
|
||||||
private Date expireTime;
|
private LocalDateTime expireTime;
|
||||||
|
|
||||||
// ========== 拓展参数 ==========
|
// ========== 拓展参数 ==========
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,7 +5,7 @@ import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从渠道返回数据中解析得到的支付退款通知的Notify DTO
|
* 从渠道返回数据中解析得到的支付退款通知的Notify DTO
|
||||||
|
@ -57,7 +57,7 @@ public class PayRefundNotifyDTO {
|
||||||
/**
|
/**
|
||||||
* 退款成功时间
|
* 退款成功时间
|
||||||
*/
|
*/
|
||||||
private Date refundSuccessTime;
|
private LocalDateTime refundSuccessTime;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package cn.iocoder.yudao.framework.pay.core.client.dto;
|
package cn.iocoder.yudao.framework.pay.core.client.dto;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRefundRespEnum;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig;
|
import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPcPayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayQrPayClient;
|
import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayQrPayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayWapPayClient;
|
import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayWapPayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXLitePayClient;
|
import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXLitePayClient;
|
||||||
|
@ -69,7 +70,7 @@ public class PayClientFactoryImpl implements PayClientFactory {
|
||||||
case ALIPAY_WAP: return (AbstractPayClient<Config>) new AlipayWapPayClient(channelId, (AlipayPayClientConfig) config);
|
case ALIPAY_WAP: return (AbstractPayClient<Config>) new AlipayWapPayClient(channelId, (AlipayPayClientConfig) config);
|
||||||
case ALIPAY_QR: return (AbstractPayClient<Config>) new AlipayQrPayClient(channelId, (AlipayPayClientConfig) config);
|
case ALIPAY_QR: return (AbstractPayClient<Config>) new AlipayQrPayClient(channelId, (AlipayPayClientConfig) config);
|
||||||
case ALIPAY_APP: return (AbstractPayClient<Config>) new AlipayQrPayClient(channelId, (AlipayPayClientConfig) config);
|
case ALIPAY_APP: return (AbstractPayClient<Config>) new AlipayQrPayClient(channelId, (AlipayPayClientConfig) config);
|
||||||
case ALIPAY_PC: return (AbstractPayClient<Config>) new AlipayQrPayClient(channelId, (AlipayPayClientConfig) config);
|
case ALIPAY_PC: return (AbstractPayClient<Config>) new AlipayPcPayClient(channelId, (AlipayPayClientConfig) config);
|
||||||
}
|
}
|
||||||
// 创建失败,错误日志 + 抛出异常
|
// 创建失败,错误日志 + 抛出异常
|
||||||
log.error("[createPayClient][配置({}) 找不到合适的客户端实现]", config);
|
log.error("[createPayClient][配置({}) 找不到合适的客户端实现]", config);
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
|
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.hutool.http.HttpUtil;
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping;
|
import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
|
import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.*;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.*;
|
||||||
|
@ -61,7 +60,7 @@ public abstract class AbstractAlipayClient extends AbstractPayClient<AlipayPayCl
|
||||||
return PayOrderNotifyRespDTO.builder().orderExtensionNo(params.get("out_trade_no"))
|
return PayOrderNotifyRespDTO.builder().orderExtensionNo(params.get("out_trade_no"))
|
||||||
.channelOrderNo(params.get("trade_no")).channelUserId(params.get("seller_id"))
|
.channelOrderNo(params.get("trade_no")).channelUserId(params.get("seller_id"))
|
||||||
.tradeStatus(params.get("trade_status"))
|
.tradeStatus(params.get("trade_status"))
|
||||||
.successTime(DateUtil.parse(params.get("notify_time"), "yyyy-MM-dd HH:mm:ss"))
|
.successTime(LocalDateTimeUtil.parse(params.get("notify_time"), "yyyy-MM-dd HH:mm:ss"))
|
||||||
.data(data.getBody()).build();
|
.data(data.getBody()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +71,7 @@ public abstract class AbstractAlipayClient extends AbstractPayClient<AlipayPayCl
|
||||||
.tradeNo(params.get("out_trade_no"))
|
.tradeNo(params.get("out_trade_no"))
|
||||||
.reqNo(params.get("out_biz_no"))
|
.reqNo(params.get("out_biz_no"))
|
||||||
.status(PayNotifyRefundStatusEnum.SUCCESS)
|
.status(PayNotifyRefundStatusEnum.SUCCESS)
|
||||||
.refundSuccessTime(DateUtil.parse(params.get("gmt_refund"), "yyyy-MM-dd HH:mm:ss"))
|
.refundSuccessTime(LocalDateTimeUtil.parse(params.get("gmt_refund"), "yyyy-MM-dd HH:mm:ss"))
|
||||||
.build();
|
.build();
|
||||||
return notifyDTO;
|
return notifyDTO;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.alipay.api.AlipayApiException;
|
||||||
|
import com.alipay.api.domain.AlipayTradePagePayModel;
|
||||||
|
import com.alipay.api.request.AlipayTradePagePayRequest;
|
||||||
|
import com.alipay.api.response.AlipayTradePagePayResponse;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付宝【PC网站支付】的 PayClient 实现类
|
||||||
|
* 文档:https://opendocs.alipay.com/open/270/105898
|
||||||
|
*
|
||||||
|
* @author XGD
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class AlipayPcPayClient extends AbstractAlipayClient {
|
||||||
|
|
||||||
|
public AlipayPcPayClient(Long channelId, AlipayPayClientConfig config) {
|
||||||
|
super(channelId, PayChannelEnum.ALIPAY_PC.getCode(), config, new AlipayPayCodeMapping());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PayCommonResult<AlipayTradePagePayResponse> doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
|
||||||
|
// 构建 AlipayTradePagePayModel 请求
|
||||||
|
AlipayTradePagePayModel model = new AlipayTradePagePayModel();
|
||||||
|
// 构建 AlipayTradePagePayRequest
|
||||||
|
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
|
||||||
|
request.setBizModel(model);
|
||||||
|
JSONObject bizContent = new JSONObject();
|
||||||
|
// 参数说明可查看: https://opendocs.alipay.com/open/028r8t?scene=22
|
||||||
|
bizContent.put("out_trade_no", reqDTO.getMerchantOrderId());
|
||||||
|
bizContent.put("total_amount", calculateAmount(reqDTO.getAmount()));
|
||||||
|
bizContent.put("subject", reqDTO.getSubject());
|
||||||
|
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
|
||||||
|
// PC扫码支付的方式:支持前置模式和跳转模式。4: 订单码-可定义宽度的嵌入式二维码
|
||||||
|
bizContent.put("qr_pay_mode", "4");
|
||||||
|
// 自定义二维码宽度
|
||||||
|
bizContent.put("qrcode_width", "150");
|
||||||
|
request.setBizContent(bizContent.toJSONString());
|
||||||
|
request.setNotifyUrl(reqDTO.getNotifyUrl());
|
||||||
|
request.setReturnUrl("");
|
||||||
|
// 执行请求
|
||||||
|
AlipayTradePagePayResponse response;
|
||||||
|
try {
|
||||||
|
response = client.pageExecute(request);
|
||||||
|
} catch (AlipayApiException e) {
|
||||||
|
log.error("[unifiedOrder][request({}) 发起支付失败]", JsonUtils.toJsonString(reqDTO), e);
|
||||||
|
return PayCommonResult.build(e.getErrCode(), e.getErrMsg(), null, codeMapping);
|
||||||
|
}
|
||||||
|
// 响应为表单格式,前端可嵌入响应的页面或关闭当前支付窗口
|
||||||
|
return PayCommonResult.build(StrUtil.blankToDefault(response.getCode(),"10000") ,response.getMsg(), response, codeMapping);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.wx;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
@ -167,7 +168,7 @@ public class WXLitePayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||||
.builder()
|
.builder()
|
||||||
.orderExtensionNo(result.getOutTradeNo())
|
.orderExtensionNo(result.getOutTradeNo())
|
||||||
.channelOrderNo(result.getTradeState())
|
.channelOrderNo(result.getTradeState())
|
||||||
.successTime(DateUtil.parse(result.getSuccessTime(), "yyyy-MM-dd'T'HH:mm:ssXXX"))
|
.successTime(LocalDateTimeUtil.parse(result.getSuccessTime(), "yyyy-MM-dd'T'HH:mm:ssXXX"))
|
||||||
.data(data.getBody())
|
.data(data.getBody())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
@ -181,7 +182,7 @@ public class WXLitePayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||||
.orderExtensionNo(notifyResult.getOutTradeNo())
|
.orderExtensionNo(notifyResult.getOutTradeNo())
|
||||||
.channelOrderNo(notifyResult.getTransactionId())
|
.channelOrderNo(notifyResult.getTransactionId())
|
||||||
.channelUserId(notifyResult.getOpenid())
|
.channelUserId(notifyResult.getOpenid())
|
||||||
.successTime(DateUtil.parse(notifyResult.getTimeEnd(), "yyyyMMddHHmmss"))
|
.successTime(LocalDateTimeUtil.parse(notifyResult.getTimeEnd(), "yyyyMMddHHmmss"))
|
||||||
.data(data.getBody())
|
.data(data.getBody())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.wx;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.util.io.FileUtils;
|
import cn.iocoder.yudao.framework.common.util.io.FileUtils;
|
||||||
|
@ -150,7 +151,7 @@ public class WXNativePayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||||
.builder()
|
.builder()
|
||||||
.orderExtensionNo(result.getOutTradeNo())
|
.orderExtensionNo(result.getOutTradeNo())
|
||||||
.channelOrderNo(result.getTradeState())
|
.channelOrderNo(result.getTradeState())
|
||||||
.successTime(DateUtil.parse(result.getSuccessTime(), "yyyy-MM-dd'T'HH:mm:ssXXX"))
|
.successTime(LocalDateTimeUtil.parse(result.getSuccessTime(), "yyyy-MM-dd'T'HH:mm:ssXXX"))
|
||||||
.data(data.getBody())
|
.data(data.getBody())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
@ -164,7 +165,7 @@ public class WXNativePayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||||
.orderExtensionNo(notifyResult.getOutTradeNo())
|
.orderExtensionNo(notifyResult.getOutTradeNo())
|
||||||
.channelOrderNo(notifyResult.getTransactionId())
|
.channelOrderNo(notifyResult.getTransactionId())
|
||||||
.channelUserId(notifyResult.getOpenid())
|
.channelUserId(notifyResult.getOpenid())
|
||||||
.successTime(DateUtil.parse(notifyResult.getTimeEnd(), "yyyyMMddHHmmss"))
|
.successTime(LocalDateTimeUtil.parse(notifyResult.getTimeEnd(), "yyyyMMddHHmmss"))
|
||||||
.data(data.getBody())
|
.data(data.getBody())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.wx;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
@ -161,7 +162,7 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||||
.builder()
|
.builder()
|
||||||
.orderExtensionNo(result.getOutTradeNo())
|
.orderExtensionNo(result.getOutTradeNo())
|
||||||
.channelOrderNo(result.getTradeState())
|
.channelOrderNo(result.getTradeState())
|
||||||
.successTime(DateUtil.parse(result.getSuccessTime(), "yyyy-MM-dd'T'HH:mm:ssXXX"))
|
.successTime(LocalDateTimeUtil.parse(result.getSuccessTime(), "yyyy-MM-dd'T'HH:mm:ssXXX"))
|
||||||
.data(data.getBody())
|
.data(data.getBody())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
@ -175,7 +176,7 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||||
.orderExtensionNo(notifyResult.getOutTradeNo())
|
.orderExtensionNo(notifyResult.getOutTradeNo())
|
||||||
.channelOrderNo(notifyResult.getTransactionId())
|
.channelOrderNo(notifyResult.getTransactionId())
|
||||||
.channelUserId(notifyResult.getOpenid())
|
.channelUserId(notifyResult.getOpenid())
|
||||||
.successTime(DateUtil.parse(notifyResult.getTimeEnd(), "yyyyMMddHHmmss"))
|
.successTime(LocalDateTimeUtil.parse(notifyResult.getTimeEnd(), "yyyyMMddHHmmss"))
|
||||||
.data(data.getBody())
|
.data(data.getBody())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ package cn.iocoder.yudao.framework.sms.core.client.dto;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息接收 Response DTO
|
* 消息接收 Response DTO
|
||||||
|
@ -32,7 +32,7 @@ public class SmsReceiveRespDTO {
|
||||||
/**
|
/**
|
||||||
* 用户接收时间
|
* 用户接收时间
|
||||||
*/
|
*/
|
||||||
private Date receiveTime;
|
private LocalDateTime receiveTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 短信 API 发送返回的序号
|
* 短信 API 发送返回的序号
|
||||||
|
|
|
@ -4,6 +4,8 @@ import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||||
|
@ -11,8 +13,6 @@ import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient;
|
import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient;
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
|
||||||
import com.aliyuncs.AcsRequest;
|
import com.aliyuncs.AcsRequest;
|
||||||
import com.aliyuncs.AcsResponse;
|
import com.aliyuncs.AcsResponse;
|
||||||
import com.aliyuncs.DefaultAcsClient;
|
import com.aliyuncs.DefaultAcsClient;
|
||||||
|
@ -28,7 +28,7 @@ import com.google.common.annotations.VisibleForTesting;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
@ -166,13 +166,13 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||||
*/
|
*/
|
||||||
@JsonProperty("send_time")
|
@JsonProperty("send_time")
|
||||||
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
|
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
|
||||||
private Date sendTime;
|
private LocalDateTime sendTime;
|
||||||
/**
|
/**
|
||||||
* 状态报告时间
|
* 状态报告时间
|
||||||
*/
|
*/
|
||||||
@JsonProperty("report_time")
|
@JsonProperty("report_time")
|
||||||
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
|
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
|
||||||
private Date reportTime;
|
private LocalDateTime reportTime;
|
||||||
/**
|
/**
|
||||||
* 是否接收成功
|
* 是否接收成功
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -22,7 +22,7 @@ import com.tencentcloudapi.sms.v20210111.SmsClient;
|
||||||
import com.tencentcloudapi.sms.v20210111.models.*;
|
import com.tencentcloudapi.sms.v20210111.models.*;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
@ -240,7 +240,7 @@ public class TencentSmsClient extends AbstractSmsClient {
|
||||||
*/
|
*/
|
||||||
@JsonProperty("user_receive_time")
|
@JsonProperty("user_receive_time")
|
||||||
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
|
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
|
||||||
private Date receiveTime;
|
private LocalDateTime receiveTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 国家(或地区)码
|
* 国家(或地区)码
|
||||||
|
|
|
@ -5,6 +5,7 @@ import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.core.util.URLUtil;
|
import cn.hutool.core.util.URLUtil;
|
||||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||||
|
@ -12,7 +13,6 @@ import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient;
|
import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient;
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
@ -23,6 +23,7 @@ import com.yunpian.sdk.model.Template;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
@ -198,7 +199,7 @@ public class YunpianSmsClient extends AbstractSmsClient {
|
||||||
*/
|
*/
|
||||||
@JsonProperty("user_receive_time")
|
@JsonProperty("user_receive_time")
|
||||||
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
|
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
|
||||||
private Date userReceiveTime;
|
private LocalDateTime userReceiveTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
|
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
|
||||||
import com.aliyuncs.AcsRequest;
|
import com.aliyuncs.AcsRequest;
|
||||||
import com.aliyuncs.IAcsClient;
|
import com.aliyuncs.IAcsClient;
|
||||||
|
@ -27,6 +26,7 @@ import org.mockito.ArgumentMatcher;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
|
||||||
assertEquals("DELIVERED", statuses.get(0).getErrorCode());
|
assertEquals("DELIVERED", statuses.get(0).getErrorCode());
|
||||||
assertEquals("用户接收成功", statuses.get(0).getErrorMsg());
|
assertEquals("用户接收成功", statuses.get(0).getErrorMsg());
|
||||||
assertEquals("13900000001", statuses.get(0).getMobile());
|
assertEquals("13900000001", statuses.get(0).getMobile());
|
||||||
assertEquals(DateUtils.buildTime(2017, 2, 2, 22, 23, 24), statuses.get(0).getReceiveTime());
|
assertEquals(LocalDateTime.of(2017, 2, 2, 22, 23, 24), statuses.get(0).getReceiveTime());
|
||||||
assertEquals("12345", statuses.get(0).getSerialNo());
|
assertEquals("12345", statuses.get(0).getSerialNo());
|
||||||
assertEquals(67890L, statuses.get(0).getLogId());
|
assertEquals(67890L, statuses.get(0).getLogId());
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
|
||||||
when(client.getAcsResponse(any(AcsRequest.class))).thenThrow(ex);
|
when(client.getAcsResponse(any(AcsRequest.class))).thenThrow(ex);
|
||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
SmsCommonResult<?> result = smsClient.invoke(request,null);
|
SmsCommonResult<?> result = smsClient.invoke(request, null);
|
||||||
// 断言
|
// 断言
|
||||||
assertEquals(ex.getErrCode(), result.getApiCode());
|
assertEquals(ex.getErrCode(), result.getApiCode());
|
||||||
assertEquals(ex.getErrMsg(), result.getApiMsg());
|
assertEquals(ex.getErrMsg(), result.getApiMsg());
|
||||||
|
|
|
@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||||
|
@ -25,6 +24,7 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
|
||||||
assertEquals("DELIVRD", statuses.get(0).getErrorCode());
|
assertEquals("DELIVRD", statuses.get(0).getErrorCode());
|
||||||
assertEquals("用户短信送达成功", statuses.get(0).getErrorMsg());
|
assertEquals("用户短信送达成功", statuses.get(0).getErrorMsg());
|
||||||
assertEquals("13900000001", statuses.get(0).getMobile());
|
assertEquals("13900000001", statuses.get(0).getMobile());
|
||||||
assertEquals(DateUtils.buildTime(2015, 10, 17, 8, 3, 4), statuses.get(0).getReceiveTime());
|
assertEquals(LocalDateTime.of(2015, 10, 17, 8, 3, 4), statuses.get(0).getReceiveTime());
|
||||||
assertEquals("12345", statuses.get(0).getSerialNo());
|
assertEquals("12345", statuses.get(0).getSerialNo());
|
||||||
assertEquals(67890L, statuses.get(0).getLogId());
|
assertEquals(67890L, statuses.get(0).getLogId());
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
||||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.yunpian.sdk.YunpianClient;
|
import com.yunpian.sdk.YunpianClient;
|
||||||
import com.yunpian.sdk.api.SmsApi;
|
import com.yunpian.sdk.api.SmsApi;
|
||||||
|
@ -23,6 +22,7 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -115,7 +115,7 @@ public class YunpianSmsClientTest extends BaseMockitoUnitTest {
|
||||||
assertEquals("", statuses.get(0).getErrorCode());
|
assertEquals("", statuses.get(0).getErrorCode());
|
||||||
assertNull(statuses.get(0).getErrorMsg());
|
assertNull(statuses.get(0).getErrorMsg());
|
||||||
assertEquals("15205201314", statuses.get(0).getMobile());
|
assertEquals("15205201314", statuses.get(0).getMobile());
|
||||||
assertEquals(DateUtils.buildTime(2014, 3, 17, 22, 55, 21), statuses.get(0).getReceiveTime());
|
assertEquals(LocalDateTime.of(2014, 3, 17, 22, 55, 21), statuses.get(0).getReceiveTime());
|
||||||
assertEquals("9527", statuses.get(0).getSerialNo());
|
assertEquals("9527", statuses.get(0).getSerialNo());
|
||||||
assertEquals(1024L, statuses.get(0).getLogId());
|
assertEquals(1024L, statuses.get(0).getLogId());
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor;
|
||||||
import cn.iocoder.yudao.framework.tenant.core.job.TenantJobAspect;
|
import cn.iocoder.yudao.framework.tenant.core.job.TenantJobAspect;
|
||||||
import cn.iocoder.yudao.framework.tenant.core.mq.TenantChannelInterceptor;
|
import cn.iocoder.yudao.framework.tenant.core.mq.TenantChannelInterceptor;
|
||||||
import cn.iocoder.yudao.framework.tenant.core.mq.TenantFunctionAroundWrapper;
|
import cn.iocoder.yudao.framework.tenant.core.mq.TenantFunctionAroundWrapper;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.redis.TenantRedisCacheManager;
|
||||||
import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter;
|
import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter;
|
||||||
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
|
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
|
||||||
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkServiceImpl;
|
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkServiceImpl;
|
||||||
|
@ -25,8 +26,16 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
import org.springframework.cloud.function.context.catalog.FunctionAroundWrapper;
|
import org.springframework.cloud.function.context.catalog.FunctionAroundWrapper;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||||
|
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||||
|
import org.springframework.data.redis.cache.RedisCacheWriter;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.integration.config.GlobalChannelInterceptor;
|
import org.springframework.integration.config.GlobalChannelInterceptor;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true) // 允许使用 yudao.tenant.enable=false 禁用多租户
|
@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true) // 允许使用 yudao.tenant.enable=false 禁用多租户
|
||||||
@EnableConfigurationProperties(TenantProperties.class)
|
@EnableConfigurationProperties(TenantProperties.class)
|
||||||
|
@ -122,4 +131,17 @@ public class YudaoTenantAutoConfiguration {
|
||||||
return new TenantJobAspect(tenantFrameworkService);
|
return new TenantJobAspect(tenantFrameworkService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== Redis ==========
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Primary // 引入租户时,tenantRedisCacheManager 为主 Bean
|
||||||
|
public RedisCacheManager tenantRedisCacheManager(RedisTemplate<String, Object> redisTemplate,
|
||||||
|
RedisCacheConfiguration redisCacheConfiguration) {
|
||||||
|
// 创建 RedisCacheWriter 对象
|
||||||
|
RedisConnectionFactory connectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory());
|
||||||
|
RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
|
||||||
|
// 创建 TenantRedisCacheManager 对象
|
||||||
|
return new TenantRedisCacheManager(cacheWriter, redisCacheConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cn.iocoder.yudao.framework.tenant.core.context;
|
package cn.iocoder.yudao.framework.tenant.core.context;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.enums.DocumentEnum;
|
||||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,7 +37,8 @@ public class TenantContextHolder {
|
||||||
public static Long getRequiredTenantId() {
|
public static Long getRequiredTenantId() {
|
||||||
Long tenantId = getTenantId();
|
Long tenantId = getTenantId();
|
||||||
if (tenantId == null) {
|
if (tenantId == null) {
|
||||||
throw new NullPointerException("TenantContextHolder 不存在租户编号"); // TODO 芋艿:增加文档链接
|
throw new NullPointerException("TenantContextHolder 不存在租户编号!可参考文档:"
|
||||||
|
+ DocumentEnum.TENANT.getUrl());
|
||||||
}
|
}
|
||||||
return tenantId;
|
return tenantId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package cn.iocoder.yudao.framework.tenant.core.redis;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.cache.Cache;
|
||||||
|
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||||
|
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||||
|
import org.springframework.data.redis.cache.RedisCacheWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多租户的 {@link RedisCacheManager} 实现类
|
||||||
|
*
|
||||||
|
* 操作指定 name 的 {@link Cache} 时,自动拼接租户后缀,格式为 name + ":" + tenantId + 后缀
|
||||||
|
*
|
||||||
|
* @author airhead
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class TenantRedisCacheManager extends RedisCacheManager {
|
||||||
|
|
||||||
|
public TenantRedisCacheManager(RedisCacheWriter cacheWriter,
|
||||||
|
RedisCacheConfiguration defaultCacheConfiguration) {
|
||||||
|
super(cacheWriter, defaultCacheConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cache getCache(String name) {
|
||||||
|
// 如果开启多租户,则 name 拼接租户后缀
|
||||||
|
if (!TenantContextHolder.isIgnore()
|
||||||
|
&& TenantContextHolder.getTenantId() != null) {
|
||||||
|
name = name + ":" + TenantContextHolder.getTenantId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 继续基于父方法
|
||||||
|
return super.getCache(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
|
||||||
import cn.iocoder.yudao.framework.web.config.WebProperties;
|
import cn.iocoder.yudao.framework.web.config.WebProperties;
|
||||||
import cn.iocoder.yudao.framework.web.core.filter.ApiRequestFilter;
|
import cn.iocoder.yudao.framework.web.core.filter.ApiRequestFilter;
|
||||||
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
||||||
|
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.util.AntPathMatcher;
|
import org.springframework.util.AntPathMatcher;
|
||||||
|
|
||||||
|
@ -65,6 +66,7 @@ public class TenantSecurityWebFilter extends ApiRequestFilter {
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
Long tenantId = TenantContextHolder.getTenantId();
|
Long tenantId = TenantContextHolder.getTenantId();
|
||||||
|
boolean isRpcRequest = !WebFrameworkUtils.isRpcRequest(request);
|
||||||
// 1. 登陆的用户,校验是否有权限访问该租户,避免越权问题。
|
// 1. 登陆的用户,校验是否有权限访问该租户,避免越权问题。
|
||||||
LoginUser user = SecurityFrameworkUtils.getLoginUser();
|
LoginUser user = SecurityFrameworkUtils.getLoginUser();
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
|
@ -73,7 +75,8 @@ public class TenantSecurityWebFilter extends ApiRequestFilter {
|
||||||
tenantId = user.getTenantId();
|
tenantId = user.getTenantId();
|
||||||
TenantContextHolder.setTenantId(tenantId);
|
TenantContextHolder.setTenantId(tenantId);
|
||||||
// 如果传递了租户编号,则进行比对租户编号,避免越权问题
|
// 如果传递了租户编号,则进行比对租户编号,避免越权问题
|
||||||
} else if (!Objects.equals(user.getTenantId(), TenantContextHolder.getTenantId())) {
|
} else if (!Objects.equals(user.getTenantId(), TenantContextHolder.getTenantId())
|
||||||
|
&& !isRpcRequest) { // Cloud 特殊逻辑:如果是 RPC 请求,就不校验了。主要考虑,一些场景下,会调用 TenantUtils 去切换租户
|
||||||
log.error("[doFilterInternal][租户({}) User({}/{}) 越权访问租户({}) URL({}/{})]",
|
log.error("[doFilterInternal][租户({}) User({}/{}) 越权访问租户({}) URL({}/{})]",
|
||||||
user.getTenantId(), user.getId(), user.getUserType(),
|
user.getTenantId(), user.getId(), user.getUserType(),
|
||||||
TenantContextHolder.getTenantId(), request.getRequestURI(), request.getMethod());
|
TenantContextHolder.getTenantId(), request.getRequestURI(), request.getMethod());
|
||||||
|
|
|
@ -5,8 +5,9 @@ import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
|
||||||
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||||
import com.alibaba.excel.converters.Converter;
|
import com.alibaba.excel.converters.Converter;
|
||||||
import com.alibaba.excel.enums.CellDataTypeEnum;
|
import com.alibaba.excel.enums.CellDataTypeEnum;
|
||||||
import com.alibaba.excel.metadata.CellData;
|
|
||||||
import com.alibaba.excel.metadata.GlobalConfiguration;
|
import com.alibaba.excel.metadata.GlobalConfiguration;
|
||||||
|
import com.alibaba.excel.metadata.data.ReadCellData;
|
||||||
|
import com.alibaba.excel.metadata.data.WriteCellData;
|
||||||
import com.alibaba.excel.metadata.property.ExcelContentProperty;
|
import com.alibaba.excel.metadata.property.ExcelContentProperty;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@ -29,11 +30,11 @@ public class DictConvert implements Converter<Object> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
|
public Object convertToJavaData(ReadCellData readCellData, ExcelContentProperty contentProperty,
|
||||||
GlobalConfiguration globalConfiguration) {
|
GlobalConfiguration globalConfiguration) {
|
||||||
// 使用字典解析
|
// 使用字典解析
|
||||||
String type = getType(contentProperty);
|
String type = getType(contentProperty);
|
||||||
String label = cellData.getStringValue();
|
String label = readCellData.getStringValue();
|
||||||
String value = DictFrameworkUtils.parseDictDataValue(type, label);
|
String value = DictFrameworkUtils.parseDictDataValue(type, label);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
log.error("[convertToJavaData][type({}) 解析不掉 label({})]", type, label);
|
log.error("[convertToJavaData][type({}) 解析不掉 label({})]", type, label);
|
||||||
|
@ -45,11 +46,11 @@ public class DictConvert implements Converter<Object> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CellData<String> convertToExcelData(Object object, ExcelContentProperty contentProperty,
|
public WriteCellData<String> convertToExcelData(Object object, ExcelContentProperty contentProperty,
|
||||||
GlobalConfiguration globalConfiguration) {
|
GlobalConfiguration globalConfiguration) {
|
||||||
// 空时,返回空
|
// 空时,返回空
|
||||||
if (object == null) {
|
if (object == null) {
|
||||||
return new CellData<>("");
|
return new WriteCellData<>("");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用字典格式化
|
// 使用字典格式化
|
||||||
|
@ -58,10 +59,10 @@ public class DictConvert implements Converter<Object> {
|
||||||
String label = DictFrameworkUtils.getDictDataLabel(type, value);
|
String label = DictFrameworkUtils.getDictDataLabel(type, value);
|
||||||
if (label == null) {
|
if (label == null) {
|
||||||
log.error("[convertToExcelData][type({}) 转换不了 label({})]", type, value);
|
log.error("[convertToExcelData][type({}) 转换不了 label({})]", type, value);
|
||||||
return new CellData<>("");
|
return new WriteCellData<>("");
|
||||||
}
|
}
|
||||||
// 生成 Excel 小表格
|
// 生成 Excel 小表格
|
||||||
return new CellData<>(label);
|
return new WriteCellData<>(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getType(ExcelContentProperty contentProperty) {
|
private static String getType(ExcelContentProperty contentProperty) {
|
||||||
|
|
|
@ -3,8 +3,8 @@ package cn.iocoder.yudao.framework.excel.core.convert;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import com.alibaba.excel.converters.Converter;
|
import com.alibaba.excel.converters.Converter;
|
||||||
import com.alibaba.excel.enums.CellDataTypeEnum;
|
import com.alibaba.excel.enums.CellDataTypeEnum;
|
||||||
import com.alibaba.excel.metadata.CellData;
|
|
||||||
import com.alibaba.excel.metadata.GlobalConfiguration;
|
import com.alibaba.excel.metadata.GlobalConfiguration;
|
||||||
|
import com.alibaba.excel.metadata.data.WriteCellData;
|
||||||
import com.alibaba.excel.metadata.property.ExcelContentProperty;
|
import com.alibaba.excel.metadata.property.ExcelContentProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,15 +25,10 @@ public class JsonConvert implements Converter<Object> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
|
public WriteCellData<String> convertToExcelData(Object value, ExcelContentProperty contentProperty,
|
||||||
throw new UnsupportedOperationException("暂不支持,也不需要");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CellData<String> convertToExcelData(Object value, ExcelContentProperty contentProperty,
|
|
||||||
GlobalConfiguration globalConfiguration) {
|
GlobalConfiguration globalConfiguration) {
|
||||||
// 生成 Excel 小表格
|
// 生成 Excel 小表格
|
||||||
return new CellData<>(JsonUtils.toJsonString(value));
|
return new WriteCellData<>(JsonUtils.toJsonString(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import lombok.Data;
|
||||||
import org.apache.ibatis.type.JdbcType;
|
import org.apache.ibatis.type.JdbcType;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基础实体对象
|
* 基础实体对象
|
||||||
|
@ -21,12 +21,12 @@ public abstract class BaseDO implements Serializable {
|
||||||
* 创建时间
|
* 创建时间
|
||||||
*/
|
*/
|
||||||
@TableField(fill = FieldFill.INSERT)
|
@TableField(fill = FieldFill.INSERT)
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
/**
|
/**
|
||||||
* 最后更新时间
|
* 最后更新时间
|
||||||
*/
|
*/
|
||||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
/**
|
/**
|
||||||
* 创建者,目前使用 SysUser 的 id 编号
|
* 创建者,目前使用 SysUser 的 id 编号
|
||||||
*
|
*
|
||||||
|
|
|
@ -5,7 +5,7 @@ import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||||
import org.apache.ibatis.reflection.MetaObject;
|
import org.apache.ibatis.reflection.MetaObject;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,7 +22,7 @@ public class DefaultDBFieldHandler implements MetaObjectHandler {
|
||||||
if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) {
|
if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) {
|
||||||
BaseDO baseDO = (BaseDO) metaObject.getOriginalObject();
|
BaseDO baseDO = (BaseDO) metaObject.getOriginalObject();
|
||||||
|
|
||||||
Date current = new Date();
|
LocalDateTime current = LocalDateTime.now();
|
||||||
// 创建时间为空,则以当前时间为插入时间
|
// 创建时间为空,则以当前时间为插入时间
|
||||||
if (Objects.isNull(baseDO.getCreateTime())) {
|
if (Objects.isNull(baseDO.getCreateTime())) {
|
||||||
baseDO.setCreateTime(current);
|
baseDO.setCreateTime(current);
|
||||||
|
@ -49,7 +49,7 @@ public class DefaultDBFieldHandler implements MetaObjectHandler {
|
||||||
// 更新时间为空,则以当前时间为更新时间
|
// 更新时间为空,则以当前时间为更新时间
|
||||||
Object modifyTime = getFieldValByName("updateTime", metaObject);
|
Object modifyTime = getFieldValByName("updateTime", metaObject);
|
||||||
if (Objects.isNull(modifyTime)) {
|
if (Objects.isNull(modifyTime)) {
|
||||||
setFieldValByName("updateTime", new Date(), metaObject);
|
setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 当前登录用户不为空,更新人为空,则当前登录用户为更新人
|
// 当前登录用户不为空,更新人为空,则当前登录用户为更新人
|
||||||
|
|
|
@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.SortingField;
|
import cn.iocoder.yudao.framework.common.pojo.SortingField;
|
||||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.StringPool;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
@ -78,7 +79,10 @@ public class MyBatisUtils {
|
||||||
* @return Column 对象
|
* @return Column 对象
|
||||||
*/
|
*/
|
||||||
public static Column buildColumn(String tableName, Alias tableAlias, String column) {
|
public static Column buildColumn(String tableName, Alias tableAlias, String column) {
|
||||||
return new Column(tableAlias != null ? tableAlias.getName() + "." + column : column);
|
if (tableAlias != null) {
|
||||||
|
tableName = tableAlias.getName();
|
||||||
|
}
|
||||||
|
return new Column(tableName + StringPool.DOT + column);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstant
|
||||||
import com.baomidou.lock.LockFailureStrategy;
|
import com.baomidou.lock.LockFailureStrategy;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义获取锁失败策略,抛出 {@link ServiceException} 异常
|
* 自定义获取锁失败策略,抛出 {@link ServiceException} 异常
|
||||||
*/
|
*/
|
||||||
|
@ -12,9 +14,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
public class DefaultLockFailureStrategy implements LockFailureStrategy {
|
public class DefaultLockFailureStrategy implements LockFailureStrategy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLockFailure(String key, long acquireTimeout, int acquireCount) {
|
public void onLockFailure(String key, Method method, Object[] arguments) {
|
||||||
log.debug("[onLockFailure][线程:{} 获取锁失败,key:{} 获取超时时长:{} ms]", Thread.currentThread().getName(), key, acquireTimeout);
|
log.debug("[onLockFailure][线程:{} 获取锁失败,key:{} 获取失败:{} ]", Thread.currentThread().getName(), key, arguments);
|
||||||
throw new ServiceException(GlobalErrorCodeConstants.LOCKED);
|
throw new ServiceException(GlobalErrorCodeConstants.LOCKED);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,10 @@
|
||||||
<artifactId>spring-boot-starter-cache</artifactId> <!-- 实现对 Caches 的自动化配置 -->
|
<artifactId>spring-boot-starter-cache</artifactId> <!-- 实现对 Caches 的自动化配置 -->
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-all</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package cn.iocoder.yudao.framework.redis.config;
|
package cn.iocoder.yudao.framework.redis.config;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.cache.CacheProperties;
|
import org.springframework.boot.autoconfigure.cache.CacheProperties;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.cache.annotation.EnableCaching;
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
@ -13,6 +14,7 @@ import org.springframework.data.redis.serializer.RedisSerializer;
|
||||||
* Cache 配置类,基于 Redis 实现
|
* Cache 配置类,基于 Redis 实现
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@EnableConfigurationProperties({CacheProperties.class})
|
||||||
@EnableCaching
|
@EnableCaching
|
||||||
public class YudaoCacheAutoConfiguration {
|
public class YudaoCacheAutoConfiguration {
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,6 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
|
||||||
.antMatchers(HttpMethod.DELETE, permitAllUrls.get(HttpMethod.DELETE).toArray(new String[0])).permitAll()
|
.antMatchers(HttpMethod.DELETE, permitAllUrls.get(HttpMethod.DELETE).toArray(new String[0])).permitAll()
|
||||||
// 基于 yudao.security.permit-all-urls 无需认证
|
// 基于 yudao.security.permit-all-urls 无需认证
|
||||||
.antMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll()
|
.antMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll()
|
||||||
.antMatchers("/captcha/get", "/captcha/check").permitAll()
|
|
||||||
// 设置 App API 无需认证
|
// 设置 App API 无需认证
|
||||||
.antMatchers(buildAppApi("/**")).permitAll()
|
.antMatchers(buildAppApi("/**")).permitAll()
|
||||||
// ②:每个项目的自定义规则
|
// ②:每个项目的自定义规则
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cn.iocoder.yudao.framework.test.core.util;
|
package cn.iocoder.yudao.framework.test.core.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.core.util.RandomUtil;
|
import cn.hutool.core.util.RandomUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
@ -8,6 +9,7 @@ import uk.co.jemos.podam.api.PodamFactory;
|
||||||
import uk.co.jemos.podam.api.PodamFactoryImpl;
|
import uk.co.jemos.podam.api.PodamFactoryImpl;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -76,6 +78,10 @@ public class RandomUtils {
|
||||||
return RandomUtil.randomDay(0, RANDOM_DATE_MAX);
|
return RandomUtil.randomDay(0, RANDOM_DATE_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static LocalDateTime randomLocalDateTime() {
|
||||||
|
return LocalDateTimeUtil.of(randomDate());
|
||||||
|
}
|
||||||
|
|
||||||
public static Short randomShort() {
|
public static Short randomShort() {
|
||||||
return (short) RandomUtil.randomInt(0, Short.MAX_VALUE);
|
return (short) RandomUtil.randomInt(0, Short.MAX_VALUE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cn.iocoder.yudao.framework.apilog.core.filter;
|
package cn.iocoder.yudao.framework.apilog.core.filter;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.hutool.core.exceptions.ExceptionUtil;
|
import cn.hutool.core.exceptions.ExceptionUtil;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.extra.servlet.ServletUtil;
|
import cn.hutool.extra.servlet.ServletUtil;
|
||||||
|
@ -7,7 +8,6 @@ import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLog;
|
||||||
import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkService;
|
import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkService;
|
||||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
|
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
||||||
import cn.iocoder.yudao.framework.web.config.WebProperties;
|
import cn.iocoder.yudao.framework.web.config.WebProperties;
|
||||||
|
@ -20,7 +20,8 @@ import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||||
|
@ -47,7 +48,7 @@ public class ApiAccessLogFilter extends ApiRequestFilter {
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
// 获得开始时间
|
// 获得开始时间
|
||||||
Date beginTim = new Date();
|
LocalDateTime beginTime = LocalDateTime.now();
|
||||||
// 提前获得参数,避免 XssFilter 过滤处理
|
// 提前获得参数,避免 XssFilter 过滤处理
|
||||||
Map<String, String> queryString = ServletUtil.getParamMap(request);
|
Map<String, String> queryString = ServletUtil.getParamMap(request);
|
||||||
String requestBody = ServletUtils.isJsonRequest(request) ? ServletUtil.getBody(request) : null;
|
String requestBody = ServletUtils.isJsonRequest(request) ? ServletUtil.getBody(request) : null;
|
||||||
|
@ -56,15 +57,15 @@ public class ApiAccessLogFilter extends ApiRequestFilter {
|
||||||
// 继续过滤器
|
// 继续过滤器
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
// 正常执行,记录日志
|
// 正常执行,记录日志
|
||||||
createApiAccessLog(request, beginTim, queryString, requestBody, null);
|
createApiAccessLog(request, beginTime, queryString, requestBody, null);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
// 异常执行,记录日志
|
// 异常执行,记录日志
|
||||||
createApiAccessLog(request, beginTim, queryString, requestBody, ex);
|
createApiAccessLog(request, beginTime, queryString, requestBody, ex);
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createApiAccessLog(HttpServletRequest request, Date beginTime,
|
private void createApiAccessLog(HttpServletRequest request, LocalDateTime beginTime,
|
||||||
Map<String, String> queryString, String requestBody, Exception ex) {
|
Map<String, String> queryString, String requestBody, Exception ex) {
|
||||||
ApiAccessLog accessLog = new ApiAccessLog();
|
ApiAccessLog accessLog = new ApiAccessLog();
|
||||||
try {
|
try {
|
||||||
|
@ -75,7 +76,7 @@ public class ApiAccessLogFilter extends ApiRequestFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildApiAccessLogDTO(ApiAccessLog accessLog, HttpServletRequest request, Date beginTime,
|
private void buildApiAccessLogDTO(ApiAccessLog accessLog, HttpServletRequest request, LocalDateTime beginTime,
|
||||||
Map<String, String> queryString, String requestBody, Exception ex) {
|
Map<String, String> queryString, String requestBody, Exception ex) {
|
||||||
// 处理用户信息
|
// 处理用户信息
|
||||||
accessLog.setUserId(WebFrameworkUtils.getLoginUserId(request));
|
accessLog.setUserId(WebFrameworkUtils.getLoginUserId(request));
|
||||||
|
@ -103,8 +104,8 @@ public class ApiAccessLogFilter extends ApiRequestFilter {
|
||||||
accessLog.setUserIp(ServletUtil.getClientIP(request));
|
accessLog.setUserIp(ServletUtil.getClientIP(request));
|
||||||
// 持续时间
|
// 持续时间
|
||||||
accessLog.setBeginTime(beginTime);
|
accessLog.setBeginTime(beginTime);
|
||||||
accessLog.setEndTime(new Date());
|
accessLog.setEndTime(LocalDateTime.now());
|
||||||
accessLog.setDuration((int) DateUtils.diff(accessLog.getEndTime(), accessLog.getBeginTime()));
|
accessLog.setDuration((int) LocalDateTimeUtil.between(accessLog.getBeginTime(), accessLog.getEndTime(), ChronoUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ package cn.iocoder.yudao.framework.apilog.core.service;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API 访问日志
|
* API 访问日志
|
||||||
|
@ -61,12 +61,12 @@ public class ApiAccessLog {
|
||||||
* 开始请求时间
|
* 开始请求时间
|
||||||
*/
|
*/
|
||||||
@NotNull(message = "开始请求时间不能为空")
|
@NotNull(message = "开始请求时间不能为空")
|
||||||
private Date beginTime;
|
private LocalDateTime beginTime;
|
||||||
/**
|
/**
|
||||||
* 结束请求时间
|
* 结束请求时间
|
||||||
*/
|
*/
|
||||||
@NotNull(message = "结束请求时间不能为空")
|
@NotNull(message = "结束请求时间不能为空")
|
||||||
private Date endTime;
|
private LocalDateTime endTime;
|
||||||
/**
|
/**
|
||||||
* 执行时长,单位:毫秒
|
* 执行时长,单位:毫秒
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3,7 +3,7 @@ package cn.iocoder.yudao.framework.apilog.core.service;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API 错误日志
|
* API 错误日志
|
||||||
|
@ -61,7 +61,7 @@ public class ApiErrorLog {
|
||||||
* 异常时间
|
* 异常时间
|
||||||
*/
|
*/
|
||||||
@NotNull(message = "异常时间不能为空")
|
@NotNull(message = "异常时间不能为空")
|
||||||
private Date exceptionTime;
|
private LocalDateTime exceptionTime;
|
||||||
/**
|
/**
|
||||||
* 异常名
|
* 异常名
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -30,7 +30,8 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.validation.ConstraintViolation;
|
import javax.validation.ConstraintViolation;
|
||||||
import javax.validation.ConstraintViolationException;
|
import javax.validation.ConstraintViolationException;
|
||||||
import javax.validation.ValidationException;
|
import javax.validation.ValidationException;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.*;
|
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.*;
|
||||||
|
@ -267,7 +268,7 @@ public class GlobalExceptionHandler {
|
||||||
errorLog.setRequestMethod(request.getMethod());
|
errorLog.setRequestMethod(request.getMethod());
|
||||||
errorLog.setUserAgent(ServletUtils.getUserAgent(request));
|
errorLog.setUserAgent(ServletUtils.getUserAgent(request));
|
||||||
errorLog.setUserIp(ServletUtil.getClientIP(request));
|
errorLog.setUserIp(ServletUtil.getClientIP(request));
|
||||||
errorLog.setExceptionTime(new Date());
|
errorLog.setExceptionTime(LocalDateTime.now());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package cn.iocoder.yudao.framework.web.core.util;
|
package cn.iocoder.yudao.framework.web.core.util;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.enums.RpcConstants;
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.web.config.WebProperties;
|
import cn.iocoder.yudao.framework.web.config.WebProperties;
|
||||||
|
@ -124,4 +125,14 @@ public class WebFrameworkUtils {
|
||||||
return servletRequestAttributes.getRequest();
|
return servletRequestAttributes.getRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为 RPC 请求
|
||||||
|
*
|
||||||
|
* @param request 请求
|
||||||
|
* @return 是否为 RPC 请求
|
||||||
|
*/
|
||||||
|
public static boolean isRpcRequest(HttpServletRequest request) {
|
||||||
|
return request.getRequestURI().startsWith(RpcConstants.RPC_API_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,20 @@
|
||||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
|
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.swagger</groupId>
|
||||||
|
<artifactId>swagger-annotations</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- RPC 远程调用相关 -->
|
<!-- RPC 远程调用相关 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
@ -63,19 +77,6 @@
|
||||||
<artifactId>yudao-spring-boot-starter-monitor</artifactId>
|
<artifactId>yudao-spring-boot-starter-monitor</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.xiaoymin</groupId>
|
|
||||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.swagger</groupId>
|
|
||||||
<artifactId>swagger-annotations</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.springfox</groupId>
|
|
||||||
<artifactId>springfox-boot-starter</artifactId>
|
|
||||||
<version>3.0.0</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,7 +88,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
<version>2.6.7</version> <!-- 如果 spring.boot.version 版本修改,则这里也要跟着修改 -->
|
<version>2.6.13</version> <!-- 如果 spring.boot.version 版本修改,则这里也要跟着修改 -->
|
||||||
<configuration>
|
<configuration>
|
||||||
<fork>true</fork>
|
<fork>true</fork>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
|
@ -2,58 +2,10 @@ package cn.iocoder.yudao.gateway;
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
|
||||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
|
||||||
import org.springframework.web.cors.reactive.CorsUtils;
|
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
|
||||||
import org.springframework.web.server.WebFilter;
|
|
||||||
import org.springframework.web.server.WebFilterChain;
|
|
||||||
import reactor.core.publisher.Mono;
|
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class GatewayServerApplication {
|
public class GatewayServerApplication {
|
||||||
|
|
||||||
// ----------------------------- 解决跨域 Begin -----------------------------
|
|
||||||
|
|
||||||
private static final String ALL = "*";
|
|
||||||
private static final String MAX_AGE = "3600L";
|
|
||||||
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public WebFilter corsFilter() {
|
|
||||||
return (ServerWebExchange ctx, WebFilterChain chain) -> {
|
|
||||||
ServerHttpRequest request = ctx.getRequest();
|
|
||||||
if (!CorsUtils.isCorsRequest(request)) {
|
|
||||||
return chain.filter(ctx);
|
|
||||||
}
|
|
||||||
HttpHeaders requestHeaders = request.getHeaders();
|
|
||||||
ServerHttpResponse response = ctx.getResponse();
|
|
||||||
HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
|
|
||||||
HttpHeaders headers = response.getHeaders();
|
|
||||||
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
|
|
||||||
headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());
|
|
||||||
if (requestMethod != null) {
|
|
||||||
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
|
|
||||||
}
|
|
||||||
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
|
|
||||||
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, ALL);
|
|
||||||
headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
|
|
||||||
if (request.getMethod() == HttpMethod.OPTIONS) {
|
|
||||||
response.setStatusCode(HttpStatus.OK);
|
|
||||||
return Mono.empty();
|
|
||||||
}
|
|
||||||
return chain.filter(ctx);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------- 解决跨域 End -----------------------------
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
// 启动 Spring Boot 应用
|
// 启动 Spring Boot 应用
|
||||||
SpringApplication.run(GatewayServerApplication.class, args);
|
SpringApplication.run(GatewayServerApplication.class, args);
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package cn.iocoder.yudao.gateway.filter.cors;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.cors.reactive.CorsUtils;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import org.springframework.web.server.WebFilter;
|
||||||
|
import org.springframework.web.server.WebFilterChain;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跨域 Filter
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class CorsFilter implements WebFilter {
|
||||||
|
|
||||||
|
private static final String ALL = "*";
|
||||||
|
private static final String MAX_AGE = "3600L";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||||
|
// 非跨域请求,直接放行
|
||||||
|
ServerHttpRequest request = exchange.getRequest();
|
||||||
|
if (!CorsUtils.isCorsRequest(request)) {
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置跨域响应头
|
||||||
|
ServerHttpResponse response = exchange.getResponse();
|
||||||
|
HttpHeaders headers = response.getHeaders();
|
||||||
|
headers.add("Access-Control-Allow-Origin", ALL);
|
||||||
|
headers.add("Access-Control-Allow-Methods", ALL);
|
||||||
|
headers.add("Access-Control-Allow-Headers", ALL);
|
||||||
|
headers.add("Access-Control-Max-Age", MAX_AGE);
|
||||||
|
if (request.getMethod() == HttpMethod.OPTIONS) {
|
||||||
|
response.setStatusCode(HttpStatus.OK);
|
||||||
|
return Mono.empty();
|
||||||
|
}
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,8 +5,7 @@ import org.springframework.cloud.gateway.route.Route;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网关的访问日志
|
* 网关的访问日志
|
||||||
|
@ -80,11 +79,11 @@ public class AccessLog {
|
||||||
/**
|
/**
|
||||||
* 开始请求时间
|
* 开始请求时间
|
||||||
*/
|
*/
|
||||||
private Date startTime;
|
private LocalDateTime startTime;
|
||||||
/**
|
/**
|
||||||
* 结束请求时间
|
* 结束请求时间
|
||||||
*/
|
*/
|
||||||
private Date endTime;
|
private LocalDateTime endTime;
|
||||||
/**
|
/**
|
||||||
* 执行时长,单位:毫秒
|
* 执行时长,单位:毫秒
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package cn.iocoder.yudao.gateway.filter.logging;
|
package cn.iocoder.yudao.gateway.filter.logging;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
|
@ -38,12 +39,13 @@ import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static cn.hutool.core.date.DatePattern.NORM_DATETIME_MS_FORMAT;
|
import static cn.hutool.core.date.DatePattern.NORM_DATETIME_MS_FORMAT;
|
||||||
|
import static cn.hutool.core.date.DatePattern.NORM_DATETIME_MS_FORMATTER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网关的访问日志过滤器
|
* 网关的访问日志过滤器
|
||||||
|
@ -89,8 +91,8 @@ public class AccessLogFilter implements GlobalFilter, Ordered {
|
||||||
values.put("responseHeaders", gatewayLog.getResponseHeaders() != null ?
|
values.put("responseHeaders", gatewayLog.getResponseHeaders() != null ?
|
||||||
JsonUtils.toJsonString(gatewayLog.getResponseHeaders().toSingleValueMap()) : null);
|
JsonUtils.toJsonString(gatewayLog.getResponseHeaders().toSingleValueMap()) : null);
|
||||||
values.put("httpStatus", gatewayLog.getHttpStatus());
|
values.put("httpStatus", gatewayLog.getHttpStatus());
|
||||||
values.put("startTime", DateUtil.format(gatewayLog.getStartTime(), NORM_DATETIME_MS_FORMAT));
|
values.put("startTime", LocalDateTimeUtil.format(gatewayLog.getStartTime(), NORM_DATETIME_MS_FORMATTER));
|
||||||
values.put("endTime", DateUtil.format(gatewayLog.getEndTime(), NORM_DATETIME_MS_FORMAT));
|
values.put("endTime", LocalDateTimeUtil.format(gatewayLog.getEndTime(), NORM_DATETIME_MS_FORMATTER));
|
||||||
values.put("duration", gatewayLog.getDuration() != null ? gatewayLog.getDuration() + " ms" : null);
|
values.put("duration", gatewayLog.getDuration() != null ? gatewayLog.getDuration() + " ms" : null);
|
||||||
log.info("[writeAccessLog][网关日志:{}]", JsonUtils.toJsonPrettyString(values));
|
log.info("[writeAccessLog][网关日志:{}]", JsonUtils.toJsonPrettyString(values));
|
||||||
}
|
}
|
||||||
|
@ -112,7 +114,7 @@ public class AccessLogFilter implements GlobalFilter, Ordered {
|
||||||
gatewayLog.setRequestUrl(request.getURI().getRawPath());
|
gatewayLog.setRequestUrl(request.getURI().getRawPath());
|
||||||
gatewayLog.setQueryParams(request.getQueryParams());
|
gatewayLog.setQueryParams(request.getQueryParams());
|
||||||
gatewayLog.setRequestHeaders(request.getHeaders());
|
gatewayLog.setRequestHeaders(request.getHeaders());
|
||||||
gatewayLog.setStartTime(new Date());
|
gatewayLog.setStartTime(LocalDateTime.now());
|
||||||
gatewayLog.setUserIp(WebFrameworkUtils.getClientIP(exchange));
|
gatewayLog.setUserIp(WebFrameworkUtils.getClientIP(exchange));
|
||||||
|
|
||||||
// 继续 filter 过滤
|
// 继续 filter 过滤
|
||||||
|
@ -179,8 +181,9 @@ public class AccessLogFilter implements GlobalFilter, Ordered {
|
||||||
if (body instanceof Flux) {
|
if (body instanceof Flux) {
|
||||||
DataBufferFactory bufferFactory = response.bufferFactory();
|
DataBufferFactory bufferFactory = response.bufferFactory();
|
||||||
// 计算执行时间
|
// 计算执行时间
|
||||||
gatewayLog.setEndTime(new Date());
|
gatewayLog.setEndTime(LocalDateTime.now());
|
||||||
gatewayLog.setDuration((int) DateUtils.diff(gatewayLog.getEndTime(), gatewayLog.getStartTime()));
|
gatewayLog.setDuration((int) (LocalDateTimeUtil.between(gatewayLog.getStartTime(),
|
||||||
|
gatewayLog.getEndTime()).toMillis()));
|
||||||
// 设置其它字段
|
// 设置其它字段
|
||||||
gatewayLog.setUserId(SecurityFrameworkUtils.getLoginUserId(exchange));
|
gatewayLog.setUserId(SecurityFrameworkUtils.getLoginUserId(exchange));
|
||||||
gatewayLog.setUserType(SecurityFrameworkUtils.getLoginUserType(exchange));
|
gatewayLog.setUserType(SecurityFrameworkUtils.getLoginUserType(exchange));
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package cn.iocoder.yudao.gateway.swagger;
|
package cn.iocoder.yudao.gateway.swagger;
|
||||||
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
@ -9,55 +8,47 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import springfox.documentation.swagger.web.SecurityConfiguration;
|
import springfox.documentation.swagger.web.*;
|
||||||
import springfox.documentation.swagger.web.SecurityConfigurationBuilder;
|
|
||||||
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
|
import javax.annotation.Resource;
|
||||||
import springfox.documentation.swagger.web.UiConfiguration;
|
import java.util.List;
|
||||||
import springfox.documentation.swagger.web.UiConfigurationBuilder;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Swagger Controller
|
||||||
|
*
|
||||||
* @author zxliu
|
* @author zxliu
|
||||||
* @create 2022-10-25 11:24
|
* @date 2022-10-25 11:24
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/swagger-resources")
|
@RequestMapping("/swagger-resources")
|
||||||
public class SwaggerHandler {
|
public class SwaggerHandler {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SwaggerResourcesProvider swaggerResources;
|
||||||
|
|
||||||
|
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") // 只有 @Autowired 可以实现可选注入
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
private SecurityConfiguration securityConfiguration;
|
private SecurityConfiguration securityConfiguration;
|
||||||
|
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") // 只有 @Autowired 可以实现可选注入
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
private UiConfiguration uiConfiguration;
|
private UiConfiguration uiConfiguration;
|
||||||
|
|
||||||
private final SwaggerResourcesProvider swaggerResources;
|
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public SwaggerHandler(SwaggerResourcesProvider swaggerResources) {
|
|
||||||
this.swaggerResources = swaggerResources;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/configuration/security")
|
|
||||||
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
|
|
||||||
return Mono.just(new ResponseEntity<>(
|
|
||||||
Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()),
|
|
||||||
HttpStatus.OK));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/configuration/ui")
|
|
||||||
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
|
|
||||||
return Mono.just(new ResponseEntity<>(
|
|
||||||
Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
@GetMapping("")
|
@GetMapping("")
|
||||||
public Mono<ResponseEntity> swaggerResources() {
|
public Mono<ResponseEntity<List<SwaggerResource>>> swaggerResources() {
|
||||||
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
|
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/configuration/security")
|
||||||
|
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
|
||||||
|
return Mono.just(new ResponseEntity<>(Optional.ofNullable(securityConfiguration)
|
||||||
|
.orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/configuration/ui")
|
||||||
|
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
|
||||||
|
return Mono.just(new ResponseEntity<>(Optional.ofNullable(uiConfiguration)
|
||||||
|
.orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +1,70 @@
|
||||||
package cn.iocoder.yudao.gateway.swagger;
|
package cn.iocoder.yudao.gateway.swagger;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import java.util.List;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.cloud.gateway.config.GatewayProperties;
|
import org.springframework.cloud.gateway.config.GatewayProperties;
|
||||||
import org.springframework.cloud.gateway.route.RouteLocator;
|
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
|
||||||
|
import org.springframework.cloud.gateway.route.RouteDefinition;
|
||||||
import org.springframework.cloud.gateway.support.NameUtils;
|
import org.springframework.cloud.gateway.support.NameUtils;
|
||||||
import org.springframework.context.annotation.Primary;
|
import org.springframework.context.annotation.Primary;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import springfox.documentation.swagger.web.SwaggerResource;
|
import springfox.documentation.swagger.web.SwaggerResource;
|
||||||
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
|
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
|
||||||
|
|
||||||
/**
|
import javax.annotation.Resource;
|
||||||
* @author zxliu
|
import java.util.ArrayList;
|
||||||
* @create 2022-10-25 11:23
|
import java.util.HashSet;
|
||||||
*/
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swagger 资源的 Provider 实现类
|
||||||
|
*
|
||||||
|
* @author zxliu
|
||||||
|
* @date 2022-10-25 11:23
|
||||||
|
*/
|
||||||
@Component
|
@Component
|
||||||
@Primary
|
@Primary
|
||||||
@AllArgsConstructor
|
@Slf4j
|
||||||
public class SwaggerProvider implements SwaggerResourcesProvider {
|
public class SwaggerProvider implements SwaggerResourcesProvider {
|
||||||
|
|
||||||
private final RouteLocator routeLocator;
|
@Resource
|
||||||
private final GatewayProperties gatewayProperties;
|
private GatewayProperties gatewayProperties;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得 SwaggerResource 列表
|
||||||
|
*
|
||||||
|
* @return SwaggerResource 列表
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<SwaggerResource> get() {
|
public List<SwaggerResource> get() {
|
||||||
|
// 将 RouteDefinition 转换成 SwaggerResource
|
||||||
List<SwaggerResource> resources = new ArrayList<>();
|
List<SwaggerResource> resources = new ArrayList<>();
|
||||||
List<String> routes = new ArrayList<>();
|
Set<String> serviceNames = new HashSet<>(); // 已处理的服务名,避免重复
|
||||||
routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
|
gatewayProperties.getRoutes().forEach(route -> {
|
||||||
gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId()))
|
// 已存在的服务,直接忽略
|
||||||
.forEach(route -> route.getPredicates().stream()
|
String serviceName = route.getUri().getHost();
|
||||||
.filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
|
if (StrUtil.isEmpty(serviceName)) {
|
||||||
.forEach(predicateDefinition -> resources.add(swaggerResource(route.getId(),
|
return;
|
||||||
predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0")
|
}
|
||||||
.replace("**", "v2/api-docs"))))
|
if (!serviceNames.add(serviceName)) {
|
||||||
);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得 Path PredicateDefinition
|
||||||
|
String path = getRoutePath(route);
|
||||||
|
if (path == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重要:构建最终的 SwaggerResource 对象
|
||||||
|
resources.add(buildSwaggerResource(serviceName, path));
|
||||||
|
});
|
||||||
return resources;
|
return resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SwaggerResource buildSwaggerResource(String name, String location) {
|
||||||
private SwaggerResource swaggerResource(String name, String location) {
|
|
||||||
SwaggerResource swaggerResource = new SwaggerResource();
|
SwaggerResource swaggerResource = new SwaggerResource();
|
||||||
swaggerResource.setName(name);
|
swaggerResource.setName(name);
|
||||||
swaggerResource.setLocation(location);
|
swaggerResource.setLocation(location);
|
||||||
|
@ -50,4 +72,31 @@ public class SwaggerProvider implements SwaggerResourcesProvider {
|
||||||
return swaggerResource;
|
return swaggerResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得路由的 Path
|
||||||
|
*
|
||||||
|
* ① 输入:
|
||||||
|
* predicates:
|
||||||
|
* - Path=/admin-api/system/**
|
||||||
|
* ② 输出:
|
||||||
|
* /admin-api/system/v2/api-docs
|
||||||
|
*
|
||||||
|
* @param route 路由
|
||||||
|
* @return 路由
|
||||||
|
*/
|
||||||
|
private String getRoutePath(RouteDefinition route) {
|
||||||
|
PredicateDefinition pathDefinition = CollUtil.findOne(route.getPredicates(),
|
||||||
|
predicateDefinition -> predicateDefinition.getName().equals("Path"));
|
||||||
|
if (pathDefinition == null) {
|
||||||
|
log.info("[get][Route({}) 没有 Path 条件,忽略接口文档]", route.getId());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String path = pathDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0");
|
||||||
|
if (StrUtil.isEmpty(path)) {
|
||||||
|
log.info("[get][Route({}) Path 的值为空,忽略接口文档]", route.getId());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return path.replace("/**", "/v2/api-docs");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,20 +5,14 @@ spring:
|
||||||
cloud:
|
cloud:
|
||||||
# Spring Cloud Gateway 配置项,对应 GatewayProperties 类
|
# Spring Cloud Gateway 配置项,对应 GatewayProperties 类
|
||||||
gateway:
|
gateway:
|
||||||
discovery:
|
|
||||||
locator:
|
|
||||||
# gateway开启服务注册和发现的功能,
|
|
||||||
enabled: true
|
|
||||||
# 将请求路径上的服务名配置为小写(因为服务注册的时候,向注册中心注册时将服务名转成大写的了)
|
|
||||||
lowerCaseServiceId: true
|
|
||||||
# 路由配置项,对应 RouteDefinition 数组
|
# 路由配置项,对应 RouteDefinition 数组
|
||||||
routes:
|
routes:
|
||||||
- id: system-admin-api # 路由的编号
|
- id: system-admin-api # 路由的编号
|
||||||
uri: grayLb://system-server
|
uri: grayLb://system-server
|
||||||
predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
|
predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
|
||||||
- Path=/admin-api/system/**,/captcha/**
|
- Path=/admin-api/system/**
|
||||||
filters:
|
filters:
|
||||||
- RewritePath=/admin-api/system/v2/api-docs, /v2/api-docs
|
- RewritePath=/admin-api/system/v2/api-docs, /v2/api-docs # 配置,保证转发到 /v2/api-docs
|
||||||
- id: system-app-api # 路由的编号
|
- id: system-app-api # 路由的编号
|
||||||
uri: grayLb://system-server
|
uri: grayLb://system-server
|
||||||
predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
|
predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
|
||||||
|
@ -30,7 +24,7 @@ spring:
|
||||||
predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
|
predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
|
||||||
- Path=/admin-api/infra/**
|
- Path=/admin-api/infra/**
|
||||||
filters:
|
filters:
|
||||||
- RewritePath=/admin-api/infram/v2/api-docs, /v2/api-docs
|
- RewritePath=/admin-api/infra/v2/api-docs, /v2/api-docs
|
||||||
- id: infra-app-api # 路由的编号
|
- id: infra-app-api # 路由的编号
|
||||||
uri: grayLb://infra-server
|
uri: grayLb://infra-server
|
||||||
predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
|
predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
|
||||||
|
|
|
@ -7,7 +7,7 @@ import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 动态表单 Response VO")
|
@ApiModel("管理后台 - 动态表单 Response VO")
|
||||||
|
@ -28,6 +28,6 @@ public class BpmFormRespVO extends BpmFormBaseVO {
|
||||||
private List<String> fields;
|
private List<String> fields;
|
||||||
|
|
||||||
@ApiModelProperty(value = "创建时间", required = true)
|
@ApiModelProperty(value = "创建时间", required = true)
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 用户组分页 Request VO")
|
@ApiModel("管理后台 - 用户组分页 Request VO")
|
||||||
@Data
|
@Data
|
||||||
|
@ -25,6 +25,6 @@ public class BpmUserGroupPageReqVO extends PageParam {
|
||||||
|
|
||||||
@DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
@ApiModelProperty(value = "创建时间")
|
@ApiModelProperty(value = "创建时间")
|
||||||
private Date[] createTime;
|
private LocalDateTime[] createTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group;
|
package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group;
|
||||||
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import io.swagger.annotations.*;
|
import io.swagger.annotations.*;
|
||||||
|
|
||||||
|
@ -14,6 +16,6 @@ public class BpmUserGroupRespVO extends BpmUserGroupBaseVO {
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@ApiModelProperty(value = "创建时间", required = true)
|
@ApiModelProperty(value = "创建时间", required = true)
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 流程模型的分页的每一项 Response VO")
|
@ApiModel("管理后台 - 流程模型的分页的每一项 Response VO")
|
||||||
@Data
|
@Data
|
||||||
|
@ -21,7 +21,7 @@ public class BpmModelPageItemRespVO extends BpmModelBaseVO {
|
||||||
private String formName;
|
private String formName;
|
||||||
|
|
||||||
@ApiModelProperty(value = "创建时间", required = true)
|
@ApiModelProperty(value = "创建时间", required = true)
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 最新部署的流程定义
|
* 最新部署的流程定义
|
||||||
|
@ -39,7 +39,7 @@ public class BpmModelPageItemRespVO extends BpmModelBaseVO {
|
||||||
private Integer version;
|
private Integer version;
|
||||||
|
|
||||||
@ApiModelProperty(value = "部署时间", required = true)
|
@ApiModelProperty(value = "部署时间", required = true)
|
||||||
private Date deploymentTime;
|
private LocalDateTime deploymentTime;
|
||||||
|
|
||||||
@ApiModelProperty(value = "中断状态", required = true, example = "1", notes = "参见 SuspensionState 枚举")
|
@ApiModelProperty(value = "中断状态", required = true, example = "1", notes = "参见 SuspensionState 枚举")
|
||||||
private Integer suspensionState;
|
private Integer suspensionState;
|
||||||
|
|
|
@ -6,7 +6,7 @@ import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 流程模型的创建 Request VO")
|
@ApiModel("管理后台 - 流程模型的创建 Request VO")
|
||||||
@Data
|
@Data
|
||||||
|
@ -21,6 +21,6 @@ public class BpmModelRespVO extends BpmModelBaseVO {
|
||||||
private String bpmnXml;
|
private String bpmnXml;
|
||||||
|
|
||||||
@ApiModelProperty(value = "创建时间", required = true)
|
@ApiModelProperty(value = "创建时间", required = true)
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 流程定义的分页的每一项 Response VO")
|
@ApiModel("管理后台 - 流程定义的分页的每一项 Response VO")
|
||||||
@Data
|
@Data
|
||||||
|
@ -18,6 +18,6 @@ public class BpmProcessDefinitionPageItemRespVO extends BpmProcessDefinitionResp
|
||||||
private String formName;
|
private String formName;
|
||||||
|
|
||||||
@ApiModelProperty(value = "部署时间", required = true)
|
@ApiModelProperty(value = "部署时间", required = true)
|
||||||
private Date deploymentTime;
|
private LocalDateTime deploymentTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo;
|
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo;
|
||||||
|
|
||||||
import lombok.*;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import java.util.*;
|
import lombok.Data;
|
||||||
import io.swagger.annotations.*;
|
|
||||||
import javax.validation.constraints.*;
|
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,11 +19,11 @@ public class BpmOALeaveBaseVO {
|
||||||
@ApiModelProperty(value = "请假的开始时间", required = true)
|
@ApiModelProperty(value = "请假的开始时间", required = true)
|
||||||
@NotNull(message = "开始时间不能为空")
|
@NotNull(message = "开始时间不能为空")
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
private Date startTime;
|
private LocalDateTime startTime;
|
||||||
@ApiModelProperty(value = "请假的结束时间", required = true)
|
@ApiModelProperty(value = "请假的结束时间", required = true)
|
||||||
@NotNull(message = "结束时间不能为空")
|
@NotNull(message = "结束时间不能为空")
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
private Date endTime;
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
@ApiModelProperty(value = "请假类型", required = true, example = "1", notes = "参见 bpm_oa_type 枚举")
|
@ApiModelProperty(value = "请假类型", required = true, example = "1", notes = "参见 bpm_oa_type 枚举")
|
||||||
private Integer type;
|
private Integer type;
|
||||||
|
|
|
@ -15,7 +15,8 @@ public class BpmOALeaveCreateReqVO extends BpmOALeaveBaseVO {
|
||||||
|
|
||||||
@AssertTrue(message = "结束时间,需要在开始时间之后")
|
@AssertTrue(message = "结束时间,需要在开始时间之后")
|
||||||
public boolean isEndTimeValid() {
|
public boolean isEndTimeValid() {
|
||||||
return !getEndTime().before(getStartTime());
|
return !getEndTime().isBefore(getStartTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import io.swagger.annotations.*;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ public class BpmOALeaveRespVO extends BpmOALeaveBaseVO {
|
||||||
@ApiModelProperty(value = "申请时间", required = true)
|
@ApiModelProperty(value = "申请时间", required = true)
|
||||||
@NotNull(message = "申请时间不能为空")
|
@NotNull(message = "申请时间不能为空")
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ApiModelProperty(value = "流程id")
|
@ApiModelProperty(value = "流程id")
|
||||||
private String processInstanceId;
|
private String processInstanceId;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 流程活动的 Response VO")
|
@ApiModel("管理后台 - 流程活动的 Response VO")
|
||||||
@Data
|
@Data
|
||||||
|
@ -16,9 +16,9 @@ public class BpmActivityRespVO {
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
@ApiModelProperty(value = "流程活动的开始时间", required = true)
|
@ApiModelProperty(value = "流程活动的开始时间", required = true)
|
||||||
private Date startTime;
|
private LocalDateTime startTime;
|
||||||
@ApiModelProperty(value = "流程活动的结束时间", required = true)
|
@ApiModelProperty(value = "流程活动的结束时间", required = true)
|
||||||
private Date endTime;
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
@ApiModelProperty(value = "关联的流程任务的编号", example = "2048", notes = "关联的流程任务,只有 UserTask 等类型才有")
|
@ApiModelProperty(value = "关联的流程任务的编号", example = "2048", notes = "关联的流程任务,只有 UserTask 等类型才有")
|
||||||
private String taskId;
|
private String taskId;
|
||||||
|
|
|
@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
|
@ -35,6 +35,6 @@ public class BpmProcessInstanceMyPageReqVO extends PageParam {
|
||||||
|
|
||||||
@ApiModelProperty(value = "创建时间")
|
@ApiModelProperty(value = "创建时间")
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
private Date[] createTime;
|
private LocalDateTime[] createTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 流程实例的分页 Item Response VO")
|
@ApiModel("管理后台 - 流程实例的分页 Item Response VO")
|
||||||
|
@ -30,10 +30,10 @@ public class BpmProcessInstancePageItemRespVO {
|
||||||
private Integer result;
|
private Integer result;
|
||||||
|
|
||||||
@ApiModelProperty(value = "提交时间", required = true)
|
@ApiModelProperty(value = "提交时间", required = true)
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ApiModelProperty(value = "结束时间", required = true)
|
@ApiModelProperty(value = "结束时间", required = true)
|
||||||
private Date endTime;
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前任务
|
* 当前任务
|
||||||
|
|
|
@ -4,7 +4,7 @@ import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -28,10 +28,10 @@ public class BpmProcessInstanceRespVO {
|
||||||
private Integer result;
|
private Integer result;
|
||||||
|
|
||||||
@ApiModelProperty(value = "提交时间", required = true)
|
@ApiModelProperty(value = "提交时间", required = true)
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ApiModelProperty(value = "结束时间", required = true)
|
@ApiModelProperty(value = "结束时间", required = true)
|
||||||
private Date endTime;
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
@ApiModelProperty(value = "提交的表单值", required = true)
|
@ApiModelProperty(value = "提交的表单值", required = true)
|
||||||
private Map<String, Object> formVariables;
|
private Map<String, Object> formVariables;
|
||||||
|
|
|
@ -6,7 +6,7 @@ import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 流程任务的 Done 已完成的分页项 Response VO")
|
@ApiModel("管理后台 - 流程任务的 Done 已完成的分页项 Response VO")
|
||||||
@Data
|
@Data
|
||||||
|
@ -15,7 +15,7 @@ import java.util.Date;
|
||||||
public class BpmTaskDonePageItemRespVO extends BpmTaskTodoPageItemRespVO {
|
public class BpmTaskDonePageItemRespVO extends BpmTaskTodoPageItemRespVO {
|
||||||
|
|
||||||
@ApiModelProperty(value = "结束时间", required = true)
|
@ApiModelProperty(value = "结束时间", required = true)
|
||||||
private Date endTime;
|
private LocalDateTime endTime;
|
||||||
@ApiModelProperty(value = "持续时间", required = true, example = "1000")
|
@ApiModelProperty(value = "持续时间", required = true, example = "1000")
|
||||||
private Long durationInMillis;
|
private Long durationInMillis;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
|
@ -23,10 +23,10 @@ public class BpmTaskDonePageReqVO extends PageParam {
|
||||||
|
|
||||||
@ApiModelProperty(value = "开始的创建收间")
|
@ApiModelProperty(value = "开始的创建收间")
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
private Date beginCreateTime;
|
private LocalDateTime beginCreateTime;
|
||||||
|
|
||||||
@ApiModelProperty(value = "结束的创建时间")
|
@ApiModelProperty(value = "结束的创建时间")
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
private Date endCreateTime;
|
private LocalDateTime endCreateTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 流程任务的 Running 进行中的分页项 Response VO")
|
@ApiModel("管理后台 - 流程任务的 Running 进行中的分页项 Response VO")
|
||||||
@Data
|
@Data
|
||||||
|
@ -17,10 +17,10 @@ public class BpmTaskTodoPageItemRespVO {
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@ApiModelProperty(value = "接收时间", required = true)
|
@ApiModelProperty(value = "接收时间", required = true)
|
||||||
private Date claimTime;
|
private LocalDateTime claimTime;
|
||||||
|
|
||||||
@ApiModelProperty(value = "创建时间", required = true)
|
@ApiModelProperty(value = "创建时间", required = true)
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ApiModelProperty(value = "激活状态", required = true, example = "1", notes = "参见 SuspensionState 枚举")
|
@ApiModelProperty(value = "激活状态", required = true, example = "1", notes = "参见 SuspensionState 枚举")
|
||||||
private Integer suspensionState;
|
private Integer suspensionState;
|
||||||
|
|
|
@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
|
@ -23,10 +23,10 @@ public class BpmTaskTodoPageReqVO extends PageParam {
|
||||||
|
|
||||||
@ApiModelProperty(value = "开始的创建收间")
|
@ApiModelProperty(value = "开始的创建收间")
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
private Date beginCreateTime;
|
private LocalDateTime beginCreateTime;
|
||||||
|
|
||||||
@ApiModelProperty(value = "结束的创建时间")
|
@ApiModelProperty(value = "结束的创建时间")
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
private Date endCreateTime;
|
private LocalDateTime endCreateTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package cn.iocoder.yudao.module.bpm.convert.definition;
|
package cn.iocoder.yudao.module.bpm.convert.definition;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormCreateReqVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormRespVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormRespVO;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormSimpleRespVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormSimpleRespVO;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormUpdateReqVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormUpdateReqVO;
|
||||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
|
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.convert.definition;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*;
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*;
|
||||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
|
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
|
||||||
|
@ -44,7 +45,7 @@ public interface BpmModelConvert {
|
||||||
default BpmModelPageItemRespVO convert(Model model, BpmFormDO form, Deployment deployment, ProcessDefinition processDefinition) {
|
default BpmModelPageItemRespVO convert(Model model, BpmFormDO form, Deployment deployment, ProcessDefinition processDefinition) {
|
||||||
BpmModelPageItemRespVO modelRespVO = new BpmModelPageItemRespVO();
|
BpmModelPageItemRespVO modelRespVO = new BpmModelPageItemRespVO();
|
||||||
modelRespVO.setId(model.getId());
|
modelRespVO.setId(model.getId());
|
||||||
modelRespVO.setCreateTime(model.getCreateTime());
|
modelRespVO.setCreateTime(DateUtils.of(model.getCreateTime()));
|
||||||
// 通用 copy
|
// 通用 copy
|
||||||
copyTo(model, modelRespVO);
|
copyTo(model, modelRespVO);
|
||||||
// Form
|
// Form
|
||||||
|
@ -57,7 +58,7 @@ public interface BpmModelConvert {
|
||||||
if (modelRespVO.getProcessDefinition() != null) {
|
if (modelRespVO.getProcessDefinition() != null) {
|
||||||
modelRespVO.getProcessDefinition().setSuspensionState(processDefinition.isSuspended() ?
|
modelRespVO.getProcessDefinition().setSuspensionState(processDefinition.isSuspended() ?
|
||||||
SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode());
|
SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode());
|
||||||
modelRespVO.getProcessDefinition().setDeploymentTime(deployment.getDeploymentTime());
|
modelRespVO.getProcessDefinition().setDeploymentTime(DateUtils.of(deployment.getDeploymentTime()));
|
||||||
}
|
}
|
||||||
return modelRespVO;
|
return modelRespVO;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +66,7 @@ public interface BpmModelConvert {
|
||||||
default BpmModelRespVO convert(Model model) {
|
default BpmModelRespVO convert(Model model) {
|
||||||
BpmModelRespVO modelRespVO = new BpmModelRespVO();
|
BpmModelRespVO modelRespVO = new BpmModelRespVO();
|
||||||
modelRespVO.setId(model.getId());
|
modelRespVO.setId(model.getId());
|
||||||
modelRespVO.setCreateTime(model.getCreateTime());
|
modelRespVO.setCreateTime(DateUtils.of(model.getCreateTime()));
|
||||||
// 通用 copy
|
// 通用 copy
|
||||||
copyTo(model, modelRespVO);
|
copyTo(model, modelRespVO);
|
||||||
return modelRespVO;
|
return modelRespVO;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cn.iocoder.yudao.module.bpm.convert.definition;
|
package cn.iocoder.yudao.module.bpm.convert.definition;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
|
||||||
|
@ -67,7 +68,7 @@ public interface BpmProcessDefinitionConvert {
|
||||||
BpmProcessDefinitionPageItemRespVO respVO = convert(bean);
|
BpmProcessDefinitionPageItemRespVO respVO = convert(bean);
|
||||||
respVO.setSuspensionState(bean.isSuspended() ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode());
|
respVO.setSuspensionState(bean.isSuspended() ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode());
|
||||||
if (deployment != null) {
|
if (deployment != null) {
|
||||||
respVO.setDeploymentTime(deployment.getDeploymentTime());
|
respVO.setDeploymentTime(LocalDateTimeUtil.of(deployment.getDeploymentTime()));
|
||||||
}
|
}
|
||||||
if (form != null) {
|
if (form != null) {
|
||||||
respVO.setFormName(form.getName());
|
respVO.setFormName(form.getName());
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
package cn.iocoder.yudao.module.bpm.convert.definition;
|
package cn.iocoder.yudao.module.bpm.convert.definition;
|
||||||
|
|
||||||
import java.util.*;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupRespVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupRespVO;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO;
|
||||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
|
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
|
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Named;
|
import org.mapstruct.Named;
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户组 Convert
|
* 用户组 Convert
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.convert.message;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
|
import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -11,6 +12,10 @@ public interface BpmMessageConvert {
|
||||||
|
|
||||||
BpmMessageConvert INSTANCE = Mappers.getMapper(BpmMessageConvert.class);
|
BpmMessageConvert INSTANCE = Mappers.getMapper(BpmMessageConvert.class);
|
||||||
|
|
||||||
|
@Mapping(target = "mobile", ignore = true)
|
||||||
|
@Mapping(source = "userId", target = "userId")
|
||||||
|
@Mapping(source = "templateCode", target = "templateCode")
|
||||||
|
@Mapping(source = "templateParams", target = "templateParams")
|
||||||
SmsSendSingleToUserReqDTO convert(Long userId, String templateCode, Map<String, Object> templateParams);
|
SmsSendSingleToUserReqDTO convert(Long userId, String templateCode, Map<String, Object> templateParams);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package cn.iocoder.yudao.module.bpm.convert.oa;
|
package cn.iocoder.yudao.module.bpm.convert.oa;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveCreateReqVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveRespVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveRespVO;
|
||||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO;
|
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cn.iocoder.yudao.module.bpm.convert.task;
|
package cn.iocoder.yudao.module.bpm.convert.task;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskDonePageItemRespVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskDonePageItemRespVO;
|
||||||
|
@ -151,7 +152,7 @@ public interface BpmTaskConvert {
|
||||||
BpmTaskExtDO taskExtDO = new BpmTaskExtDO().setTaskId(task.getId())
|
BpmTaskExtDO taskExtDO = new BpmTaskExtDO().setTaskId(task.getId())
|
||||||
.setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setName(task.getName())
|
.setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setName(task.getName())
|
||||||
.setProcessDefinitionId(task.getProcessDefinitionId()).setProcessInstanceId(task.getProcessInstanceId());
|
.setProcessDefinitionId(task.getProcessDefinitionId()).setProcessInstanceId(task.getProcessInstanceId());
|
||||||
taskExtDO.setCreateTime(task.getCreateTime());
|
taskExtDO.setCreateTime(LocalDateTimeUtil.of(task.getCreateTime()));
|
||||||
return taskExtDO;
|
return taskExtDO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.oa;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
|
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
@ -46,11 +48,11 @@ public class BpmOALeaveDO extends BaseDO {
|
||||||
/**
|
/**
|
||||||
* 开始时间
|
* 开始时间
|
||||||
*/
|
*/
|
||||||
private Date startTime;
|
private LocalDateTime startTime;
|
||||||
/**
|
/**
|
||||||
* 结束时间
|
* 结束时间
|
||||||
*/
|
*/
|
||||||
private Date endTime;
|
private LocalDateTime endTime;
|
||||||
/**
|
/**
|
||||||
* 请假天数
|
* 请假天数
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
|
||||||
|
@ -80,14 +80,14 @@ public class BpmActivityDO {
|
||||||
*/
|
*/
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
|
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
|
||||||
private Date startTime;
|
private LocalDateTime startTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务结束时间
|
* 任务结束时间
|
||||||
*/
|
*/
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
|
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
|
||||||
private Date endTime;
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
private Integer transactionOrder;
|
private Integer transactionOrder;
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,7 +79,7 @@ public class BpmProcessInstanceExtDO extends BaseDO {
|
||||||
*
|
*
|
||||||
* 冗余 HistoricProcessInstance 的 endTime 属性
|
* 冗余 HistoricProcessInstance 的 endTime 属性
|
||||||
*/
|
*/
|
||||||
private Date endTime;
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提交的表单值
|
* 提交的表单值
|
||||||
|
|
|
@ -8,7 +8,7 @@ import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bpm 流程任务的拓展表
|
* Bpm 流程任务的拓展表
|
||||||
|
@ -67,7 +67,7 @@ public class BpmTaskExtDO extends BaseDO {
|
||||||
*
|
*
|
||||||
* 冗余 HistoricTaskInstance 的 endTime 属性
|
* 冗余 HistoricTaskInstance 的 endTime 属性
|
||||||
*/
|
*/
|
||||||
private Date endTime;
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程实例的编号
|
* 流程实例的编号
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package cn.iocoder.yudao.module.bpm.service.oa;
|
package cn.iocoder.yudao.module.bpm.service.oa;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
|
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
|
||||||
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
|
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
|
||||||
|
@ -46,7 +47,7 @@ public class BpmOALeaveServiceImpl implements BpmOALeaveService {
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public Long createLeave(Long userId, BpmOALeaveCreateReqVO createReqVO) {
|
public Long createLeave(Long userId, BpmOALeaveCreateReqVO createReqVO) {
|
||||||
// 插入 OA 请假单
|
// 插入 OA 请假单
|
||||||
long day = DateUtil.betweenDay(createReqVO.getStartTime(), createReqVO.getEndTime(), false);
|
long day = LocalDateTimeUtil.between(createReqVO.getStartTime(), createReqVO.getEndTime()).toDays();
|
||||||
BpmOALeaveDO leave = BpmOALeaveConvert.INSTANCE.convert(createReqVO).setUserId(userId).setDay(day)
|
BpmOALeaveDO leave = BpmOALeaveConvert.INSTANCE.convert(createReqVO).setUserId(userId).setDay(day)
|
||||||
.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
|
.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
|
||||||
leaveMapper.insert(leave);
|
leaveMapper.insert(leave);
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.service.task;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.PageUtils;
|
import cn.iocoder.yudao.framework.common.util.object.PageUtils;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
|
||||||
|
@ -32,6 +33,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
@ -74,10 +76,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
||||||
taskQuery.taskNameLike("%" + pageVO.getName() + "%");
|
taskQuery.taskNameLike("%" + pageVO.getName() + "%");
|
||||||
}
|
}
|
||||||
if (pageVO.getBeginCreateTime() != null) {
|
if (pageVO.getBeginCreateTime() != null) {
|
||||||
taskQuery.taskCreatedAfter(pageVO.getBeginCreateTime());
|
taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getBeginCreateTime()));
|
||||||
}
|
}
|
||||||
if (pageVO.getEndCreateTime() != null) {
|
if (pageVO.getEndCreateTime() != null) {
|
||||||
taskQuery.taskCreatedBefore(pageVO.getEndCreateTime());
|
taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getEndCreateTime()));
|
||||||
}
|
}
|
||||||
// 执行查询
|
// 执行查询
|
||||||
List<Task> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
|
List<Task> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
|
||||||
|
@ -106,10 +108,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
||||||
taskQuery.taskNameLike("%" + pageVO.getName() + "%");
|
taskQuery.taskNameLike("%" + pageVO.getName() + "%");
|
||||||
}
|
}
|
||||||
if (pageVO.getBeginCreateTime() != null) {
|
if (pageVO.getBeginCreateTime() != null) {
|
||||||
taskQuery.taskCreatedAfter(pageVO.getBeginCreateTime());
|
taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getBeginCreateTime()));
|
||||||
}
|
}
|
||||||
if (pageVO.getEndCreateTime() != null) {
|
if (pageVO.getEndCreateTime() != null) {
|
||||||
taskQuery.taskCreatedBefore(pageVO.getEndCreateTime());
|
taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getEndCreateTime()));
|
||||||
}
|
}
|
||||||
// 执行查询
|
// 执行查询
|
||||||
List<HistoricTaskInstance> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
|
List<HistoricTaskInstance> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
|
||||||
|
@ -205,7 +207,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
||||||
// 更新任务拓展表为不通过
|
// 更新任务拓展表为不通过
|
||||||
taskExtMapper.updateByTaskId(
|
taskExtMapper.updateByTaskId(
|
||||||
new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.REJECT.getResult())
|
new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.REJECT.getResult())
|
||||||
.setEndTime(new Date()).setReason(reqVO.getReason()));
|
.setEndTime(LocalDateTime.now()).setReason(reqVO.getReason()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -249,7 +251,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
||||||
public void updateTaskExtComplete(Task task) {
|
public void updateTaskExtComplete(Task task) {
|
||||||
BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task)
|
BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task)
|
||||||
.setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()) // 不设置也问题不大,因为 Complete 一般是审核通过,已经设置
|
.setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()) // 不设置也问题不大,因为 Complete 一般是审核通过,已经设置
|
||||||
.setEndTime(new Date());
|
.setEndTime(LocalDateTime.now());
|
||||||
taskExtMapper.updateByTaskId(taskExtDO);
|
taskExtMapper.updateByTaskId(taskExtDO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,7 +282,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
||||||
|
|
||||||
// 更新任务
|
// 更新任务
|
||||||
taskExtMapper.updateById(new BpmTaskExtDO().setId(taskExt.getId()).setResult(BpmProcessInstanceResultEnum.CANCEL.getResult())
|
taskExtMapper.updateById(new BpmTaskExtDO().setId(taskExt.getId()).setResult(BpmProcessInstanceResultEnum.CANCEL.getResult())
|
||||||
.setEndTime(new Date()).setReason(BpmProcessInstanceDeleteReasonEnum.translateReason(task.getDeleteReason())));
|
.setEndTime(LocalDateTime.now()).setReason(BpmProcessInstanceDeleteReasonEnum.translateReason(task.getDeleteReason())));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,7 +16,7 @@ spring:
|
||||||
# Jackson 配置项
|
# Jackson 配置项
|
||||||
jackson:
|
jackson:
|
||||||
serialization:
|
serialization:
|
||||||
write-dates-as-timestamps: true # 设置 Date 的格式,使用时间戳
|
write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
|
||||||
write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
|
write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
|
||||||
write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
|
write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
|
||||||
fail-on-empty-beans: false # 允许序列化无属性的 Bean
|
fail-on-empty-beans: false # 允许序列化无属性的 Bean
|
||||||
|
|
|
@ -41,6 +41,8 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest {
|
||||||
// mock 方法(startUser)
|
// mock 方法(startUser)
|
||||||
AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L));
|
AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L));
|
||||||
when(adminUserApi.getUser(eq(1L))).thenReturn(success(startUser));
|
when(adminUserApi.getUser(eq(1L))).thenReturn(success(startUser));
|
||||||
|
// mock 方法(getStartUserDept)没有部门
|
||||||
|
when(deptApi.getDept(eq(10L))).thenReturn(success(null));
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
Set<Long> result = script.calculateTaskCandidateUsers(execution);
|
Set<Long> result = script.calculateTaskCandidateUsers(execution);
|
||||||
|
@ -57,7 +59,9 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest {
|
||||||
when(adminUserApi.getUser(eq(1L))).thenReturn(success(startUser));
|
when(adminUserApi.getUser(eq(1L))).thenReturn(success(startUser));
|
||||||
DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L)
|
DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L)
|
||||||
.setLeaderUserId(20L));
|
.setLeaderUserId(20L));
|
||||||
|
// mock 方法(getDept)
|
||||||
when(deptApi.getDept(eq(10L))).thenReturn(success(startUserDept));
|
when(deptApi.getDept(eq(10L))).thenReturn(success(startUserDept));
|
||||||
|
when(deptApi.getDept(eq(100L))).thenReturn(success(null));
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
Set<Long> result = script.calculateTaskCandidateUsers(execution);
|
Set<Long> result = script.calculateTaskCandidateUsers(execution);
|
||||||
|
|
|
@ -17,8 +17,9 @@ import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildLocalDateTime;
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime;
|
||||||
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
|
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
|
||||||
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_NOT_EXISTS;
|
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_NOT_EXISTS;
|
||||||
|
@ -106,7 +107,7 @@ public class BpmUserGroupServiceTest extends BaseDbUnitTest {
|
||||||
BpmUserGroupDO dbUserGroup = RandomUtils.randomPojo(BpmUserGroupDO.class, o -> { // 等会查询到
|
BpmUserGroupDO dbUserGroup = RandomUtils.randomPojo(BpmUserGroupDO.class, o -> { // 等会查询到
|
||||||
o.setName("芋道源码");
|
o.setName("芋道源码");
|
||||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||||
o.setCreateTime(DateUtils.buildTime(2021, 11, 11));
|
o.setCreateTime(buildLocalDateTime(2021, 11, 11));
|
||||||
});
|
});
|
||||||
userGroupMapper.insert(dbUserGroup);
|
userGroupMapper.insert(dbUserGroup);
|
||||||
// 测试 name 不匹配
|
// 测试 name 不匹配
|
||||||
|
@ -114,12 +115,13 @@ public class BpmUserGroupServiceTest extends BaseDbUnitTest {
|
||||||
// 测试 status 不匹配
|
// 测试 status 不匹配
|
||||||
userGroupMapper.insert(cloneIgnoreId(dbUserGroup, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
userGroupMapper.insert(cloneIgnoreId(dbUserGroup, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
||||||
// 测试 createTime 不匹配
|
// 测试 createTime 不匹配
|
||||||
userGroupMapper.insert(cloneIgnoreId(dbUserGroup, o -> o.setCreateTime(DateUtils.buildTime(2021, 12, 12))));
|
userGroupMapper.insert(cloneIgnoreId(dbUserGroup, o -> o.setCreateTime(buildLocalDateTime(2021, 12, 12))));
|
||||||
// 准备参数
|
// 准备参数
|
||||||
BpmUserGroupPageReqVO reqVO = new BpmUserGroupPageReqVO();
|
BpmUserGroupPageReqVO reqVO = new BpmUserGroupPageReqVO();
|
||||||
reqVO.setName("源码");
|
reqVO.setName("源码");
|
||||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||||
reqVO.setCreateTime((new Date[]{buildTime(2021, 11, 10),buildTime(2021, 11, 12)}));
|
reqVO.setCreateTime((new LocalDateTime[]{buildLocalDateTime(2021, 11, 10),
|
||||||
|
buildLocalDateTime(2021, 11, 12)}));
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
PageResult<BpmUserGroupDO> pageResult = userGroupService.getUserGroupPage(reqVO);
|
PageResult<BpmUserGroupDO> pageResult = userGroupService.getUserGroupPage(reqVO);
|
||||||
|
|
|
@ -23,6 +23,9 @@ spring:
|
||||||
mybatis-plus:
|
mybatis-plus:
|
||||||
lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试
|
lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试
|
||||||
type-aliases-package: ${yudao.info.base-package}.module.*.dal.dataobject
|
type-aliases-package: ${yudao.info.base-package}.module.*.dal.dataobject
|
||||||
|
global-config:
|
||||||
|
db-config:
|
||||||
|
id-type: AUTO # H2 主键递增
|
||||||
|
|
||||||
--- #################### 定时任务相关配置 ####################
|
--- #################### 定时任务相关配置 ####################
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@ApiModel("RPC 服务 - API 访问日志创建 Request DTO")
|
@ApiModel("RPC 服务 - API 访问日志创建 Request DTO")
|
||||||
@Data
|
@Data
|
||||||
|
@ -40,10 +40,10 @@ public class ApiAccessLogCreateReqDTO {
|
||||||
|
|
||||||
@ApiModelProperty(value = "开始时间", required = true)
|
@ApiModelProperty(value = "开始时间", required = true)
|
||||||
@NotNull(message = "开始请求时间不能为空")
|
@NotNull(message = "开始请求时间不能为空")
|
||||||
private Date beginTime;
|
private LocalDateTime beginTime;
|
||||||
@ApiModelProperty(value = "结束时间", required = true)
|
@ApiModelProperty(value = "结束时间", required = true)
|
||||||
@NotNull(message = "结束请求时间不能为空")
|
@NotNull(message = "结束请求时间不能为空")
|
||||||
private Date endTime;
|
private LocalDateTime endTime;
|
||||||
@ApiModelProperty(value = "执行时长,单位:毫秒", required = true)
|
@ApiModelProperty(value = "执行时长,单位:毫秒", required = true)
|
||||||
@NotNull(message = "执行时长不能为空")
|
@NotNull(message = "执行时长不能为空")
|
||||||
private Integer duration;
|
private Integer duration;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@ApiModel("RPC 服务 - API 错误日志创建 Request DTO")
|
@ApiModel("RPC 服务 - API 错误日志创建 Request DTO")
|
||||||
@Data
|
@Data
|
||||||
|
@ -40,7 +40,7 @@ public class ApiErrorLogCreateReqDTO {
|
||||||
|
|
||||||
@ApiModelProperty(value = "异常时间", required = true)
|
@ApiModelProperty(value = "异常时间", required = true)
|
||||||
@NotNull(message = "异常时间不能为空")
|
@NotNull(message = "异常时间不能为空")
|
||||||
private Date exceptionTime;
|
private LocalDateTime exceptionTime;
|
||||||
@ApiModelProperty(value = "异常名", required = true)
|
@ApiModelProperty(value = "异常名", required = true)
|
||||||
@NotNull(message = "异常名不能为空")
|
@NotNull(message = "异常名不能为空")
|
||||||
private String exceptionName;
|
private String exceptionName;
|
||||||
|
|
|
@ -6,7 +6,7 @@ import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 代码生成字段定义 Response VO")
|
@ApiModel("管理后台 - 代码生成字段定义 Response VO")
|
||||||
@Data
|
@Data
|
||||||
|
@ -18,6 +18,6 @@ public class CodegenColumnRespVO extends CodegenColumnBaseVO {
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@ApiModelProperty(value = "创建时间", required = true)
|
@ApiModelProperty(value = "创建时间", required = true)
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
|
@ -26,6 +26,6 @@ public class CodegenTablePageReqVO extends PageParam {
|
||||||
|
|
||||||
@ApiModelProperty(value = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
|
@ApiModelProperty(value = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
private Date[] createTime;
|
private LocalDateTime[] createTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@ApiModel("管理后台 - 代码生成表定义 Response VO")
|
@ApiModel("管理后台 - 代码生成表定义 Response VO")
|
||||||
@Data
|
@Data
|
||||||
|
@ -21,9 +21,9 @@ public class CodegenTableRespVO extends CodegenTableBaseVO {
|
||||||
private Integer dataSourceConfigId;
|
private Integer dataSourceConfigId;
|
||||||
|
|
||||||
@ApiModelProperty(value = "创建时间", required = true)
|
@ApiModelProperty(value = "创建时间", required = true)
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ApiModelProperty(value = "更新时间", required = true)
|
@ApiModelProperty(value = "更新时间", required = true)
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cn.iocoder.yudao.module.infra.controller.admin.db.vo;
|
package cn.iocoder.yudao.module.infra.controller.admin.db.vo;
|
||||||
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import io.swagger.annotations.*;
|
import io.swagger.annotations.*;
|
||||||
|
|
||||||
|
@ -14,6 +16,6 @@ public class DataSourceConfigRespVO extends DataSourceConfigBaseVO {
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
||||||
@ApiModelProperty(value = "创建时间", required = true)
|
@ApiModelProperty(value = "创建时间", required = true)
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
|
@ -26,6 +26,6 @@ public class FileConfigPageReqVO extends PageParam {
|
||||||
|
|
||||||
@ApiModelProperty(value = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
|
@ApiModelProperty(value = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
private Date[] createTime;
|
private LocalDateTime[] createTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue