🎉 4.8.0.RELEASE 新增接口权限模块,增强系统安全性

This commit is contained in:
smallchill 2026-01-15 01:31:35 +08:00
parent 92770ff35e
commit 80a2844c4a
15 changed files with 445 additions and 215 deletions

View File

@ -1,14 +1,9 @@
<p align="center">
<img src="https://img.shields.io/badge/Release-V4.8.0-blue.svg" alt="Downloads">
<img src="https://img.shields.io/badge/JDK-17+-green.svg" alt="Build Status">
<img src="https://img.shields.io/badge/license-LGPL%20v3-blue.svg" alt="Build Status">
<img src="https://img.shields.io/badge/Spring%20Cloud-2025-blue.svg" alt="Coverage Status">
<img src="https://img.shields.io/badge/Spring%20Boot-3.5-blue.svg" alt="Downloads">
<a href="https://central.sonatype.com/artifact/org.springblade/blade-core-bom/versions">
<img src="https://img.shields.io/nexus/r/https/oss.sonatype.org/org.springblade/blade-core-bom.svg?style=flat-square" alt="Downloads">
</a>
<a href="https://oss.sonatype.org/content/repositories/snapshots/org/springblade/blade-core-bom/">
<img src="https://img.shields.io/nexus/s/https/oss.sonatype.org/org.springblade/blade-core-bom.svg?style=flat-square" alt="Downloads">
</a>
<br/>
<a target="_blank" href="https://bladex.cn">
<img src="https://img.shields.io/badge/Author-Small%20Chill-ff69b4.svg" alt="Downloads">
@ -39,15 +34,14 @@
|----------------------|------------|
| Java | 17+ |
| NodeJS | 18+ |
| Spring | 6.2.11 |
| Spring Boot | 3.5.6 |
| Spring Cloud | 2025.0.0 |
| Spring Cloud Alibaba | 2023.0.3.3 |
| Nacos Alibaba | 3.1.0 |
| Spring | 6.2.15 |
| Spring Boot | 3.5.9 |
| Spring Cloud | 2025.0.1 |
| Spring Cloud Alibaba | 2025.0.0.0 |
| Nacos Alibaba | 3.1.1 |
| Mybatis Plus | 3.5.19 |
## 工程结构
```
blade-tool
@ -93,20 +87,20 @@ blade-tool
## 官方产品
| 简介 | 演示地址 |
|---------------|------------------------------------------------------|
| BladeX企业级开发平台 | [https://saber3.bladex.cn](https://saber3.bladex.cn) |
| BladeX可视化数据大屏 | [https://data.bladex.cn](https://data.bladex.cn) |
| BladeX物联网开发平台 | [https://iot.bladex.cn](https://iot.bladex.cn) |
| BladeX大模型开发平台 | [https://ai.bladex.cn](https://ai.bladex.cn) |
| 简介 | 演示地址 |
|-----------------|------------------------------------------------------|
| BladeX企业级开发平台 | [https://saber3.bladex.cn](https://saber3.bladex.cn) |
| BladeX可视化数据大屏 | [https://data.bladex.cn](https://data.bladex.cn) |
| BladeX物联网开发平台 | [https://iot.bladex.cn](https://iot.bladex.cn) |
| BladeXAI大模型平台 | [https://ai.bladex.cn/](https://ai.bladex.cn/) |
## 前端项目
| 简介 | 地址 |
|--------------------|----------------------------------------------------------------------------------------------------|
| 前端框架Sword(基于React) | [https://gitee.com/smallc/Sword](https://gitee.com/smallc/Sword) |
| 前端框架Saber(基于Vue2) | [https://gitee.com/smallc/Saber](https://gitee.com/smallc/Saber) |
| 前端框架Saber3(基于Vue3) | [https://gitee.com/smallc/Saber3](https://gitee.com/smallc/Saber/tree/3.x/) |
| 简介 | 地址 |
|--------------------|------------------------------------------------------------------------------|
| 前端框架Saber3(基于Vue3) | [https://gitee.com/smallc/Saber3](https://gitee.com/smallc/Saber) |
| 前端框架Saber(基于Vue2) | [https://gitee.com/smallc/Saber2](https://gitee.com/smallc/Saber/tree/vue2/) |
| 前端框架Sword(基于React) | [https://gitee.com/smallc/Sword](https://gitee.com/smallc/Sword) |
## 后端项目
| 简介 | 地址 |

View File

@ -44,7 +44,6 @@
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>${spring.boot.admin.version}</version>
</dependency>
<!-- Nacos -->
<dependency>

View File

@ -33,6 +33,10 @@
<groupId>org.springblade</groupId>
<artifactId>blade-core-tool</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-cache</artifactId>
</dependency>
<!--Jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -15,10 +15,34 @@
*/
package org.springblade.core.secure.annotation;
import org.springblade.core.tool.utils.StringPool;
import java.lang.annotation.*;
/**
* 权限注解 用于检查权限 规定访问权限
* 权限注解用于检查权限规定访问权限
* 支持以下几种使用方式
* <p>
* 1. 单个属性模式
* <pre>{@code
* @PreAuth(permission = "user:add")
* @PreAuth(role = "admin")
* }</pre>
*
* 2. 组合属性模式
* <pre>{@code
* @PreAuth(role = "admin", permission = "user:add")
* }</pre>
*
* 3. SpEL表达式模式
* <pre>{@code
* @PreAuth("#userVO.id<10")
* @PreAuth("hasRole('admin')")
* @PreAuth("hasPermission('user:add')")
* @PreAuth("hasPermission(#test) and hasRole('admin')")
* }</pre>
*
* @author Chill
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@ -27,10 +51,19 @@ import java.lang.annotation.*;
public @interface PreAuth {
/**
* Spring el
* 文档地址https://docs.spring.io/spring/docs/4.3.16.RELEASE/spring-framework-reference/htmlsingle/#expressions-operators-logical
* Spring el表达式
*/
String value();
String value() default StringPool.EMPTY;
/**
* 接口权限编码
*/
String permission() default StringPool.EMPTY;
/**
* 角色权限
*/
String role() default StringPool.EMPTY;
}

View File

@ -15,6 +15,8 @@
*/
package org.springblade.core.secure.aspect;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@ -22,6 +24,7 @@ import org.aspectj.lang.reflect.MethodSignature;
import org.springblade.core.secure.annotation.PreAuth;
import org.springblade.core.secure.auth.AuthFun;
import org.springblade.core.secure.exception.SecureException;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.ResultCode;
import org.springblade.core.tool.utils.ClassUtil;
import org.springblade.core.tool.utils.StringUtil;
@ -34,6 +37,7 @@ import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.lang.NonNull;
import java.lang.reflect.Method;
@ -42,13 +46,20 @@ import java.lang.reflect.Method;
*
* @author Chill
*/
@Slf4j
@Aspect
@RequiredArgsConstructor
public class AuthAspect implements ApplicationContextAware {
/**
* 权限处理函数
*/
private final AuthFun authFun;
/**
* 表达式处理
*/
private static final ExpressionParser SPEL_PARSER = new SpelExpressionParser();
private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
/**
* 方法 类上的 @PreAuth 注解
@ -74,20 +85,30 @@ public class AuthAspect implements ApplicationContextAware {
* @param point 切点
*/
private boolean handleAuth(ProceedingJoinPoint point) {
// 读取权限注解优先方法上没有则读取类
MethodSignature ms = (MethodSignature) point.getSignature();
Method method = ms.getMethod();
// 读取权限注解优先方法上没有则读取类
PreAuth preAuth = ClassUtil.getAnnotation(method, PreAuth.class);
// 处理接口权限属性验证
if (StringUtil.isNotBlank(preAuth.permission()) && !authFun.hasPermission(preAuth.permission())) {
return false;
}
// 处理角色权限属性验证
if (StringUtil.isNotBlank(preAuth.role()) && !authFun.hasRole(preAuth.role())) {
return false;
}
// 判断表达式
String condition = preAuth.value();
if (StringUtil.isNotBlank(condition)) {
Expression expression = SPEL_PARSER.parseExpression(condition);
Expression expression = EXPRESSION_PARSER.parseExpression(condition);
// 方法参数值
Object[] args = point.getArgs();
StandardEvaluationContext context = getEvaluationContext(method, args);
return expression.getValue(context, Boolean.class);
return Boolean.TRUE.equals(expression.getValue(context, Boolean.class));
} else {
// 判断用户是否通过鉴权
return AuthUtil.hasAuth();
}
return false;
}
/**
@ -99,7 +120,7 @@ public class AuthAspect implements ApplicationContextAware {
*/
private StandardEvaluationContext getEvaluationContext(Method method, Object[] args) {
// 初始化Sp el表达式上下文并设置 AuthFun
StandardEvaluationContext context = new StandardEvaluationContext(new AuthFun());
StandardEvaluationContext context = new StandardEvaluationContext(authFun);
// 设置表达式支持spring bean
context.setBeanResolver(new BeanFactoryResolver(applicationContext));
for (int i = 0; i < args.length; i++) {
@ -114,7 +135,7 @@ public class AuthAspect implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}

View File

@ -15,15 +15,15 @@
*/
package org.springblade.core.secure.auth;
import jakarta.servlet.http.HttpServletRequest;
import org.springblade.core.launch.constant.TokenConstant;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.handler.IPermissionHandler;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.secure.utils.SecureUtil;
import org.springblade.core.tool.constant.RoleConstant;
import org.springblade.core.tool.utils.CollectionUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springblade.core.tool.utils.*;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Objects;
/**
@ -33,6 +33,37 @@ import java.util.Objects;
*/
public class AuthFun {
/**
* 权限校验处理器
*/
private static IPermissionHandler permissionHandler;
private static IPermissionHandler getPermissionHandler() {
if (permissionHandler == null) {
permissionHandler = SpringUtil.getBean(IPermissionHandler.class);
}
return permissionHandler;
}
/**
* 判断角色是否具有接口权限全量校验
*
* @return {boolean}
*/
public boolean permissionAll() {
return getPermissionHandler().permissionAll();
}
/**
* 判断角色是否具有接口权限
*
* @param permission 权限编号
* @return {boolean}
*/
public boolean hasPermission(String permission) {
return getPermissionHandler().hasPermission(permission);
}
/**
* 放行所有请求
*
@ -51,6 +82,27 @@ public class AuthFun {
return hasRole(RoleConstant.ADMIN);
}
/**
* 是否已授权
*
* @return {boolean}
*/
public boolean hasAuth() {
return AuthUtil.hasAuth();
}
/**
* 是否有时间授权
*
* @param start 开始时间
* @param end 结束时间
* @return {boolean}
*/
public boolean hasTimeAuth(Integer start, Integer end) {
Integer hour = DateUtil.hour();
return hour >= start && hour <= end;
}
/**
* 判断是否有该角色权限
*
@ -61,6 +113,21 @@ public class AuthFun {
return hasAnyRole(role);
}
/**
* 判断是否具有所有角色权限
*
* @param role 角色集合
* @return {boolean}
*/
public boolean hasAllRole(String... role) {
for (String r : role) {
if (!hasRole(r)) {
return false;
}
}
return true;
}
/**
* 判断是否有该角色权限
*
@ -68,7 +135,11 @@ public class AuthFun {
* @return {boolean}
*/
public boolean hasAnyRole(String... role) {
String userRole = SecureUtil.getUser().getRoleName();
BladeUser user = AuthUtil.getUser();
if (user == null) {
return false;
}
String userRole = user.getRoleName();
if (StringUtil.isBlank(userRole)) {
return false;
}
@ -94,4 +165,29 @@ public class AuthFun {
);
}
/**
* 判断是否有该请求头
*
* @param header 请求头
* @return {boolean}
*/
public boolean hasHeader(String header) {
HttpServletRequest request = WebUtil.getRequest();
String value = Objects.requireNonNull(request).getHeader(header);
return StringUtil.isNotBlank(value);
}
/**
* 判断是否有该请求头
*
* @param header 请求头
* @param key 请求值
* @return {boolean}
*/
public boolean hasHeader(String header, String key) {
HttpServletRequest request = WebUtil.getRequest();
String value = Objects.requireNonNull(request).getHeader(header);
return StringUtil.equals(value, key);
}
}

View File

@ -18,6 +18,9 @@ package org.springblade.core.secure.config;
import lombok.AllArgsConstructor;
import org.springblade.core.secure.aspect.AuthAspect;
import org.springblade.core.secure.auth.AuthFun;
import org.springblade.core.secure.handler.BladePermissionHandler;
import org.springblade.core.secure.handler.IPermissionHandler;
import org.springblade.core.secure.interceptor.ClientInterceptor;
import org.springblade.core.secure.interceptor.SecureInterceptor;
import org.springblade.core.secure.props.BladeAuthProperties;
@ -66,7 +69,13 @@ public class SecureConfiguration implements WebMvcConfigurer {
@Bean
public AuthAspect authAspect() {
return new AuthAspect();
return new AuthAspect(new AuthFun());
}
@Bean
@ConditionalOnMissingBean(IPermissionHandler.class)
public IPermissionHandler permissionHandler() {
return new BladePermissionHandler(jdbcTemplate);
}
@Bean

View File

@ -0,0 +1,58 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.core.secure.constant;
import org.springblade.core.tool.utils.StringUtil;
/**
* 权限校验常量
*
* @author Chill
*/
public interface PermissionConstant {
/**
* 获取角色所有的权限编号
*
* @param size 数量
* @return string
*/
static String permissionAllStatement(int size) {
return StringUtil.format("select scope_path as path from blade_scope_api where id in (select scope_id from blade_role_scope where scope_category = 2 and role_id in ({}))", buildHolder(size));
}
/**
* 获取角色指定的权限编号
*
* @param size 数量
* @return string
*/
static String permissionCodeStatement(int size) {
return StringUtil.format("select resource_code as code from blade_scope_api where resource_code = ? and id in (select scope_id from blade_role_scope where scope_category = 2 and role_id in ({}))", buildHolder(size));
}
/**
* 获取Sql占位符
*
* @param size 数量
* @return String
*/
static String buildHolder(int size) {
StringBuilder builder = StringUtil.builder().append("?,".repeat(Math.max(0, size)));
return StringUtil.removeSuffix(builder.toString(), ",");
}
}

View File

@ -0,0 +1,112 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.core.secure.handler;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.springblade.core.secure.constant.PermissionConstant.permissionAllStatement;
import static org.springblade.core.secure.constant.PermissionConstant.permissionCodeStatement;
import static org.springblade.core.cache.utils.CacheUtil.SYS_CACHE;
/**
* 默认授权校验类
*
* @author Chill
*/
@AllArgsConstructor
public class BladePermissionHandler implements IPermissionHandler {
private static final String SCOPE_CACHE_ROLE = "apiScope:role:";
private static final String SCOPE_CACHE_CODE = "apiScope:code:";
private final JdbcTemplate jdbcTemplate;
@Override
public boolean permissionAll() {
HttpServletRequest request = WebUtil.getRequest();
BladeUser user = AuthUtil.getUser();
if (request == null || user == null) {
return false;
}
String uri = request.getRequestURI();
List<String> paths = permissionPath(user.getRoleId());
if (paths.isEmpty()) {
return false;
}
return paths.stream().anyMatch(uri::contains);
}
@Override
public boolean hasPermission(String permission) {
HttpServletRequest request = WebUtil.getRequest();
BladeUser user = AuthUtil.getUser();
if (request == null || user == null) {
return false;
}
List<String> codes = permissionCode(permission, user.getRoleId());
return !codes.isEmpty();
}
/**
* 获取接口权限地址
*
* @param roleId 角色id
* @return permissions
*/
private List<String> permissionPath(String roleId) {
List<String> permissions = CacheUtil.get(SYS_CACHE, SCOPE_CACHE_ROLE, roleId, List.class);
if (permissions == null) {
List<Long> roleIds = Func.toLongList(roleId);
permissions = jdbcTemplate.queryForList(permissionAllStatement(roleIds.size()), String.class, roleIds.toArray());
CacheUtil.put(SYS_CACHE, SCOPE_CACHE_ROLE, roleId, permissions);
}
return permissions;
}
/**
* 获取接口权限信息
*
* @param permission 权限编号
* @param roleId 角色id
* @return permissions
*/
private List<String> permissionCode(String permission, String roleId) {
String cacheKey = permission + StringPool.COLON + roleId;
List<String> permissions = CacheUtil.get(SYS_CACHE, SCOPE_CACHE_CODE, cacheKey, List.class);
if (permissions == null) {
List<Object> args = new ArrayList<>(Collections.singletonList(permission));
List<Long> roleIds = Func.toLongList(roleId);
args.addAll(roleIds);
permissions = jdbcTemplate.queryForList(permissionCodeStatement(roleIds.size()), String.class, args.toArray());
CacheUtil.put(SYS_CACHE, SCOPE_CACHE_CODE, cacheKey, permissions);
}
return permissions;
}
}

View File

@ -0,0 +1,41 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.core.secure.handler;
/**
* 权限校验通用接口
*
* @author Chill
*/
public interface IPermissionHandler {
/**
* 判断角色是否具有接口权限全量校验
*
* @return {boolean}
*/
boolean permissionAll();
/**
* 判断角色是否具有接口权限
*
* @param permission 权限编号
* @return {boolean}
*/
boolean hasPermission(String permission);
}

View File

@ -303,6 +303,15 @@ public class SecureUtil {
return (null == user) ? StringPool.EMPTY : user.getClientId();
}
/**
* 是否已授权
*
* @return boolean
*/
public static boolean hasAuth() {
return getUser() != null;
}
/**
* 获取Claims
*

View File

@ -1,170 +0,0 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.core.tool.utils;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.lang.Nullable;
import java.util.concurrent.Callable;
/**
* 缓存工具类
*
* @author Chill
* @deprecated in favor of {org.springblade.core.cache.utils.CacheUtil}.
*/
@Deprecated
public class CacheUtil {
public static final String SYS_CACHE = "blade:sys";
private static CacheManager cacheManager;
/**
* 获取缓存工具
*
* @return CacheManager
*/
private static CacheManager getCacheManager() {
if (cacheManager == null) {
cacheManager = SpringUtil.getBean(CacheManager.class);
}
return cacheManager;
}
/**
* 获取缓存对象
*
* @param cacheName 缓存名
* @return Cache
*/
public static Cache getCache(String cacheName) {
return getCacheManager().getCache(cacheName);
}
/**
* 获取缓存
*
* @param cacheName 缓存名
* @param keyPrefix 缓存键前缀
* @param key 缓存键值
* @return Cache
*/
@Nullable
public static Object get(String cacheName, String keyPrefix, Object key) {
if (Func.hasEmpty(cacheName, keyPrefix, key)) {
return null;
}
Cache.ValueWrapper wrapper = getCache(cacheName).get(keyPrefix.concat(String.valueOf(key)));
return wrapper == null ? null : wrapper.get();
}
/**
* 获取缓存
*
* @param cacheName 缓存名
* @param keyPrefix 缓存键前缀
* @param key 缓存键值
* @param type 转换类型
* @param <T> 类型
* @return Cache
*/
@Nullable
public static <T> T get(String cacheName, String keyPrefix, Object key, @Nullable Class<T> type) {
if (Func.hasEmpty(cacheName, keyPrefix, key)) {
return null;
}
return getCache(cacheName).get(keyPrefix.concat(String.valueOf(key)), type);
}
/**
* 获取缓存
*
* @param cacheName 缓存名
* @param keyPrefix 缓存键前缀
* @param key 缓存键值
* @param valueLoader 重载对象
* @param <T> 类型
* @return Cache
*/
@Nullable
public static <T> T get(String cacheName, String keyPrefix, Object key, Callable<T> valueLoader) {
if (Func.hasEmpty(cacheName, keyPrefix, key)) {
return null;
}
final String fullKey = keyPrefix.concat(String.valueOf(key));
Cache cache = getCache(cacheName);
Cache.ValueWrapper valueWrapper = cache.get(fullKey);
if (valueWrapper != null) {
return (T) valueWrapper.get();
}
try {
T value = valueLoader.call();
if (value == null) {
return null;
}
cache.put(fullKey, value);
return value;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
/**
* 设置缓存
*
* @param cacheName 缓存名
* @param keyPrefix 缓存键前缀
* @param key 缓存键值
* @param value 缓存值
*/
public static void put(String cacheName, String keyPrefix, Object key, @Nullable Object value) {
getCache(cacheName).put(keyPrefix.concat(String.valueOf(key)), value);
}
/**
* 清除缓存
*
* @param cacheName 缓存名
* @param keyPrefix 缓存键前缀
* @param key 缓存键值
*/
public static void evict(String cacheName, String keyPrefix, Object key) {
if (Func.hasEmpty(cacheName, keyPrefix, key)) {
return;
}
getCache(cacheName).evict(keyPrefix.concat(String.valueOf(key)));
}
/**
* 清空缓存
*
* @param cacheName 缓存名
*/
public static void clear(String cacheName) {
if (Func.isEmpty(cacheName)) {
return;
}
getCache(cacheName).clear();
}
}

View File

@ -597,4 +597,13 @@ public class DateUtil {
return format(LocalDate.now(), "yyyyMMdd");
}
/**
* 获取当前小时
*
* @return 当前小时 (0-23)
*/
public static Integer hour() {
return LocalDateTime.now().getHour();
}
}

View File

@ -16,9 +16,13 @@
package org.springblade.core.datascope.handler;
import lombok.RequiredArgsConstructor;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.datascope.constant.DataScopeConstant;
import org.springblade.core.datascope.model.DataScopeModel;
import org.springblade.core.tool.utils.*;
import org.springblade.core.tool.utils.CollectionUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
@ -26,7 +30,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.springblade.core.tool.utils.CacheUtil.SYS_CACHE;
import static org.springblade.core.cache.utils.CacheUtil.SYS_CACHE;
/**

13
pom.xml
View File

@ -36,7 +36,7 @@
<properties>
<!-- Blade-Tool Version -->
<revision>4.7.1-SNAPSHOT</revision>
<revision>4.8.0</revision>
<module.name>org.springblade.blade.tool</module.name>
<!-- jdk Version -->
<java.version>17</java.version>
@ -256,6 +256,17 @@
<artifactId>blade-starter-api-crypto</artifactId>
<version>${revision}</version>
</dependency>
<!-- Admin -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>${spring.boot.admin.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>${spring.boot.admin.version}</version>
</dependency>
<!-- common -->
<dependency>
<groupId>org.apache.commons</groupId>