Compare commits

...

2 Commits

7 changed files with 415 additions and 16 deletions

View File

@ -2,6 +2,7 @@ package com.coscoshipping.ebtp.system.dict.service.impl;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.chinaunicom.mall.ebtp.common.base.service.impl.BaseServiceImpl;
@ -76,13 +77,9 @@ public class DictProjectServiceImpl extends BaseServiceImpl<DictProjectMapper, D
@Override
public List<DictProject> selectDictList(DictProject dictProject) {
if (dictProject != null && dictProject.getCode() != null && dictProject.getParentType() != null) {
return this.list(Wrappers.<DictProject>lambdaQuery()
.eq(DictProject::getCode, dictProject.getCode())
.eq(DictProject::getParentType, dictProject.getParentType())
.last("limit 1"));
}
return ListUtil.empty();
return this.list(Wrappers.<DictProject>lambdaQuery()
.eq(StrUtil.isNotBlank(dictProject.getCode()), DictProject::getCode, dictProject.getCode())
.eq(StrUtil.isNotBlank(dictProject.getParentType()), DictProject::getParentType, dictProject.getParentType()));
}
@Override

View File

@ -0,0 +1,48 @@
package com.coscoshipping.ebtp.system.org.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import java.util.List;
/**
* 组织机构缓存配置类
* 配置专门的RedisTemplate用于组织机构缓存使用Java原生序列化提高性能
*
* @author system
*/
@Configuration
public class OrgCacheConfig {
/**
* 组织机构专用RedisTemplate配置
* 使用Java原生序列化避免JSON转换开销
*
* @param redisConnectionFactory Redis连接工厂
* @return 配置好的RedisTemplate
*/
@Bean(name = "orgCacheRedisTemplate")
public RedisTemplate<String, List> orgCacheRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, List> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使用String序列化器处理key
redisTemplate.setKeySerializer(new GenericToStringSerializer<>(String.class));
redisTemplate.setHashKeySerializer(new GenericToStringSerializer<>(String.class));
// 使用Java原生序列化器处理value避免JSON转换
JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer();
redisTemplate.setValueSerializer(jdkSerializer);
redisTemplate.setHashValueSerializer(jdkSerializer);
// 启用事务支持
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}

View File

@ -0,0 +1,41 @@
package com.coscoshipping.ebtp.system.org.config;
import com.coscoshipping.ebtp.system.org.manager.OrgCacheManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* 组织机构缓存初始化器
* 在系统启动时自动初始化组织机构数据到Redis缓存
*
* @author system
*/
@Slf4j
@Component
@Order(1) // 设置执行顺序,确保在其他组件之前执行
public class OrgCacheInitializer implements ApplicationRunner {
@Autowired
private OrgCacheManager orgCacheManager;
@Override
public void run(ApplicationArguments args) throws Exception {
log.info("系统启动 - 开始初始化组织机构缓存");
try {
// 初始化组织机构缓存
orgCacheManager.initCache();
log.info("系统启动 - 组织机构缓存初始化完成");
// 可选:执行性能测试(仅在需要时启用)
// orgCacheManager.performanceTest(100);
} catch (Exception e) {
log.error("系统启动 - 组织机构缓存初始化失败", e);
// 不抛出异常,避免影响系统启动
}
}
}

View File

