JeecgBoot2.4.3版本发布——企业级低代码平台

This commit is contained in:
zhangdaiscott
2021-03-17 18:43:42 +08:00
parent 47ea38038d
commit 76e7ee6c09
131 changed files with 3851 additions and 43841 deletions

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>jeecg-boot-base-api</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>2.4.2</version>
<version>2.4.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@ -140,7 +141,7 @@ public interface ISysBaseAPI extends CommonAPI {
* 15根据业务类型 busType 及业务 busId 修改消息已读
*/
@GetMapping("/sys/api/updateSysAnnounReadFlag")
public void updateSysAnnounReadFlag(@RequestParam("busType") String busType, @RequestParam("busId") String busId);
public void updateSysAnnounReadFlag(@RequestParam("busType") String busType, @RequestParam("busId")String busId);
/**
* 16查询表字典 支持过滤数据
@ -177,7 +178,7 @@ public interface ISysBaseAPI extends CommonAPI {
* @return
*/
@GetMapping("/sys/api/queryAllUser")
public JSONObject queryAllUser(@RequestParam(name = "userIds", required = false) String userIds, @RequestParam(name = "pageNo", required = false) Integer pageNo, @RequestParam(name = "pageSize", required = false) int pageSize);
public JSONObject queryAllUser(@RequestParam(name="userIds",required=false)String userIds, @RequestParam(name="pageNo",required=false) Integer pageNo,@RequestParam(name="pageSize",required=false) int pageSize);
/**
@ -186,7 +187,7 @@ public interface ISysBaseAPI extends CommonAPI {
* @return
*/
@GetMapping("/sys/api/queryAllRole")
public List<ComboModel> queryAllRole(@RequestParam(name = "roleIds", required = false) String[] roleIds);
public List<ComboModel> queryAllRole(@RequestParam(name = "roleIds",required = false)String[] roleIds);
/**
* 21通过用户账号查询角色Id集合
@ -194,7 +195,7 @@ public interface ISysBaseAPI extends CommonAPI {
* @return
*/
@GetMapping("/sys/api/getRoleIdsByUsername")
public List<String> getRoleIdsByUsername(@RequestParam("username") String username);
public List<String> getRoleIdsByUsername(@RequestParam("username")String username);
/**
* 22通过部门编号查询部门id
@ -202,7 +203,7 @@ public interface ISysBaseAPI extends CommonAPI {
* @return
*/
@GetMapping("/sys/api/getDepartIdsByOrgCode")
public String getDepartIdsByOrgCode(@RequestParam("orgCode") String orgCode);
public String getDepartIdsByOrgCode(@RequestParam("orgCode")String orgCode);
/**
* 23查询所有部门
@ -217,7 +218,7 @@ public interface ISysBaseAPI extends CommonAPI {
* @return
*/
@GetMapping("/sys/api/getParentDepartId")
DictModel getParentDepartId(@RequestParam("departId") String departId);
DictModel getParentDepartId(@RequestParam("departId")String departId);
/**
* 25根据部门Id获取部门负责人
@ -233,7 +234,7 @@ public interface ISysBaseAPI extends CommonAPI {
* @param cmd
*/
@GetMapping("/sys/api/sendWebSocketMsg")
public void sendWebSocketMsg(@RequestParam("userIds") String[] userIds, @RequestParam("cmd") String cmd);
public void sendWebSocketMsg(@RequestParam("userIds")String[] userIds, @RequestParam("cmd") String cmd);
/**
* 27根据id获取所有参与用户
@ -250,7 +251,7 @@ public interface ISysBaseAPI extends CommonAPI {
* @param userId
*/
@GetMapping("/sys/api/meetingSignWebsocket")
void meetingSignWebsocket(@RequestParam("userId") String userId);
void meetingSignWebsocket(@RequestParam("userId")String userId);
/**
* 29根据name获取所有参与用户
@ -258,7 +259,7 @@ public interface ISysBaseAPI extends CommonAPI {
* @return
*/
@GetMapping("/sys/api/queryUserByNames")
List<LoginUser> queryUserByNames(@RequestParam("userNames") String[] userNames);
List<LoginUser> queryUserByNames(@RequestParam("userNames")String[] userNames);
/**
@ -267,7 +268,7 @@ public interface ISysBaseAPI extends CommonAPI {
* @return
*/
@GetMapping("/sys/api/getUserRoleSet")
Set<String> getUserRoleSet(@RequestParam("username") String username);
Set<String> getUserRoleSet(@RequestParam("username")String username);
/**
* 31获取用户的权限集合
@ -308,7 +309,7 @@ public interface ISysBaseAPI extends CommonAPI {
* @return
*/
@GetMapping("/sys/api/queryUserRoles")
Set<String> queryUserRoles(@RequestParam("username") String username);
Set<String> queryUserRoles(@RequestParam("username")String username);
/**
* 36查询用户权限信息
@ -316,7 +317,7 @@ public interface ISysBaseAPI extends CommonAPI {
* @return
*/
@GetMapping("/sys/api/queryUserAuths")
Set<String> queryUserAuths(@RequestParam("username") String username);
Set<String> queryUserAuths(@RequestParam("username")String username);
/**
* 37根据 id 查询数据库中存储的 DynamicDataSourceModel
@ -368,7 +369,7 @@ public interface ISysBaseAPI extends CommonAPI {
* @return
*/
@GetMapping("/sys/api/queryPermissionDataRule")
List<SysPermissionDataRuleModel> queryPermissionDataRule(@RequestParam("component") String component, @RequestParam("requestPath") String requestPath, @RequestParam("username") String username);
List<SysPermissionDataRuleModel> queryPermissionDataRule(@RequestParam("component") String component, @RequestParam("requestPath")String requestPath, @RequestParam("username") String username);
/**
* 43查询用户信息
@ -408,7 +409,7 @@ public interface ISysBaseAPI extends CommonAPI {
*/
@GetMapping("/sys/api/queryDepartsByOrgIds")
List<JSONObject> queryDepartsByOrgIds(String ids);
/**
* 40发送邮件消息
* @param email
@ -416,5 +417,11 @@ public interface ISysBaseAPI extends CommonAPI {
* @param content
*/
@GetMapping("/sys/api/sendEmailMsg")
void sendEmailMsg(@RequestParam("email") String email, @RequestParam("title") String title, @RequestParam("content") String content);
void sendEmailMsg(@RequestParam("email")String email,@RequestParam("title")String title,@RequestParam("content")String content);
/**
* 41 获取公司下级部门和公司下所有用户id
* @param orgCode
*/
@GetMapping("/sys/api/getDeptUserByOrgCode")
List<Map> getDeptUserByOrgCode(@RequestParam("orgCode")String orgCode);
}

