mirror of
https://gitee.com/orangeform/orange-admin.git
synced 2026-01-17 18:46:36 +08:00
commit:同步1.4版本
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
package com.orange.demo.common.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 主要用于标记数据权限中基于DeptId进行过滤的字段。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2020-09-24
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DeptFilterColumn {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.orange.demo.common.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 作为DisableDataFilterAspect的切点。
|
||||
* 该注解仅能标记在方法上,方法内所有的查询语句,均不会被Mybatis拦截器过滤数据。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2020-09-24
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DisableDataFilter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.orange.demo.common.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 仅用于微服务的多租户项目。
|
||||
* 用于注解DAO层Mapper对象的租户过滤规则。被包含的方法将不会进行租户Id的过滤。
|
||||
* 对于tk mapper和mybatis plus中的内置方法,可以直接指定方法名即可,如:selectOne。
|
||||
* 需要说明的是,在大多数场景下,只要在实体对象中指定了租户Id字段,基于该主表的绝大部分增删改操作,
|
||||
* 都需要经过租户Id过滤,仅当查询非常复杂,或者主表不在SQL语句之中的时候,可以通过该注解禁用该SQL,
|
||||
* 并根据需求通过手动的方式实现租户过滤。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2020-09-24
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DisableTenantFilter {
|
||||
|
||||
/**
|
||||
* 包含的方法名称数组。该值不能为空,因为如想取消所有方法的租户过滤,
|
||||
* 可以通过在实体对象中不指定租户Id字段注解的方式实现。
|
||||
*
|
||||
* @return 被包括的方法名称数组。
|
||||
*/
|
||||
String[] includeMethodName();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.orange.demo.common.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 用于注解DAO层Mapper对象的数据权限规则。
|
||||
* 由于框架使用了tk.mapper,所以并非所有的Mapper接口均在当前Mapper对象中定义,有一部分被tk.mapper封装,如selectAll等。
|
||||
* 如果需要排除tk.mapper中的方法,可以直接使用tk.mapper基类所声明的方法名称即可。
|
||||
* 另外,比较特殊的场景是,因为tk.mapper是通用框架,所以同样的selectAll方法,可以获取不同的数据集合,因此在service中如果
|
||||
* 出现两个不同的方法调用Mapper的selectAll方法,但是一个需要参与过滤,另外一个不需要参与,那么就需要修改当前类的Mapper方法,
|
||||
* 将其中一个方法重新定义一个具体的接口方法,并重新设定其是否参与数据过滤。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2020-09-24
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface EnableDataPerm {
|
||||
|
||||
/**
|
||||
* 排除的方法名称数组。如果为空,所有的方法均会被Mybaits拦截注入权限过滤条件。
|
||||
*
|
||||
* @return 被排序的方法名称数据。
|
||||
*/
|
||||
String[] excluseMethodName() default {};
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.orange.demo.common.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 主要用于标记通过租户Id进行过滤的字段。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2020-09-24
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface TenantFilterColumn {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.orange.demo.common.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 主要用于标记数据权限中基于UserId进行过滤的字段。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2020-09-24
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface UserFilterColumn {
|
||||
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package com.orange.demo.common.core.cache;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.caffeine.CaffeineCache;
|
||||
import org.springframework.cache.support.SimpleCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 使用Caffeine作为本地缓存库
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2020-09-24
|
||||
*/
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public class CacheConfig {
|
||||
|
||||
private static final int DEFAULT_MAXSIZE = 10000;
|
||||
private static final int DEFAULT_TTL = 3600;
|
||||
|
||||
/**
|
||||
* 定义cache名称、超时时长秒、最大个数
|
||||
* 每个cache缺省3600秒过期,最大个数1000
|
||||
*/
|
||||
public enum CacheEnum {
|
||||
/**
|
||||
* 专门存储用户权限的缓存。
|
||||
*/
|
||||
USER_PERMISSION_CACHE(1800, 10000),
|
||||
/**
|
||||
* session下上传文件名的缓存(时间是24小时)。
|
||||
*/
|
||||
UPLOAD_FILENAME_CACHE(86400, 20000),
|
||||
/**
|
||||
* 缺省全局缓存(时间是24小时)。
|
||||
*/
|
||||
GLOBAL_CACHE(86400, 20000);
|
||||
|
||||
CacheEnum() {
|
||||
}
|
||||
|
||||
CacheEnum(int ttl, int maxSize) {
|
||||
this.ttl = ttl;
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存的最大数量。
|
||||
*/
|
||||
private int maxSize = DEFAULT_MAXSIZE;
|
||||
/**
|
||||
* 缓存的时长(单位:秒)
|
||||
*/
|
||||
private int ttl = DEFAULT_TTL;
|
||||
|
||||
public int getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
public int getTtl() {
|
||||
return ttl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化缓存配置。
|
||||
*/
|
||||
@Bean
|
||||
public CacheManager cacheManager() {
|
||||
SimpleCacheManager manager = new SimpleCacheManager();
|
||||
// 把各个cache注册到cacheManager中,CaffeineCache实现了org.springframework.cache.Cache接口
|
||||
ArrayList<CaffeineCache> caches = new ArrayList<>();
|
||||
for (CacheEnum c : CacheEnum.values()) {
|
||||
caches.add(new CaffeineCache(c.name(),
|
||||
Caffeine.newBuilder().recordStats()
|
||||
.expireAfterAccess(c.getTtl(), TimeUnit.SECONDS)
|
||||
.maximumSize(c.getMaxSize())
|
||||
.build())
|
||||
);
|
||||
}
|
||||
manager.setCaches(caches);
|
||||
return manager;
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
package com.orange.demo.common.core.cache;
|
||||
|
||||
import com.orange.demo.common.core.object.TokenData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Session数据缓存辅助类。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2020-09-24
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Component
|
||||
public class SessionCacheHelper {
|
||||
|
||||
@Autowired
|
||||
private CacheManager cacheManager;
|
||||
|
||||
/**
|
||||
* 缓存当前session内,上传过的文件名。
|
||||
*
|
||||
* @param filename 通常是本地存储的文件名,而不是上传时的原始文件名。
|
||||
*/
|
||||
public void putSessionUploadFile(String filename) {
|
||||
if (filename != null) {
|
||||
Set<String> sessionUploadFileSet = null;
|
||||
Cache cache = cacheManager.getCache(CacheConfig.CacheEnum.UPLOAD_FILENAME_CACHE.name());
|
||||
Cache.ValueWrapper valueWrapper = cache.get(TokenData.takeFromRequest().getSessionId());
|
||||
if (valueWrapper != null) {
|
||||
sessionUploadFileSet = (Set<String>) valueWrapper.get();
|
||||
}
|
||||
if (sessionUploadFileSet == null) {
|
||||
sessionUploadFileSet = new HashSet<>();
|
||||
}
|
||||
sessionUploadFileSet.add(filename);
|
||||
cache.put(TokenData.takeFromRequest().getSessionId(), sessionUploadFileSet);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断参数中的文件名,是否有当前session上传。
|
||||
*
|
||||
* @param filename 通常是本地存储的文件名,而不是上传时的原始文件名。
|
||||
* @return true表示该文件是由当前session上传并存储在本地的,否则false。
|
||||
*/
|
||||
public boolean existSessionUploadFile(String filename) {
|
||||
if (filename == null) {
|
||||
return false;
|
||||
}
|
||||
Cache cache = cacheManager.getCache(CacheConfig.CacheEnum.UPLOAD_FILENAME_CACHE.name());
|
||||
Cache.ValueWrapper valueWrapper = cache.get(TokenData.takeFromRequest().getSessionId());
|
||||
if (valueWrapper == null) {
|
||||
return false;
|
||||
}
|
||||
return ((Set<String>) valueWrapper.get()).contains(filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存放session的Token数据。
|
||||
*
|
||||
* @param sessionId 当前会话的SessionId。
|
||||
* @param tokenData 当前会话的JWT Token对象。
|
||||
*/
|
||||
public void putTokenData(String sessionId, TokenData tokenData) {
|
||||
if (sessionId == null || tokenData == null) {
|
||||
return;
|
||||
}
|
||||
Cache cache = cacheManager.getCache(CacheConfig.CacheEnum.GLOBAL_CACHE.name());
|
||||
cache.put(sessionId, tokenData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取session的JWT Token对象。
|
||||
*
|
||||
* @param sessionId 当前会话的SessionId。
|
||||
* @return 当前会话的JWT Token对象。
|
||||
*/
|
||||
public TokenData getTokenData(String sessionId) {
|
||||
Cache cache = cacheManager.getCache(CacheConfig.CacheEnum.GLOBAL_CACHE.name());
|
||||
return cache.get(sessionId, TokenData.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除当前session的所有缓存数据。
|
||||
*
|
||||
* @param sessionId 当前会话的SessionId。
|
||||
*/
|
||||
public void removeAllSessionCache(String sessionId) {
|
||||
for (CacheConfig.CacheEnum c : CacheConfig.CacheEnum.values()) {
|
||||
cacheManager.getCache(c.name()).evict(sessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -206,7 +206,7 @@ public class MyRequestArgumentResolver implements HandlerMethodArgumentResolver
|
||||
}
|
||||
}
|
||||
} else if (parameterType == Boolean.class) {
|
||||
return value.toString();
|
||||
return value;
|
||||
} else if (parameterType == Character.class) {
|
||||
return value.toString().charAt(0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.orange.demo.common.core.object;
|
||||
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
|
||||
/**
|
||||
* 线程本地化数据管理的工具类。可根据需求自行添加更多的线程本地化变量及其操作方法。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2020-09-24
|
||||
*/
|
||||
public class GlobalThreadLocal {
|
||||
|
||||
/**
|
||||
* 存储数据权限过滤是否启用的线程本地化对象。
|
||||
* 目前的过滤条件,包括数据权限和租户过滤。
|
||||
*/
|
||||
private static final ThreadLocal<Boolean> DATA_FILTER_ENABLE = ThreadLocal.withInitial(() -> Boolean.TRUE);
|
||||
|
||||
/**
|
||||
* 设置数据过滤是否打开。如果打开,当前Servlet线程所执行的SQL操作,均会进行数据过滤。
|
||||
*
|
||||
* @param enable 打开为true,否则false。
|
||||
* @return 返回之前的状态,便于恢复。
|
||||
*/
|
||||
public static boolean setDataFilter(boolean enable) {
|
||||
boolean oldValue = DATA_FILTER_ENABLE.get();
|
||||
DATA_FILTER_ENABLE.set(enable);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前Servlet线程所执行的SQL操作,是否进行数据过滤。
|
||||
*
|
||||
* @return true 进行数据权限过滤,否则false。
|
||||
*/
|
||||
public static boolean enabledDataFilter() {
|
||||
return BooleanUtil.isTrue(DATA_FILTER_ENABLE.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空该存储数据,主动释放线程本地化存储资源。
|
||||
*/
|
||||
public static void clearDataFilter() {
|
||||
DATA_FILTER_ENABLE.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private GlobalThreadLocal() {
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,16 @@ public class TokenData {
|
||||
* 用户Id。
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 用户所在部门Id。
|
||||
* 仅当系统支持uaa时可用,否则可以直接忽略该字段。保留该字段是为了保持单体和微服务通用代码部分的兼容性。
|
||||
*/
|
||||
private Long deptId;
|
||||
/**
|
||||
* 租户Id。
|
||||
* 仅当系统支持uaa时可用,否则可以直接忽略该字段。保留该字段是为了保持单体和微服务通用代码部分的兼容性。
|
||||
*/
|
||||
private Long tenantId;
|
||||
/**
|
||||
* 是否为超级管理员。
|
||||
*/
|
||||
@@ -36,6 +46,11 @@ public class TokenData {
|
||||
* 标识不同登录的会话Id。
|
||||
*/
|
||||
private String sessionId;
|
||||
/**
|
||||
* 访问uaa的授权token。
|
||||
* 仅当系统支持uaa时可用,否则可以直接忽略该字段。保留该字段是为了保持单体和微服务通用代码部分的兼容性。
|
||||
*/
|
||||
private String uaaAccessToken;
|
||||
|
||||
/**
|
||||
* 将令牌对象添加到Http请求对象。
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.orange.demo.common.core.util;
|
||||
|
||||
/**
|
||||
* Redis 键生成工具类。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2020-09-24
|
||||
*/
|
||||
public class RedisKeyUtil {
|
||||
|
||||
/**
|
||||
* 计算SessionId关联的权限数据存储于Redis中的键。
|
||||
*
|
||||
* @param sessionId 会话Id。
|
||||
* @return 会话关联的权限数据存储于Redis中的键值。
|
||||
*/
|
||||
public static String makeSessionPermIdKeyForRedis(String sessionId) {
|
||||
return "PERM__" + sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算SessionId关联的数据权限数据存储于Redis中的键。
|
||||
*
|
||||
* @param sessionId 会话Id。
|
||||
* @return 会话关联的数据权限数据存储于Redis中的键值。
|
||||
*/
|
||||
public static String makeSessionDataPermIdKeyForRedis(String sessionId) {
|
||||
return "DATA_PERM__" + sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private RedisKeyUtil() {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user