@ -98,12 +98,17 @@ public class SysOrgController{
*/
@ApiOperation("查询列表数据")
@GetMapping("/list")
public BaseResponse<List<SysOrg>> list(@ApiParam(value = "查询对象数据", required = false) SysOrg param) {
public BaseResponse<List<SysOrg>> list(@ApiParam(value = "查询对象数据", required = false) SysOrgVO param) {
//查询
LambdaQueryWrapper<SysOrg> query = Wrappers.lambdaQuery(param);
// 处理多orgId查询条件
if (param.getAllDepartmentId() != null && !param.getAllDepartmentId().trim().isEmpty()) {
String[] orgIds = param.getAllDepartmentId().split(",");
query.in(SysOrg::getOrgId, orgIds);
}
List<SysOrg> list = iSysOrgService.list(query);
//异常处理
//RespsExceptionEnum.FRAME_EXCEPTION_DEMO_NOT_FIND.customValid(list.isEmpty());
return BaseResponse.success(list);
}

View File

@ -0,0 +1,163 @@
package com.coscoshipping.ebtp.system.org.manager;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.coscoshipping.ebtp.system.org.entity.SysOrg;
import com.coscoshipping.ebtp.system.org.service.SysOrgService;
import com.coscoshipping.ebtp.system.org.util.CachePerformanceTest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 组织机构缓存管理器
* 负责组织机构数据的Redis缓存操作
*
* @author system
*/
@Slf4j
@Component
public class OrgCacheManager {
private static final String ORG_CACHE_KEY = "sys:org:all";
private static final long CACHE_EXPIRE_TIME = 24; // 24小时过期
@Autowired
@Qualifier("cacheRedisTemplate")
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private SysOrgService sysOrgService;
/**
* 初始化缓存 - 系统启动时调用
*/
public void initCache() {
log.info("开始初始化组织机构缓存...");
try {
// 从数据库查询所有组织机构数据
List<SysOrg> allOrgs = sysOrgService.list(new LambdaQueryWrapper<SysOrg>()
.eq(SysOrg::getDeleteFlag, "normal")
.orderByAsc(SysOrg::getSort));
if (!CollectionUtils.isEmpty(allOrgs)) {
// 直接将List<SysOrg>存入Redis缓存无需JSON转换
redisTemplate.opsForValue().set(ORG_CACHE_KEY, allOrgs, CACHE_EXPIRE_TIME, TimeUnit.HOURS);
log.info("组织机构缓存初始化完成,共缓存{}条记录", allOrgs.size());
// 可选:执行性能测试(仅在开发环境建议启用)
// CachePerformanceTest.comparePerformance(allOrgs, 100);
} else {
log.warn("数据库中没有找到组织机构数据");
}
} catch (Exception e) {
log.error("初始化组织机构缓存失败", e);
}
}
/**
* 从缓存中获取所有组织机构数据
*
* @return 组织机构列表如果缓存中没有数据则返回null
*/
@SuppressWarnings("unchecked")
public List<SysOrg> getAllOrgsFromCache() {
try {
Object cacheData = redisTemplate.opsForValue().get(ORG_CACHE_KEY);
if (cacheData != null) {
log.debug("从缓存中获取组织机构数据");
return (List<SysOrg>) cacheData;
} else {
log.debug("缓存中没有组织机构数据");
return null;
}
} catch (Exception e) {
log.error("从缓存获取组织机构数据失败", e);
return null;
}
}
/**
* 刷新缓存 - 增删改操作后调用
*/
public void refreshCache() {
log.info("开始刷新组织机构缓存...");
try {
// 先删除旧缓存
redisTemplate.delete(ORG_CACHE_KEY);
// 重新初始化缓存
initCache();
log.info("组织机构缓存刷新完成");
} catch (Exception e) {
log.error("刷新组织机构缓存失败", e);
}
}
/**
* 清除缓存
*/
public void clearCache() {
try {
redisTemplate.delete(ORG_CACHE_KEY);
log.info("组织机构缓存已清除");
} catch (Exception e) {
log.error("清除组织机构缓存失败", e);
}
}
/**
* 检查缓存是否存在
*
* @return true 如果缓存存在false 如果缓存不存在
*/
public boolean isCacheExists() {
try {
return Boolean.TRUE.equals(redisTemplate.hasKey(ORG_CACHE_KEY));
} catch (Exception e) {
log.error("检查缓存是否存在时出错", e);
return false;
}
}
/**
* 延长缓存过期时间
*/
public void extendCacheExpire() {
try {
redisTemplate.expire(ORG_CACHE_KEY, CACHE_EXPIRE_TIME, TimeUnit.HOURS);
log.debug("组织机构缓存过期时间已延长");
} catch (Exception e) {
log.error("延长缓存过期时间失败", e);
}
}
/**
* 执行缓存性能测试
* 比较JSON序列化与Java原生序列化的性能差异
*
* @param testCount 测试次数建议100-1000次
*/
public void performanceTest(int testCount) {
try {
List<SysOrg> allOrgs = sysOrgService.list(new LambdaQueryWrapper<SysOrg>()
.eq(SysOrg::getDeleteFlag, "normal"));
if (!CollectionUtils.isEmpty(allOrgs)) {
log.info("开始执行组织机构缓存性能测试...");
CachePerformanceTest.comparePerformance(allOrgs, testCount);
log.info("组织机构缓存性能测试完成");
} else {
log.warn("没有组织机构数据,无法进行性能测试");
}
} catch (Exception e) {
log.error("执行缓存性能测试失败", e);
}
}
}

View File

@ -10,6 +10,7 @@ import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
@ -26,6 +27,7 @@ import com.coscoshipping.ebtp.system.org.entity.SysOrg;
import com.coscoshipping.ebtp.system.org.entity.vo.SysOrgVO;
import com.coscoshipping.ebtp.system.org.service.SysOrgService;
import com.coscoshipping.ebtp.system.org.util.CommonUtil;
import com.coscoshipping.ebtp.system.org.manager.OrgCacheManager;
import cn.hutool.core.bean.BeanUtil;
@ -37,6 +39,9 @@ import cn.hutool.core.bean.BeanUtil;
@Service
public class SysOrgServiceImpl extends BaseServiceImpl<SysOrgMapper, SysOrg> implements SysOrgService {
@Autowired
private OrgCacheManager orgCacheManager;
@Override
public IPage<SysOrg> getPage(SysOrgVO SysOrgVO) {
LambdaQueryWrapper<SysOrg> query = buildQueryWrapper(SysOrgVO);
@ -79,9 +84,15 @@ public class SysOrgServiceImpl extends BaseServiceImpl<SysOrgMapper, SysOrg> imp
return buildOrgTree(orgList, org);
}
// 3. 没有条件,才全查
List<SysOrg> allOrgList = this.list();
if (CollectionUtils.isEmpty(allOrgList)) return new ArrayList<>();
// 3. 没有条件,才全查 - 优先从缓存获取
List<SysOrg> allOrgList = orgCacheManager.getAllOrgsFromCache();
if (CollectionUtils.isEmpty(allOrgList)) {
// 缓存中没有数据,从数据库查询
allOrgList = this.list();
if (CollectionUtils.isEmpty(allOrgList)) return new ArrayList<>();
// 如果数据库有数据但缓存没有,刷新缓存
orgCacheManager.refreshCache();
}
return buildOrgTree(allOrgList, org);
}
@ -165,7 +176,14 @@ public class SysOrgServiceImpl extends BaseServiceImpl<SysOrgMapper, SysOrg> imp
SysOrg full = this.buildOrgFullPath(vo);
vo.setOrgFullId(full.getOrgFullId()).setOrgFullName(full.getOrgFullName());
validEntityBeforeSave(vo, false);
return baseMapper.insert(vo) > 0;
boolean result = baseMapper.insert(vo) > 0;
// 新增成功后刷新缓存
if (result) {
orgCacheManager.refreshCache();
}
return result;
}
@Override
@ -175,7 +193,14 @@ public class SysOrgServiceImpl extends BaseServiceImpl<SysOrgMapper, SysOrg> imp
vo.setOrgFullId(full.getOrgFullId()).setOrgFullName(full.getOrgFullName());
// 删除机构与人员关联
// roleMenuService.remove(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, vo.getRoleId()));
return baseMapper.updateById(vo) > 0;
boolean result = baseMapper.updateById(vo) > 0;
// 更新成功后刷新缓存
if (result) {
orgCacheManager.refreshCache();
}
return result;
}
@ -186,7 +211,14 @@ public class SysOrgServiceImpl extends BaseServiceImpl<SysOrgMapper, SysOrg> imp
CommonExceptionEnum.FRAME_EXCEPTION_COMMON_DATA_OTHER_ERROR.customValidName("存在下级组织,不可删除", !orgList.isEmpty());
// 删除机构与人员关联
// roleMenuService.remove(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
return this.removeById(orgId);
boolean result = this.removeById(orgId);
// 删除成功后刷新缓存
if (result) {
orgCacheManager.refreshCache();
}
return result;
}
@Override