View File

@ -9,6 +9,7 @@ import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.vo.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@ -259,6 +260,11 @@ public class SysBaseAPIFallback implements ISysBaseAPI {
}
@Override
public List<Map> getDeptUserByOrgCode(String orgCode) {
return null;
}
@Override
public List<JSONObject> queryDepartsByOrgIds(String ids) {
return null;

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>jeecg-boot-base-api</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>2.4.2</version>
<version>2.4.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -1,12 +1,16 @@
package org.jeecg.common.system.api;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.api.dto.OnlineAuthDTO;
import org.jeecg.common.api.dto.message.*;
import org.jeecg.common.system.vo.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@ -280,5 +284,9 @@ public interface ISysBaseAPI extends CommonAPI {
* @param content
*/
void sendEmailMsg(String email,String title,String content);
/**
* 41 获取公司下级部门和公司下所有用户信息
* @param orgCode
*/
List<Map> getDeptUserByOrgCode(String orgCode);
}

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>jeecg-boot-base</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>2.4.2</version>
<version>2.4.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-base</artifactId>
<version>2.4.2</version>
<version>2.4.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -101,6 +101,21 @@
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>${dynamic-datasource-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<exclusions>
<exclusion>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>hibernate-re</artifactId>
<version>2.4.3-RC</version>
</dependency>
<!--mysql-->
<dependency>
@ -150,21 +165,6 @@
<artifactId>shiro-spring-boot-starter</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>hibernate-re</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<exclusions>
<exclusion>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- shiro-redis -->
<dependency>
<groupId>org.crazycake</groupId>
@ -185,16 +185,6 @@
<version>${knife4j-spring-boot-starter.version}</version>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- 代码生成器 -->
<!-- 如下载失败,请参考此文档 http://doc.jeecg.com/2043876 -->
<dependency>

View File

@ -70,7 +70,7 @@ public class PermissionDataAspect {
String url = "";
if(oConvertUtils.isNotEmpty(requestPath)){
url = requestPath.replace("\\", "/");
url = requestPath.replace("//", "/");
url = url.replace("//", "/");
if(url.indexOf("//")>=0){
url = filterUrl(url);
}

View File

@ -265,7 +265,7 @@ public interface CommonConstant {
/**
* 在线聊天 用户好友缓存前缀
*/
public static final String IM_PREFIX_USER_FRIEND_CACHE = "im_prefix_user_friend_";
public static final String IM_PREFIX_USER_FRIEND_CACHE = "sys:cache:im:im_prefix_user_friend_";
/**
* 考勤补卡业务状态 1同意 2不同意
@ -294,7 +294,7 @@ public interface CommonConstant {
/**
* 多租户 请求头
*/
public final static String TENANT_ID = "tenant_id";
public final static String TENANT_ID = "tenant-id";
/**
* 微服务读取配置文件属性 服务地址

View File

@ -12,6 +12,8 @@ public interface CommonSendStatus {
public static final String PUBLISHED_STATUS_1 = "1"; //已发布
public static final String REVOKE_STATUS_2 = "2"; //撤销
//app端推送会话标识后缀
public static final String APP_SESSION_SUFFIX = "_app"; //app端推送会话标识后缀

View File

@ -6,6 +6,7 @@ public interface DataBaseConstant {
//*********数据库类型****************************************
public static final String DB_TYPE_MYSQL = "MYSQL";
public static final String DB_TYPE_ORACLE = "ORACLE";
public static final String DB_TYPE_DM = "DM";//达梦数据库
public static final String DB_TYPE_POSTGRESQL = "POSTGRESQL";
public static final String DB_TYPE_SQLSERVER = "SQLSERVER";

View File

@ -1,6 +1,8 @@
package org.jeecg.common.system.base.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;
@ -13,6 +15,7 @@ import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -23,9 +26,7 @@ import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -76,6 +77,55 @@ public class JeecgController<T, S extends IService<T>> {
mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
return mv;
}
/**
* 根据每页sheet数量导出多sheet
*
* @param request
* @param object 实体类
* @param clazz 实体类class
* @param title 标题
* @param exportFields 导出字段自定义
* @param pageNum 每个sheet的数据条数
* @param request
*/
protected ModelAndView exportXlsSheet(HttpServletRequest request, T object, Class<T> clazz, String title,String exportFields,Integer pageNum) {
// Step.1 组装查询条件
QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
// Step.2 计算分页sheet数据
double total = service.count();
int count = (int)Math.ceil(total/pageNum);
// Step.3 多sheet处理
List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>();
for (int i = 1; i <=count ; i++) {
Page<T> page = new Page<T>(i, pageNum);
IPage<T> pageList = service.page(page, queryWrapper);
List<T> records = pageList.getRecords();
List<T> exportList = null;
// 过滤选中数据
String selections = request.getParameter("selections");
if (oConvertUtils.isNotEmpty(selections)) {
List<String> selectionList = Arrays.asList(selections.split(","));
exportList = records.stream().filter(item -> selectionList.contains(getId(item))).collect(Collectors.toList());
} else {
exportList = records;
}
Map<String, Object> map = new HashMap<String, Object>();
ExportParams exportParams=new ExportParams(title + "报表", "导出人:" + sysUser.getRealname(), title+i,upLoadPath);
exportParams.setType(ExcelType.XSSF);
//map.put("title",exportParams);//表格Title
map.put(NormalExcelConstants.PARAMS,exportParams);//表格Title
map.put(NormalExcelConstants.CLASS,clazz);//表格对应实体
map.put(NormalExcelConstants.DATA_LIST, exportList);//数据集合
listMap.add(map);
}
// Step.4 AutoPoi 导出Excel
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
mv.addObject(NormalExcelConstants.FILE_NAME, title); //此处设置的filename无效 ,前端会重更新设置一下
mv.addObject(NormalExcelConstants.MAP_LIST, listMap);
return mv;
}
/**
* 根据权限导出excel传入导出字段参数

View File

@ -72,7 +72,7 @@ public class WebMvcConfiguration implements WebMvcConfigurer {
}
/**
* 添加Long转json精度丢失配置
* 添加Long转json精度丢失配置
* @Return: void
*/
@Override

View File

@ -230,13 +230,14 @@ public class ShiroConfig {
RedisManager redisManager = new RedisManager();
redisManager.setHost(lettuceConnectionFactory.getHostName());
redisManager.setPort(lettuceConnectionFactory.getPort());
redisManager.setDatabase(lettuceConnectionFactory.getDatabase());
redisManager.setTimeout(0);
if (!StringUtils.isEmpty(lettuceConnectionFactory.getPassword())) {
redisManager.setPassword(lettuceConnectionFactory.getPassword());
}
manager = redisManager;
}else{
// redis 集群支持,优先使用集群配置 add by jzyadmin@163.com
// redis集群支持优先使用集群配置
RedisClusterManager redisManager = new RedisClusterManager();
Set<HostAndPort> portSet = new HashSet<>();
lettuceConnectionFactory.getClusterConfiguration().getClusterNodes().forEach(node -> portSet.add(new HostAndPort(node.getHost() , node.getPort())));

View File

@ -4,7 +4,7 @@
<parent>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-base</artifactId>
<version>2.4.2</version>
<version>2.4.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<description>公共模块</description>
@ -17,6 +17,15 @@
<artifactId>spring-boot-starter-web</artifactId>
<optional>true</optional>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--加载hutool-->
<dependency>
<groupId>cn.hutool</groupId>

View File

@ -52,7 +52,7 @@ public interface CacheConstant {
/**
* gateway路由缓存
*/
public static final String GATEWAY_ROUTES = "gateway_routes";
public static final String GATEWAY_ROUTES = "sys:cache:cloud:gateway_routes";
/**
@ -70,4 +70,15 @@ public interface CacheConstant {
*插件商城排行榜
*/
public static final String PLUGIN_MALL_PAGE_LIST = "pluginMall::queryPageList";
/**
* online列表页配置信息缓存key
*/
public static final String ONLINE_LIST = "sys:cache:online:list";
/**
* online表单页配置信息缓存key
*/
public static final String ONLINE_FORM = "sys:cache:online:form";
}

View File

@ -0,0 +1,32 @@
package org.jeecg.common.modules.redis.client;
import org.jeecg.common.base.BaseMap;
import org.jeecg.common.constant.GlobalConstants;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import javax.annotation.Resource;
/**
* redis客户端
*/
@Configuration
public class JeecgRedisClient {
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* 发送消息
*
* @param handlerName
* @param params
*/
public void sendMessage(String handlerName, BaseMap params) {
params.put(GlobalConstants.HANDLER_NAME, handlerName);
redisTemplate.convertAndSend(GlobalConstants.REDIS_TOPIC_NAME, params);
}
}

View File

@ -1,11 +1,17 @@
package org.jeecg.config.redis;
package org.jeecg.common.modules.redis.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.GlobalConstants;
import org.jeecg.common.modules.redis.receiver.RedisReceiver;
import org.jeecg.common.modules.redis.writer.JeecgRedisCacheWriter;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
@ -14,8 +20,12 @@ import org.springframework.context.annotation.Configuration;
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.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.*;
import javax.annotation.Resource;
@ -25,7 +35,8 @@ import static java.util.Collections.singletonMap;
/**
* 开启缓存支持
* @Return:
* @author zyf
* @Return:
*/
@Slf4j
@EnableCaching
@ -57,27 +68,24 @@ public class RedisConfig extends CachingConfigurerSupport {
/**
* RedisTemplate配置
*
* @param lettuceConnectionFactory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
log.info(" --- redis config init --- ");
// 设置序列化
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, Visibility.ANY);
om.enableDefaultTyping(DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置redisTemplate
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =jacksonSerializer();
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
RedisSerializer<?> stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);// key序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// value序列化
redisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);// Hash value序列化
// key序列化
redisTemplate.setKeySerializer(stringSerializer);
// value序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// Hash key序列化
redisTemplate.setHashKeySerializer(stringSerializer);
// Hash value序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@ -94,19 +102,53 @@ public class RedisConfig extends CachingConfigurerSupport {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(6));
RedisCacheConfiguration redisCacheConfiguration = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
// 以锁写入的方式创建RedisCacheWriter对象
//RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(factory);
//update-begin-author:taoyan date:20210316 for:注解CacheEvict根据key删除redis支持通配符*
RedisCacheWriter writer = new JeecgRedisCacheWriter(factory, Duration.ofMillis(50L));
//RedisCacheWriter.lockingRedisCacheWriter(factory);
// 创建默认缓存配置对象
/* 默认配置,设置缓存有效期 1小时*/
//RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1));
/* 自定义配置test:demo 的超时时间为 5分钟*/
RedisCacheManager cacheManager = RedisCacheManager.builder(RedisCacheWriter.lockingRedisCacheWriter(factory)).cacheDefaults(redisCacheConfiguration)
RedisCacheManager cacheManager = RedisCacheManager.builder(writer).cacheDefaults(redisCacheConfiguration)
.withInitialCacheConfigurations(singletonMap(CacheConstant.TEST_DEMO_CACHE, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5)).disableCachingNullValues()))
.withInitialCacheConfigurations(singletonMap(CacheConstant.PLUGIN_MALL_RANKING, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(24)).disableCachingNullValues()))
.withInitialCacheConfigurations(singletonMap(CacheConstant.PLUGIN_MALL_PAGE_LIST, RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(24)).disableCachingNullValues()))
.transactionAware().build();
//update-end-author:taoyan date:20210316 for:注解CacheEvict根据key删除redis支持通配符*
return cacheManager;
}
/**
* redis 监听配置
*
* @param redisConnectionFactory redis 配置
* @return
*/
@Bean
public RedisMessageListenerContainer redisContainer(RedisConnectionFactory redisConnectionFactory, RedisReceiver redisReceiver, MessageListenerAdapter commonListenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(redisConnectionFactory);
container.addMessageListener(commonListenerAdapter, new ChannelTopic(GlobalConstants.REDIS_TOPIC_NAME));
return container;
}
@Bean
MessageListenerAdapter commonListenerAdapter(RedisReceiver redisReceiver) {
MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(redisReceiver, "onMessage");
messageListenerAdapter.setSerializer(jacksonSerializer());
return messageListenerAdapter;
}
private Jackson2JsonRedisSerializer jacksonSerializer() {
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
return jackson2JsonRedisSerializer;
}
}

View File

@ -0,0 +1,12 @@
package org.jeecg.common.modules.redis.listener;
import org.jeecg.common.base.BaseMap;
/**
* 自定义消息监听
*/
public interface JeecgRedisListerer {
void onMessage(BaseMap message);
}

View File

@ -0,0 +1,33 @@
package org.jeecg.common.modules.redis.receiver;
import cn.hutool.core.util.ObjectUtil;
import lombok.Data;
import org.jeecg.common.base.BaseMap;
import org.jeecg.common.constant.GlobalConstants;
import org.jeecg.common.modules.redis.listener.JeecgRedisListerer;
import org.jeecg.common.util.SpringContextHolder;
import org.springframework.stereotype.Component;
/**
* @author zyf
*/
@Component
@Data
public class RedisReceiver {
/**
* 接受消息并调用业务逻辑处理器
*
* @param params
*/
public void onMessage(BaseMap params) {
Object handlerName = params.get(GlobalConstants.HANDLER_NAME);
JeecgRedisListerer messageListener = SpringContextHolder.getHandler(handlerName.toString(), JeecgRedisListerer.class);
if (ObjectUtil.isNotEmpty(messageListener)) {
messageListener.onMessage(params);
}
}
}

View File

@ -0,0 +1,221 @@
package org.jeecg.common.modules.redis.writer;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* 该类参照 DefaultRedisCacheWriter 重写了 remove 方法实现通配符*删除
*/
@Slf4j
public class JeecgRedisCacheWriter implements RedisCacheWriter {
private final RedisConnectionFactory connectionFactory;
private final Duration sleepTime;
public JeecgRedisCacheWriter(RedisConnectionFactory connectionFactory) {
this(connectionFactory, Duration.ZERO);
}
public JeecgRedisCacheWriter(RedisConnectionFactory connectionFactory, Duration sleepTime) {
Assert.notNull(connectionFactory, "ConnectionFactory must not be null!");
Assert.notNull(sleepTime, "SleepTime must not be null!");
this.connectionFactory = connectionFactory;
this.sleepTime = sleepTime;
}
public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
Assert.notNull(value, "Value must not be null!");
this.execute(name, (connection) -> {
if (shouldExpireWithin(ttl)) {
connection.set(key, value, Expiration.from(ttl.toMillis(), TimeUnit.MILLISECONDS), SetOption.upsert());
} else {
connection.set(key, value);
}
return "OK";
});
}
public byte[] get(String name, byte[] key) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
return (byte[])this.execute(name, (connection) -> {
return connection.get(key);
});
}
public byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
Assert.notNull(value, "Value must not be null!");
return (byte[])this.execute(name, (connection) -> {
if (this.isLockingCacheWriter()) {
this.doLock(name, connection);
}
Object var7;
try {
boolean put;
if (shouldExpireWithin(ttl)) {
put = connection.set(key, value, Expiration.from(ttl), SetOption.ifAbsent());
} else {
put = connection.setNX(key, value);
}
if (!put) {
byte[] var11 = connection.get(key);
return var11;
}
var7 = null;
} finally {
if (this.isLockingCacheWriter()) {
this.doUnlock(name, connection);
}
}
return (byte[])var7;
});
}
public void remove(String name, byte[] key) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
String keyString = new String(key);
log.info("redis remove key:" + keyString);
if(keyString!=null && keyString.endsWith("*")){
execute(name, connection -> {
// 获取某个前缀所拥有的所有的键,某个前缀开头,后面肯定是*
Set<byte[]> keys = connection.keys(key);
int delNum = 0;
for (byte[] keyByte : keys) {
delNum += connection.del(keyByte);
}
return delNum;
});
}else{
this.execute(name, (connection) -> {
return connection.del(new byte[][]{key});
});
}
}
public void clean(String name, byte[] pattern) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(pattern, "Pattern must not be null!");
this.execute(name, (connection) -> {
boolean wasLocked = false;
try {
if (this.isLockingCacheWriter()) {
this.doLock(name, connection);
wasLocked = true;
}
byte[][] keys = (byte[][])((Set)Optional.ofNullable(connection.keys(pattern)).orElse(Collections.emptySet())).toArray(new byte[0][]);
if (keys.length > 0) {
connection.del(keys);
}
} finally {
if (wasLocked && this.isLockingCacheWriter()) {
this.doUnlock(name, connection);
}
}
return "OK";
});
}
void lock(String name) {
this.execute(name, (connection) -> {
return this.doLock(name, connection);
});
}
void unlock(String name) {
this.executeLockFree((connection) -> {
this.doUnlock(name, connection);
});
}
private Boolean doLock(String name, RedisConnection connection) {
return connection.setNX(createCacheLockKey(name), new byte[0]);
}
private Long doUnlock(String name, RedisConnection connection) {
return connection.del(new byte[][]{createCacheLockKey(name)});
}
boolean doCheckLock(String name, RedisConnection connection) {
return connection.exists(createCacheLockKey(name));
}
private boolean isLockingCacheWriter() {
return !this.sleepTime.isZero() && !this.sleepTime.isNegative();
}
private <T> T execute(String name, Function<RedisConnection, T> callback) {
RedisConnection connection = this.connectionFactory.getConnection();
try {
this.checkAndPotentiallyWaitUntilUnlocked(name, connection);
return callback.apply(connection);
} finally {
connection.close();
}
}
private void executeLockFree(Consumer<RedisConnection> callback) {
RedisConnection connection = this.connectionFactory.getConnection();
try {
callback.accept(connection);
} finally {
connection.close();
}
}
private void checkAndPotentiallyWaitUntilUnlocked(String name, RedisConnection connection) {
if (this.isLockingCacheWriter()) {
try {
while(this.doCheckLock(name, connection)) {
Thread.sleep(this.sleepTime.toMillis());
}
} catch (InterruptedException var4) {
Thread.currentThread().interrupt();
throw new PessimisticLockingFailureException(String.format("Interrupted while waiting to unlock cache %s", name), var4);
}
}
}
private static boolean shouldExpireWithin(@Nullable Duration ttl) {
return ttl != null && !ttl.isZero() && !ttl.isNegative();
}
private static byte[] createCacheLockKey(String name) {
return (name + "~lock").getBytes(StandardCharsets.UTF_8);
}
}

View File

@ -6,7 +6,6 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jeecg.common.exception.JeecgBootException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>jeecg-boot-parent</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>2.4.2</version>
<version>2.4.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>