View File

@ -0,0 +1,113 @@
package com.coscoshipping.ebtp.system.org.util;
import com.chinaunicom.mall.ebtp.common.util.JsonUtils;
import com.coscoshipping.ebtp.system.org.entity.SysOrg;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.util.List;
/**
* 缓存性能测试工具类
* 用于比较JSON序列化与Java原生序列化的性能差异
*
* @author system
*/
@Slf4j
public class CachePerformanceTest {
/**
* 测试JSON序列化性能
*
* @param orgList 组织机构列表
* @param testCount 测试次数
* @return 平均耗时(纳秒)
*/
public static long testJsonSerialization(List<SysOrg> orgList, int testCount) {
long startTime = System.nanoTime();
for (int i = 0; i < testCount; i++) {
// 序列化
String json = JsonUtils.objectToJson(orgList);
// 反序列化
List<SysOrg> result = JsonUtils.jsonToList(json, SysOrg.class);
}
long endTime = System.nanoTime();
long avgTime = (endTime - startTime) / testCount;
log.info("JSON序列化测试完成测试次数: {}, 平均耗时: {} 纳秒", testCount, avgTime);
return avgTime;
}
/**
* 测试Java原生序列化性能
*
* @param orgList 组织机构列表
* @param testCount 测试次数
* @return 平均耗时(纳秒)
*/
@SuppressWarnings("unchecked")
public static long testJavaSerial(List<SysOrg> orgList, int testCount) {
long startTime = System.nanoTime();
for (int i = 0; i < testCount; i++) {
try {
// 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(orgList);
byte[] bytes = bos.toByteArray();
oos.close();
bos.close();
// 反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
List<SysOrg> result = (List<SysOrg>) ois.readObject();
ois.close();
bis.close();
} catch (Exception e) {
log.error("Java序列化测试失败", e);
}
}
long endTime = System.nanoTime();
long avgTime = (endTime - startTime) / testCount;
log.info("Java原生序列化测试完成测试次数: {}, 平均耗时: {} 纳秒", testCount, avgTime);
return avgTime;
}
/**
* 比较两种序列化方式的性能
*
* @param orgList 组织机构列表
* @param testCount 测试次数
*/
public static void comparePerformance(List<SysOrg> orgList, int testCount) {
log.info("开始缓存性能测试,数据量: {} 条记录", orgList.size());
// 预热JVM
testJsonSerialization(orgList, 10);
testJavaSerial(orgList, 10);
// 正式测试
long jsonTime = testJsonSerialization(orgList, testCount);
long javaTime = testJavaSerial(orgList, testCount);
// 计算性能提升
double improvement = ((double) (jsonTime - javaTime) / jsonTime) * 100;
log.info("=== 缓存性能测试结果 ===");
log.info("JSON序列化平均耗时: {} 纳秒", jsonTime);
log.info("Java原生序列化平均耗时: {} 纳秒", javaTime);
log.info("性能提升: {:.2f}%", improvement);
if (improvement > 0) {
log.info("Java原生序列化比JSON序列化快 {:.2f}%", improvement);
} else {
log.info("JSON序列化比Java原生序列化快 {:.2f}%", Math.abs(improvement));
}
}
}