Merge remote-tracking branch 'origin/master'

This commit is contained in:
YunaiV 2023-01-25 10:51:25 +08:00
commit 41bb7c6f29
35 changed files with 204 additions and 718 deletions

View File

@ -76,23 +76,24 @@ public interface BaseMapperX<T> extends BaseMapper<T> {
return selectList(new LambdaQueryWrapper<T>().in(field, values)); return selectList(new LambdaQueryWrapper<T>().in(field, values));
} }
/** default List<T> selectList(SFunction<T, ?> leField, SFunction<T, ?> geField, Object value) {
* 逐条插入适合少量数据插入或者对性能要求不高的场景 return selectList(new LambdaQueryWrapper<T>().le(leField, value).ge(geField, value));
*
* 如果大量请使用 {@link com.baomidou.mybatisplus.extension.service.impl.ServiceImpl#saveBatch(Collection)} 方法
* 使用示例可见 RoleMenuBatchInsertMapperUserRoleBatchInsertMapper
*
* @param entities 实体们
*/
default void insertBatch(Collection<T> entities) {
entities.forEach(this::insert);
} }
/** /**
* 批量插入适合大量数据插入 * 批量插入适合大量数据插入
* *
* @param entities 实体们 * @param entities 实体们
* @param size 插入数量 Db.saveBatch 默认为1000 */
default void insertBatch(Collection<T> entities) {
Db.saveBatch(entities);
}
/**
* 批量插入适合大量数据插入
*
* @param entities 实体们
* @param size 插入数量 Db.saveBatch 默认为 1000
*/ */
default void insertBatch(Collection<T> entities, int size) { default void insertBatch(Collection<T> entities, int size) {
Db.saveBatch(entities, size); Db.saveBatch(entities, size);
@ -105,4 +106,5 @@ public interface BaseMapperX<T> extends BaseMapper<T> {
default void updateBatch(Collection<T> entities, int size) { default void updateBatch(Collection<T> entities, int size) {
Db.updateBatchById(entities, size); Db.updateBatchById(entities, size);
} }
} }

View File

@ -6,15 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.time.LocalDateTime;
/**
* 文件配置 Mapper
*
* @author 芋道源码
*/
@Mapper @Mapper
public interface FileConfigMapper extends BaseMapperX<FileConfigDO> { public interface FileConfigMapper extends BaseMapperX<FileConfigDO> {
@ -26,7 +18,4 @@ public interface FileConfigMapper extends BaseMapperX<FileConfigDO> {
.orderByDesc(FileConfigDO::getId)); .orderByDesc(FileConfigDO::getId));
} }
@Select("SELECT COUNT(*) FROM infra_file_config WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
} }

View File

@ -23,7 +23,7 @@ public class FileConfigRefreshConsumer {
@EventListener @EventListener
public void execute(FileConfigRefreshMessage message) { public void execute(FileConfigRefreshMessage message) {
log.info("[execute][收到 FileConfig 刷新消息]"); log.info("[execute][收到 FileConfig 刷新消息]");
fileConfigService.initFileClients(); fileConfigService.initLocalCache();
} }
} }

View File

@ -21,7 +21,7 @@ public interface FileConfigService {
/** /**
* 初始化文件客户端 * 初始化文件客户端
*/ */
void initFileClients(); void initLocalCache();
/** /**
* 创建文件配置 * 创建文件配置

View File

@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.infra.service.file;
import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
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.common.util.validation.ValidationUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.framework.file.core.client.FileClient; import cn.iocoder.yudao.framework.file.core.client.FileClient;
@ -19,7 +18,6 @@ import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper;
import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer; import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronization;
@ -29,7 +27,6 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Validator; import javax.validation.Validator;
import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -48,18 +45,6 @@ import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG
@Slf4j @Slf4j
public class FileConfigServiceImpl implements FileConfigService { public class FileConfigServiceImpl implements FileConfigService {
/**
* 定时执行 {@link #schedulePeriodicRefresh()} 的周期
* 因为已经通过 Redis Pub/Sub 机制所以频率不需要高
*/
private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
/**
* 缓存菜单的最大更新时间用于后续的增量轮询判断是否有更新
*/
@Getter
private volatile LocalDateTime maxUpdateTime;
@Resource @Resource
private FileClientFactory fileClientFactory; private FileClientFactory fileClientFactory;
/** /**
@ -79,34 +64,12 @@ public class FileConfigServiceImpl implements FileConfigService {
@Override @Override
@PostConstruct @PostConstruct
public void initFileClients() { public void initLocalCache() {
initLocalCacheIfUpdate(null); // 第一步查询数据
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
initLocalCacheIfUpdate(this.maxUpdateTime);
}
/**
* 刷新本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/
private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步基于 maxUpdateTime 判断缓存是否刷新
// 如果没有增量的数据变化则不进行本地缓存的刷新
if (maxUpdateTime != null
&& fileConfigMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return;
}
List<FileConfigDO> configs = fileConfigMapper.selectList(); List<FileConfigDO> configs = fileConfigMapper.selectList();
log.info("[initLocalCacheIfUpdate][缓存文件配置,数量为:{}]", configs.size()); log.info("[initLocalCache][缓存文件配置,数量为:{}]", configs.size());
// 第二步构建缓存创建或更新文件 Client // 第二步构建缓存创建或更新文件 Client
configs.forEach(config -> { configs.forEach(config -> {
fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig()); fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig());
// 如果是 master进行设置 // 如果是 master进行设置
@ -114,9 +77,6 @@ public class FileConfigServiceImpl implements FileConfigService {
masterFileClient = fileClientFactory.getFileClient(config.getId()); masterFileClient = fileClientFactory.getFileClient(config.getId());
} }
}); });
// 第三步设置最新的 maxUpdateTime用于下次的增量判断
this.maxUpdateTime = CollectionUtils.getMaxValue(configs, FileConfigDO::getUpdateTime);
} }
@Override @Override

View File

@ -28,9 +28,8 @@ import java.time.LocalDateTime;
import java.util.Map; import java.util.Map;
import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildLocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.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.framework.common.util.object.ObjectUtils.max;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
@ -42,10 +41,10 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
/** /**
* {@link FileConfigServiceImpl} 的单元测试类 * {@link FileConfigServiceImpl} 的单元测试类
* *
* @author 芋道源码 * @author 芋道源码
*/ */
@Import(FileConfigServiceImpl.class) @Import(FileConfigServiceImpl.class)
public class FileConfigServiceImplTest extends BaseDbUnitTest { public class FileConfigServiceImplTest extends BaseDbUnitTest {
@ -74,16 +73,13 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
when(fileClientFactory.getFileClient(eq(1L))).thenReturn(masterFileClient); when(fileClientFactory.getFileClient(eq(1L))).thenReturn(masterFileClient);
// 调用 // 调用
fileConfigService.initFileClients(); fileConfigService.initLocalCache();
// 断言 fileClientFactory 调用 // 断言 fileClientFactory 调用
verify(fileClientFactory).createOrUpdateFileClient(eq(1L), verify(fileClientFactory).createOrUpdateFileClient(eq(1L),
eq(configDO1.getStorage()), eq(configDO1.getConfig())); eq(configDO1.getStorage()), eq(configDO1.getConfig()));
verify(fileClientFactory).createOrUpdateFileClient(eq(2L), verify(fileClientFactory).createOrUpdateFileClient(eq(2L),
eq(configDO2.getStorage()), eq(configDO2.getConfig())); eq(configDO2.getStorage()), eq(configDO2.getConfig()));
assertSame(masterFileClient, fileConfigService.getMasterFileClient()); assertSame(masterFileClient, fileConfigService.getMasterFileClient());
// 断言 maxUpdateTime 缓存
assertEquals(max(configDO1.getUpdateTime(), configDO2.getUpdateTime()),
fileConfigService.getMaxUpdateTime());
} }
@Test @Test
@ -175,8 +171,8 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
// 调用 // 调用
fileConfigService.deleteFileConfig(id); fileConfigService.deleteFileConfig(id);
// 校验数据不存在了 // 校验数据不存在了
assertNull(fileConfigMapper.selectById(id)); assertNull(fileConfigMapper.selectById(id));
// verify 调用 // verify 调用
verify(fileConfigProducer).sendFileConfigRefreshMessage(); verify(fileConfigProducer).sendFileConfigRefreshMessage();
} }
@ -204,30 +200,30 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
@Test @Test
public void testGetFileConfigPage() { public void testGetFileConfigPage() {
// mock 数据 // mock 数据
FileConfigDO dbFileConfig = randomFileConfigDO().setName("芋道源码") FileConfigDO dbFileConfig = randomFileConfigDO().setName("芋道源码")
.setStorage(FileStorageEnum.LOCAL.getStorage()); .setStorage(FileStorageEnum.LOCAL.getStorage());
dbFileConfig.setCreateTime(LocalDateTimeUtil.parse("2020-01-23", DatePattern.NORM_DATE_PATTERN));// 等会查询到 dbFileConfig.setCreateTime(LocalDateTimeUtil.parse("2020-01-23", DatePattern.NORM_DATE_PATTERN));// 等会查询到
fileConfigMapper.insert(dbFileConfig); fileConfigMapper.insert(dbFileConfig);
// 测试 name 不匹配 // 测试 name 不匹配
fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setName("源码"))); fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setName("源码")));
// 测试 storage 不匹配 // 测试 storage 不匹配
fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setStorage(FileStorageEnum.DB.getStorage()))); fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setStorage(FileStorageEnum.DB.getStorage())));
// 测试 createTime 不匹配 // 测试 createTime 不匹配
fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setCreateTime(LocalDateTimeUtil.parse("2020-11-23", DatePattern.NORM_DATE_PATTERN)))); fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setCreateTime(LocalDateTimeUtil.parse("2020-11-23", DatePattern.NORM_DATE_PATTERN))));
// 准备参数 // 准备参数
FileConfigPageReqVO reqVO = new FileConfigPageReqVO(); FileConfigPageReqVO reqVO = new FileConfigPageReqVO();
reqVO.setName("芋道"); reqVO.setName("芋道");
reqVO.setStorage(FileStorageEnum.LOCAL.getStorage()); reqVO.setStorage(FileStorageEnum.LOCAL.getStorage());
reqVO.setCreateTime((new LocalDateTime[]{buildLocalDateTime(2020, 1, 1), reqVO.setCreateTime((new LocalDateTime[]{buildTime(2020, 1, 1),
buildLocalDateTime(2020, 1, 24)})); buildTime(2020, 1, 24)}));
// 调用 // 调用
PageResult<FileConfigDO> pageResult = fileConfigService.getFileConfigPage(reqVO); PageResult<FileConfigDO> pageResult = fileConfigService.getFileConfigPage(reqVO);
// 断言 // 断言
assertEquals(1, pageResult.getTotal()); assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size()); assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbFileConfig, pageResult.getList().get(0)); assertPojoEquals(dbFileConfig, pageResult.getList().get(0));
} }
@Test @Test

View File

@ -6,10 +6,7 @@ import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqV
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@Mapper @Mapper
@ -31,7 +28,4 @@ public interface DeptMapper extends BaseMapperX<DeptDO> {
return selectCount(DeptDO::getParentId, parentId); return selectCount(DeptDO::getParentId, parentId);
} }
@Select("SELECT COUNT(*) FROM system_dept WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
} }

View File

@ -6,10 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
/** /**
* OAuth2 客户端 Mapper * OAuth2 客户端 Mapper
@ -30,7 +27,4 @@ public interface OAuth2ClientMapper extends BaseMapperX<OAuth2ClientDO> {
return selectOne(OAuth2ClientDO::getClientId, clientId); return selectOne(OAuth2ClientDO::getClientId, clientId);
} }
@Select("SELECT COUNT(*) FROM system_oauth2_client WHERE update_time > #{maxUpdateTime}")
int selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
} }

View File

@ -6,9 +6,7 @@ import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuLi
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@Mapper @Mapper
@ -28,7 +26,4 @@ public interface MenuMapper extends BaseMapperX<MenuDO> {
.eqIfPresent(MenuDO::getStatus, reqVO.getStatus())); .eqIfPresent(MenuDO::getStatus, reqVO.getStatus()));
} }
@Select("SELECT COUNT(*) FROM system_menu WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
} }

View File

@ -8,11 +8,9 @@ import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleEx
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import java.util.Collection; import java.util.Collection;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@Mapper @Mapper
@ -47,7 +45,4 @@ public interface RoleMapper extends BaseMapperX<RoleDO> {
return selectList(RoleDO::getStatus, statuses); return selectList(RoleDO::getStatus, statuses);
} }
@Select("SELECT COUNT(*) FROM system_role WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
} }

View File

@ -1,14 +0,0 @@
package cn.iocoder.yudao.module.system.dal.mysql.permission;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Repository;
/**
* 实体 {@link RoleMenuDO} 的批量插入 Mapper
*
* @author 芋道源码
*/
@Repository
public class RoleMenuBatchInsertMapper extends ServiceImpl<RoleMenuMapper, RoleMenuDO> {
}

View File

@ -2,14 +2,12 @@ package cn.iocoder.yudao.module.system.dal.mysql.permission;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.Collection; import java.util.Collection;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@Mapper @Mapper
@ -20,23 +18,21 @@ public interface RoleMenuMapper extends BaseMapperX<RoleMenuDO> {
} }
default List<RoleMenuDO> selectListByRoleId(Long roleId) { default List<RoleMenuDO> selectListByRoleId(Long roleId) {
return selectList(new QueryWrapper<RoleMenuDO>().eq("role_id", roleId)); return selectList(RoleMenuDO::getRoleId, roleId);
} }
default void deleteListByRoleIdAndMenuIds(Long roleId, Collection<Long> menuIds) { default void deleteListByRoleIdAndMenuIds(Long roleId, Collection<Long> menuIds) {
delete(new QueryWrapper<RoleMenuDO>().eq("role_id", roleId) delete(new LambdaQueryWrapper<RoleMenuDO>()
.in("menu_id", menuIds)); .eq(RoleMenuDO::getRoleId, roleId)
.in(RoleMenuDO::getMenuId, menuIds));
} }
default void deleteListByMenuId(Long menuId) { default void deleteListByMenuId(Long menuId) {
delete(new QueryWrapper<RoleMenuDO>().eq("menu_id", menuId)); delete(new LambdaQueryWrapper<RoleMenuDO>().eq(RoleMenuDO::getMenuId, menuId));
} }
default void deleteListByRoleId(Long roleId) { default void deleteListByRoleId(Long roleId) {
delete(new QueryWrapper<RoleMenuDO>().eq("role_id", roleId)); delete(new LambdaQueryWrapper<RoleMenuDO>().eq(RoleMenuDO::getRoleId, roleId));
} }
@Select("SELECT COUNT(*) FROM system_role_menu WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
} }

View File

@ -1,14 +0,0 @@
package cn.iocoder.yudao.module.system.dal.mysql.permission;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Repository;
/**
* 实体 {@link UserRoleDO} 的批量插入 Mapper
*
* @author 芋道源码
*/
@Repository
public class UserRoleBatchInsertMapper extends ServiceImpl<UserRoleMapper, UserRoleDO> {
}

View File

@ -2,44 +2,35 @@ package cn.iocoder.yudao.module.system.dal.mysql.permission;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.Collection; import java.util.Collection;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@Mapper @Mapper
public interface UserRoleMapper extends BaseMapperX<UserRoleDO> { public interface UserRoleMapper extends BaseMapperX<UserRoleDO> {
default List<UserRoleDO> selectListByUserId(Long userId) { default List<UserRoleDO> selectListByUserId(Long userId) {
return selectList(new QueryWrapper<UserRoleDO>().eq("user_id", userId)); return selectList(UserRoleDO::getUserId, userId);
}
default List<UserRoleDO> selectListByRoleId(Long roleId) {
return selectList(new QueryWrapper<UserRoleDO>().eq("role_id", roleId));
} }
default void deleteListByUserIdAndRoleIdIds(Long userId, Collection<Long> roleIds) { default void deleteListByUserIdAndRoleIdIds(Long userId, Collection<Long> roleIds) {
delete(new QueryWrapper<UserRoleDO>().eq("user_id", userId) delete(new LambdaQueryWrapper<UserRoleDO>()
.in("role_id", roleIds)); .eq(UserRoleDO::getUserId, userId)
.in(UserRoleDO::getRoleId, roleIds));
} }
default void deleteListByUserId(Long userId) { default void deleteListByUserId(Long userId) {
delete(new QueryWrapper<UserRoleDO>().eq("user_id", userId)); delete(new LambdaQueryWrapper<UserRoleDO>().eq(UserRoleDO::getUserId, userId));
} }
default void deleteListByRoleId(Long roleId) { default void deleteListByRoleId(Long roleId) {
delete(new QueryWrapper<UserRoleDO>().eq("role_id", roleId)); delete(new LambdaQueryWrapper<UserRoleDO>().eq(UserRoleDO::getRoleId, roleId));
} }
default List<UserRoleDO> selectListByRoleIds(Collection<Long> roleIds) { default List<UserRoleDO> selectListByRoleIds(Collection<Long> roleIds) {
return selectList(UserRoleDO::getRoleId, roleIds); return selectList(UserRoleDO::getRoleId, roleIds);
} }
@Select("SELECT COUNT(*) FROM system_user_role WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
} }

View File

@ -7,9 +7,7 @@ import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.Sensitiv
import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO; import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
/** /**
@ -42,7 +40,4 @@ public interface SensitiveWordMapper extends BaseMapperX<SensitiveWordDO> {
return selectOne(SensitiveWordDO::getName, name); return selectOne(SensitiveWordDO::getName, name);
} }
@Select("SELECT COUNT(*) FROM system_sensitive_word WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
} }

View File

@ -6,9 +6,6 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.time.LocalDateTime;
@Mapper @Mapper
public interface SmsChannelMapper extends BaseMapperX<SmsChannelDO> { public interface SmsChannelMapper extends BaseMapperX<SmsChannelDO> {
@ -21,7 +18,4 @@ public interface SmsChannelMapper extends BaseMapperX<SmsChannelDO> {
.orderByDesc(SmsChannelDO::getId)); .orderByDesc(SmsChannelDO::getId));
} }
@Select("SELECT COUNT(*) FROM system_sms_channel WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
} }

View File

@ -7,17 +7,12 @@ import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTempla
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@Mapper @Mapper
public interface SmsTemplateMapper extends BaseMapperX<SmsTemplateDO> { public interface SmsTemplateMapper extends BaseMapperX<SmsTemplateDO> {
@Select("SELECT COUNT(*) FROM system_sms_template WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
default SmsTemplateDO selectByCode(String code) { default SmsTemplateDO selectByCode(String code) {
return selectOne(SmsTemplateDO::getCode, code); return selectOne(SmsTemplateDO::getCode, code);
} }

View File

@ -1,15 +1,13 @@
package cn.iocoder.yudao.module.system.dal.mysql.tenant; package cn.iocoder.yudao.module.system.dal.mysql.tenant;
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
/** /**
@ -52,7 +50,4 @@ public interface TenantMapper extends BaseMapperX<TenantDO> {
return selectList(TenantDO::getPackageId, packageId); return selectList(TenantDO::getPackageId, packageId);
} }
@Select("SELECT COUNT(*) FROM system_tenant WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
} }

View File

@ -17,6 +17,7 @@ import cn.iocoder.yudao.module.system.mq.producer.dept.DeptProducer;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -40,19 +41,13 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
@Slf4j @Slf4j
public class DeptServiceImpl implements DeptService { public class DeptServiceImpl implements DeptService {
/**
* 定时执行 {@link #schedulePeriodicRefresh()} 的周期
* 因为已经通过 Redis Pub/Sub 机制所以频率不需要高
*/
private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
/** /**
* 部门缓存 * 部门缓存
* key部门编号 {@link DeptDO#getId()} * key部门编号 {@link DeptDO#getId()}
* *
* 这里声明 volatile 修饰的原因是每次刷新时直接修改指向 * 这里声明 volatile 修饰的原因是每次刷新时直接修改指向
*/ */
@SuppressWarnings("FieldCanBeLocal") @Getter
private volatile Map<Long, DeptDO> deptCache; private volatile Map<Long, DeptDO> deptCache;
/** /**
* 父部门缓存 * 父部门缓存
@ -61,11 +56,8 @@ public class DeptServiceImpl implements DeptService {
* *
* 这里声明 volatile 修饰的原因是每次刷新时直接修改指向 * 这里声明 volatile 修饰的原因是每次刷新时直接修改指向
*/ */
@Getter
private volatile Multimap<Long, DeptDO> parentDeptCache; private volatile Multimap<Long, DeptDO> parentDeptCache;
/**
* 缓存部门的最大更新时间用于后续的增量轮询判断是否有更新
*/
private volatile LocalDateTime maxUpdateTime;
@Resource @Resource
private DeptMapper deptMapper; private DeptMapper deptMapper;
@ -79,48 +71,21 @@ public class DeptServiceImpl implements DeptService {
@Override @Override
@PostConstruct @PostConstruct
public synchronized void initLocalCache() { public synchronized void initLocalCache() {
initLocalCacheIfUpdate(null);
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
initLocalCacheIfUpdate(this.maxUpdateTime);
}
/**
* 刷新本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/
private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
// 注意忽略自动多租户因为要全局初始化缓存 // 注意忽略自动多租户因为要全局初始化缓存
TenantUtils.executeIgnore(() -> { TenantUtils.executeIgnore(() -> {
// 第一步基于 maxUpdateTime 判断缓存是否刷新 // 第一步查询数据
// 如果没有增量的数据变化则不进行本地缓存的刷新
if (maxUpdateTime != null
&& deptMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return;
}
List<DeptDO> depts = deptMapper.selectList(); List<DeptDO> depts = deptMapper.selectList();
log.info("[initLocalCacheIfUpdate][缓存部门,数量为:{}]", depts.size()); log.info("[initLocalCache][缓存部门,数量为:{}]", depts.size());
// 第二步构建缓存创建或更新支付 Client // 第二步构建缓存
// 构建缓存
ImmutableMap.Builder<Long, DeptDO> builder = ImmutableMap.builder(); ImmutableMap.Builder<Long, DeptDO> builder = ImmutableMap.builder();
ImmutableMultimap.Builder<Long, DeptDO> parentBuilder = ImmutableMultimap.builder(); ImmutableMultimap.Builder<Long, DeptDO> parentBuilder = ImmutableMultimap.builder();
depts.forEach(sysRoleDO -> { depts.forEach(sysRoleDO -> {
builder.put(sysRoleDO.getId(), sysRoleDO); builder.put(sysRoleDO.getId(), sysRoleDO);
parentBuilder.put(sysRoleDO.getParentId(), sysRoleDO); parentBuilder.put(sysRoleDO.getParentId(), sysRoleDO);
}); });
// 设置缓存
deptCache = builder.build(); deptCache = builder.build();
parentDeptCache = parentBuilder.build(); parentDeptCache = parentBuilder.build();
// 第三步设置最新的 maxUpdateTime用于下次的增量判断
this.maxUpdateTime = CollectionUtils.getMaxValue(depts, DeptDO::getUpdateTime);
}); });
} }

View File

@ -17,20 +17,17 @@ import com.google.common.annotations.VisibleForTesting;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
/** /**
@ -43,12 +40,6 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
@Slf4j @Slf4j
public class OAuth2ClientServiceImpl implements OAuth2ClientService { public class OAuth2ClientServiceImpl implements OAuth2ClientService {
/**
* 定时执行 {@link #schedulePeriodicRefresh()} 的周期
* 因为已经通过 Redis Pub/Sub 机制所以频率不需要高
*/
private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
/** /**
* 客户端缓存 * 客户端缓存
* key客户端编号 {@link OAuth2ClientDO#getClientId()} ()} * key客户端编号 {@link OAuth2ClientDO#getClientId()} ()}
@ -58,11 +49,6 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService {
@Getter // 解决单测 @Getter // 解决单测
@Setter // 解决单测 @Setter // 解决单测
private volatile Map<String, OAuth2ClientDO> clientCache; private volatile Map<String, OAuth2ClientDO> clientCache;
/**
* 缓存角色的最大更新时间用于后续的增量轮询判断是否有更新
*/
@Getter
private volatile LocalDateTime maxUpdateTime;
@Resource @Resource
private OAuth2ClientMapper oauth2ClientMapper; private OAuth2ClientMapper oauth2ClientMapper;
@ -76,37 +62,12 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService {
@Override @Override
@PostConstruct @PostConstruct
public void initLocalCache() { public void initLocalCache() {
initLocalCacheIfUpdate(null); // 第一步查询数据
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
initLocalCacheIfUpdate(this.maxUpdateTime);
}
/**
* 刷新本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/
private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步基于 maxUpdateTime 判断缓存是否刷新
// 如果没有增量的数据变化则不进行本地缓存的刷新
if (maxUpdateTime != null
&& oauth2ClientMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return;
}
List<OAuth2ClientDO> clients = oauth2ClientMapper.selectList(); List<OAuth2ClientDO> clients = oauth2ClientMapper.selectList();
log.info("[initLocalCacheIfUpdate][缓存 OAuth2 客户端,数量为:{}]", clients.size()); log.info("[initLocalCache][缓存 OAuth2 客户端,数量为:{}]", clients.size());
// 第二步构建缓存 // 第二步构建缓存
clientCache = convertMap(clients, OAuth2ClientDO::getClientId); clientCache = convertMap(clients, OAuth2ClientDO::getClientId);
// 第三步设置最新的 maxUpdateTime用于下次的增量判断
this.maxUpdateTime = getMaxValue(clients, OAuth2ClientDO::getUpdateTime);
} }
@Override @Override

View File

@ -18,9 +18,9 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronization;
@ -28,7 +28,6 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -43,18 +42,13 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
@Slf4j @Slf4j
public class MenuServiceImpl implements MenuService { public class MenuServiceImpl implements MenuService {
/**
* 定时执行 {@link #schedulePeriodicRefresh()} 的周期
* 因为已经通过 Redis Pub/Sub 机制所以频率不需要高
*/
private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
/** /**
* 菜单缓存 * 菜单缓存
* key菜单编号 * key菜单编号
* *
* 这里声明 volatile 修饰的原因是每次刷新时直接修改指向 * 这里声明 volatile 修饰的原因是每次刷新时直接修改指向
*/ */
@Getter
private volatile Map<Long, MenuDO> menuCache; private volatile Map<Long, MenuDO> menuCache;
/** /**
* 权限与菜单缓存 * 权限与菜单缓存
@ -63,11 +57,8 @@ public class MenuServiceImpl implements MenuService {
* *
* 这里声明 volatile 修饰的原因是每次刷新时直接修改指向 * 这里声明 volatile 修饰的原因是每次刷新时直接修改指向
*/ */
@Getter
private volatile Multimap<String, MenuDO> permissionMenuCache; private volatile Multimap<String, MenuDO> permissionMenuCache;
/**
* 缓存菜单的最大更新时间用于后续的增量轮询判断是否有更新
*/
private volatile LocalDateTime maxUpdateTime;
@Resource @Resource
private MenuMapper menuMapper; private MenuMapper menuMapper;
@ -86,33 +77,11 @@ public class MenuServiceImpl implements MenuService {
@Override @Override
@PostConstruct @PostConstruct
public synchronized void initLocalCache() { public synchronized void initLocalCache() {
initLocalCacheIfUpdate(null); // 第一步查询数据
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
initLocalCacheIfUpdate(this.maxUpdateTime);
}
/**
* 刷新本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/
private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步基于 maxUpdateTime 判断缓存是否刷新
// 如果没有增量的数据变化则不进行本地缓存的刷新
if (maxUpdateTime != null
&& menuMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return;
}
List<MenuDO> menuList = menuMapper.selectList(); List<MenuDO> menuList = menuMapper.selectList();
log.info("[initLocalCacheIfUpdate][缓存菜单,数量为:{}]", menuList.size()); log.info("[initLocalCache][缓存菜单,数量为:{}]", menuList.size());
// 第二步构建缓存 // 第二步构建缓存
ImmutableMap.Builder<Long, MenuDO> menuCacheBuilder = ImmutableMap.builder(); ImmutableMap.Builder<Long, MenuDO> menuCacheBuilder = ImmutableMap.builder();
ImmutableMultimap.Builder<String, MenuDO> permMenuCacheBuilder = ImmutableMultimap.builder(); ImmutableMultimap.Builder<String, MenuDO> permMenuCacheBuilder = ImmutableMultimap.builder();
menuList.forEach(menuDO -> { menuList.forEach(menuDO -> {
@ -123,9 +92,6 @@ public class MenuServiceImpl implements MenuService {
}); });
menuCache = menuCacheBuilder.build(); menuCache = menuCacheBuilder.build();
permissionMenuCache = permMenuCacheBuilder.build(); permissionMenuCache = permMenuCacheBuilder.build();
// 第三步设置最新的 maxUpdateTime用于下次的增量判断
this.maxUpdateTime = CollectionUtils.getMaxValue(menuList, MenuDO::getUpdateTime);
} }
@Override @Override
@ -219,7 +185,7 @@ public class MenuServiceImpl implements MenuService {
} }
// 创建新数组避免缓存被修改 // 创建新数组避免缓存被修改
return menuCache.values().stream().filter(menu -> menuTypes.contains(menu.getType()) return menuCache.values().stream().filter(menu -> menuTypes.contains(menu.getType())
&& menusStatuses.contains(menu.getStatus())) && menusStatuses.contains(menu.getStatus()))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@ -231,8 +197,8 @@ public class MenuServiceImpl implements MenuService {
return Collections.emptyList(); return Collections.emptyList();
} }
return menuCache.values().stream().filter(menu -> menuIds.contains(menu.getId()) return menuCache.values().stream().filter(menu -> menuIds.contains(menu.getId())
&& menuTypes.contains(menu.getType()) && menuTypes.contains(menu.getType())
&& menusStatuses.contains(menu.getStatus())) && menusStatuses.contains(menu.getStatus()))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@ -272,7 +238,7 @@ public class MenuServiceImpl implements MenuService {
} }
// 父菜单必须是目录或者菜单类型 // 父菜单必须是目录或者菜单类型
if (!MenuTypeEnum.DIR.getType().equals(menu.getType()) if (!MenuTypeEnum.DIR.getType().equals(menu.getType())
&& !MenuTypeEnum.MENU.getType().equals(menu.getType())) { && !MenuTypeEnum.MENU.getType().equals(menu.getType())) {
throw ServiceExceptionUtil.exception(MENU_PARENT_NOT_DIR_OR_MENU); throw ServiceExceptionUtil.exception(MENU_PARENT_NOT_DIR_OR_MENU);
} }
} }

View File

@ -16,9 +16,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO;
import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuBatchInsertMapper;
import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper; import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper;
import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleBatchInsertMapper;
import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper; import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper;
import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;
import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer; import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer;
@ -32,7 +30,6 @@ import com.google.common.collect.Sets;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronization;
@ -40,12 +37,10 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.function.Supplier; import java.util.function.Supplier;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue;
import static java.util.Collections.singleton; import static java.util.Collections.singleton;
/** /**
@ -57,12 +52,6 @@ import static java.util.Collections.singleton;
@Slf4j @Slf4j
public class PermissionServiceImpl implements PermissionService { public class PermissionServiceImpl implements PermissionService {
/**
* 定时执行 {@link #schedulePeriodicRefresh()} 的周期
* 因为已经通过 Redis Pub/Sub 机制所以频率不需要高
*/
private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
/** /**
* 角色编号与菜单编号的缓存映射 * 角色编号与菜单编号的缓存映射
* key角色编号 * key角色编号
@ -83,11 +72,6 @@ public class PermissionServiceImpl implements PermissionService {
@Getter @Getter
@Setter // 单元测试需要 @Setter // 单元测试需要
private volatile Multimap<Long, Long> menuRoleCache; private volatile Multimap<Long, Long> menuRoleCache;
/**
* 缓存 RoleMenu 的最大更新时间用于后续的增量轮询判断是否有更新
*/
@Getter
private volatile LocalDateTime roleMenuMaxUpdateTime;
/** /**
* 用户编号与角色编号的缓存映射 * 用户编号与角色编号的缓存映射
@ -99,20 +83,11 @@ public class PermissionServiceImpl implements PermissionService {
@Getter @Getter
@Setter // 单元测试需要 @Setter // 单元测试需要
private volatile Map<Long, Set<Long>> userRoleCache; private volatile Map<Long, Set<Long>> userRoleCache;
/**
* 缓存 UserRole 的最大更新时间用于后续的增量轮询判断是否有更新
*/
@Getter
private volatile LocalDateTime userRoleMaxUpdateTime;
@Resource @Resource
private RoleMenuMapper roleMenuMapper; private RoleMenuMapper roleMenuMapper;
@Resource @Resource
private RoleMenuBatchInsertMapper roleMenuBatchInsertMapper;
@Resource
private UserRoleMapper userRoleMapper; private UserRoleMapper userRoleMapper;
@Resource
private UserRoleBatchInsertMapper userRoleBatchInsertMapper;
@Resource @Resource
private RoleService roleService; private RoleService roleService;
@ -129,38 +104,22 @@ public class PermissionServiceImpl implements PermissionService {
@Override @Override
@PostConstruct @PostConstruct
public void initLocalCache() { public void initLocalCache() {
initLocalCacheIfUpdateForRoleMenu(null); initLocalCacheForRoleMenu();
initLocalCacheIfUpdateForUserRole(null); initLocalCacheForUserRole();
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
initLocalCacheIfUpdateForRoleMenu(this.roleMenuMaxUpdateTime);
initLocalCacheIfUpdateForUserRole(this.userRoleMaxUpdateTime);
} }
/** /**
* 刷新 RoleMenu 本地缓存 * 刷新 RoleMenu 本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/ */
@VisibleForTesting @VisibleForTesting
void initLocalCacheIfUpdateForRoleMenu(LocalDateTime maxUpdateTime) { void initLocalCacheForRoleMenu() {
// 注意忽略自动多租户因为要全局初始化缓存 // 注意忽略自动多租户因为要全局初始化缓存
TenantUtils.executeIgnore(() -> { TenantUtils.executeIgnore(() -> {
// 第一步基于 maxUpdateTime 判断缓存是否刷新 // 第一步查询数据
// 如果没有增量的数据变化则不进行本地缓存的刷新
if (maxUpdateTime != null
&& roleMenuMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdateForRoleMenu][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return;
}
List<RoleMenuDO> roleMenus = roleMenuMapper.selectList(); List<RoleMenuDO> roleMenus = roleMenuMapper.selectList();
log.info("[initLocalCacheIfUpdateForRoleMenu][缓存角色与菜单,数量为:{}]", roleMenus.size()); log.info("[initLocalCacheForRoleMenu][缓存角色与菜单,数量为:{}]", roleMenus.size());
// 第二步构建缓存 // 第二步构建缓存
ImmutableMultimap.Builder<Long, Long> roleMenuCacheBuilder = ImmutableMultimap.builder(); ImmutableMultimap.Builder<Long, Long> roleMenuCacheBuilder = ImmutableMultimap.builder();
ImmutableMultimap.Builder<Long, Long> menuRoleCacheBuilder = ImmutableMultimap.builder(); ImmutableMultimap.Builder<Long, Long> menuRoleCacheBuilder = ImmutableMultimap.builder();
roleMenus.forEach(roleMenuDO -> { roleMenus.forEach(roleMenuDO -> {
@ -169,40 +128,24 @@ public class PermissionServiceImpl implements PermissionService {
}); });
roleMenuCache = roleMenuCacheBuilder.build(); roleMenuCache = roleMenuCacheBuilder.build();
menuRoleCache = menuRoleCacheBuilder.build(); menuRoleCache = menuRoleCacheBuilder.build();
// 第三步设置最新的 maxUpdateTime用于下次的增量判断
this.roleMenuMaxUpdateTime = getMaxValue(roleMenus, RoleMenuDO::getUpdateTime);
}); });
} }
/** /**
* 刷新 UserRole 本地缓存 * 刷新 UserRole 本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/ */
@VisibleForTesting @VisibleForTesting
void initLocalCacheIfUpdateForUserRole(LocalDateTime maxUpdateTime) { void initLocalCacheForUserRole() {
// 注意忽略自动多租户因为要全局初始化缓存 // 注意忽略自动多租户因为要全局初始化缓存
TenantUtils.executeIgnore(() -> { TenantUtils.executeIgnore(() -> {
// 第一步基于 maxUpdateTime 判断缓存是否刷新 // 第一步加载数据
// 如果没有增量的数据变化则不进行本地缓存的刷新
if (maxUpdateTime != null
&& userRoleMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdateForUserRole][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return;
}
List<UserRoleDO> userRoles = userRoleMapper.selectList(); List<UserRoleDO> userRoles = userRoleMapper.selectList();
log.info("[initLocalCacheIfUpdateForUserRole][缓存用户与角色,数量为:{}]", userRoles.size()); log.info("[initLocalCacheForUserRole][缓存用户与角色,数量为:{}]", userRoles.size());
// 第二步构建缓存 // 第二步构建缓存
ImmutableMultimap.Builder<Long, Long> userRoleCacheBuilder = ImmutableMultimap.builder(); ImmutableMultimap.Builder<Long, Long> userRoleCacheBuilder = ImmutableMultimap.builder();
userRoles.forEach(userRoleDO -> userRoleCacheBuilder.put(userRoleDO.getUserId(), userRoleDO.getRoleId())); userRoles.forEach(userRoleDO -> userRoleCacheBuilder.put(userRoleDO.getUserId(), userRoleDO.getRoleId()));
userRoleCache = CollectionUtils.convertMultiMap2(userRoles, UserRoleDO::getUserId, UserRoleDO::getRoleId); userRoleCache = CollectionUtils.convertMultiMap2(userRoles, UserRoleDO::getUserId, UserRoleDO::getRoleId);
// 第三步设置最新的 maxUpdateTime用于下次的增量判断
this.userRoleMaxUpdateTime = getMaxValue(userRoles, UserRoleDO::getUpdateTime);
}); });
} }
@ -264,7 +207,7 @@ public class PermissionServiceImpl implements PermissionService {
Collection<Long> deleteMenuIds = CollUtil.subtract(dbMenuIds, menuIds); Collection<Long> deleteMenuIds = CollUtil.subtract(dbMenuIds, menuIds);
// 执行新增和删除对于已经授权的菜单不用做任何处理 // 执行新增和删除对于已经授权的菜单不用做任何处理
if (!CollectionUtil.isEmpty(createMenuIds)) { if (!CollectionUtil.isEmpty(createMenuIds)) {
roleMenuBatchInsertMapper.saveBatch(CollectionUtils.convertList(createMenuIds, menuId -> { roleMenuMapper.insertBatch(CollectionUtils.convertList(createMenuIds, menuId -> {
RoleMenuDO entity = new RoleMenuDO(); RoleMenuDO entity = new RoleMenuDO();
entity.setRoleId(roleId); entity.setRoleId(roleId);
entity.setMenuId(menuId); entity.setMenuId(menuId);
@ -308,7 +251,7 @@ public class PermissionServiceImpl implements PermissionService {
Collection<Long> deleteMenuIds = CollUtil.subtract(dbRoleIds, roleIds); Collection<Long> deleteMenuIds = CollUtil.subtract(dbRoleIds, roleIds);
// 执行新增和删除对于已经授权的角色不用做任何处理 // 执行新增和删除对于已经授权的角色不用做任何处理
if (!CollectionUtil.isEmpty(createRoleIds)) { if (!CollectionUtil.isEmpty(createRoleIds)) {
userRoleBatchInsertMapper.saveBatch(CollectionUtils.convertList(createRoleIds, roleId -> { userRoleMapper.insertBatch(CollectionUtils.convertList(createRoleIds, roleId -> {
UserRoleDO entity = new UserRoleDO(); UserRoleDO entity = new UserRoleDO();
entity.setUserId(userId); entity.setUserId(userId);
entity.setRoleId(roleId); entity.setRoleId(roleId);

View File

@ -6,7 +6,6 @@ import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO;
@ -22,9 +21,7 @@ import cn.iocoder.yudao.module.system.mq.producer.permission.RoleProducer;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronization;
@ -33,7 +30,6 @@ import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -49,12 +45,6 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
@Slf4j @Slf4j
public class RoleServiceImpl implements RoleService { public class RoleServiceImpl implements RoleService {
/**
* 定时执行 {@link #schedulePeriodicRefresh()} 的周期
* 因为已经通过 Redis Pub/Sub 机制所以频率不需要高
*/
private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
/** /**
* 角色缓存 * 角色缓存
* key角色编号 {@link RoleDO#getId()} * key角色编号 {@link RoleDO#getId()}
@ -63,11 +53,6 @@ public class RoleServiceImpl implements RoleService {
*/ */
@Getter @Getter
private volatile Map<Long, RoleDO> roleCache; private volatile Map<Long, RoleDO> roleCache;
/**
* 缓存角色的最大更新时间用于后续的增量轮询判断是否有更新
*/
@Getter
private volatile LocalDateTime maxUpdateTime;
@Resource @Resource
private PermissionService permissionService; private PermissionService permissionService;
@ -78,49 +63,20 @@ public class RoleServiceImpl implements RoleService {
@Resource @Resource
private RoleProducer roleProducer; private RoleProducer roleProducer;
@Resource
@Lazy // 注入自己所以延迟加载
private RoleService self;
/** /**
* 初始化 {@link #roleCache} 缓存 * 初始化 {@link #roleCache} 缓存
*/ */
@Override @Override
@PostConstruct @PostConstruct
public void initLocalCache() { public void initLocalCache() {
initLocalCacheIfUpdate(null);
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
initLocalCacheIfUpdate(this.maxUpdateTime);
}
/**
* 刷新本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/
private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
// 注意忽略自动多租户因为要全局初始化缓存 // 注意忽略自动多租户因为要全局初始化缓存
TenantUtils.executeIgnore(() -> { TenantUtils.executeIgnore(() -> {
// 第一步基于 maxUpdateTime 判断缓存是否刷新 // 第一步查询数据
// 如果没有增量的数据变化则不进行本地缓存的刷新
if (maxUpdateTime != null
&& roleMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return;
}
List<RoleDO> roleList = roleMapper.selectList(); List<RoleDO> roleList = roleMapper.selectList();
log.info("[initLocalCacheIfUpdate][缓存角色,数量为:{}]", roleList.size()); log.info("[initLocalCache][缓存角色,数量为:{}]", roleList.size());
// 第二步构建缓存 // 第二步构建缓存
roleCache = CollectionUtils.convertMap(roleList, RoleDO::getId); roleCache = CollectionUtils.convertMap(roleList, RoleDO::getId);
// 第三步设置最新的 maxUpdateTime用于下次的增量判断
this.maxUpdateTime = CollectionUtils.getMaxValue(roleList, RoleDO::getUpdateTime);
}); });
} }
@ -215,8 +171,8 @@ public class RoleServiceImpl implements RoleService {
@Override @Override
public List<RoleDO> getRoles(@Nullable Collection<Integer> statuses) { public List<RoleDO> getRoles(@Nullable Collection<Integer> statuses) {
if (CollUtil.isEmpty(statuses)) { if (CollUtil.isEmpty(statuses)) {
return roleMapper.selectList(); return roleMapper.selectList();
} }
return roleMapper.selectListByStatus(statuses); return roleMapper.selectListByStatus(statuses);
} }

View File

@ -17,13 +17,11 @@ import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
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;
@ -40,12 +38,6 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SENSITIVE_
@Validated @Validated
public class SensitiveWordServiceImpl implements SensitiveWordService { public class SensitiveWordServiceImpl implements SensitiveWordService {
/**
* 定时执行 {@link #schedulePeriodicRefresh()} 的周期
* 因为已经通过 Redis Pub/Sub 机制所以频率不需要高
*/
private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
/** /**
* 敏感词标签缓存 * 敏感词标签缓存
* key敏感词编号 {@link SensitiveWordDO#getId()} * key敏感词编号 {@link SensitiveWordDO#getId()}
@ -55,12 +47,6 @@ public class SensitiveWordServiceImpl implements SensitiveWordService {
@Getter @Getter
private volatile Set<String> sensitiveWordTagsCache = Collections.emptySet(); private volatile Set<String> sensitiveWordTagsCache = Collections.emptySet();
/**
* 缓存敏感词的最大更新时间用于后续的增量轮询判断是否有更新
*/
@Getter
private volatile LocalDateTime maxUpdateTime;
@Resource @Resource
private SensitiveWordMapper sensitiveWordMapper; private SensitiveWordMapper sensitiveWordMapper;
@ -84,42 +70,17 @@ public class SensitiveWordServiceImpl implements SensitiveWordService {
@Override @Override
@PostConstruct @PostConstruct
public void initLocalCache() { public void initLocalCache() {
initLocalCacheIfUpdate(null); // 第一步查询数据
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
initLocalCacheIfUpdate(this.maxUpdateTime);
}
/**
* 刷新本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/
private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步基于 maxUpdateTime 判断缓存是否刷新
// 如果没有增量的数据变化则不进行本地缓存的刷新
if (maxUpdateTime != null
&& sensitiveWordMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return;
}
List<SensitiveWordDO> sensitiveWords = sensitiveWordMapper.selectList(); List<SensitiveWordDO> sensitiveWords = sensitiveWordMapper.selectList();
log.info("[initLocalCacheIfUpdate][缓存敏感词,数量为:{}]", sensitiveWords.size()); log.info("[initLocalCache][缓存敏感词,数量为:{}]", sensitiveWords.size());
// 第二步构建缓存 // 第二步构建缓存
// 写入 sensitiveWordTagsCache 缓存 // 写入 sensitiveWordTagsCache 缓存
Set<String> tags = new HashSet<>(); Set<String> tags = new HashSet<>();
sensitiveWords.forEach(word -> tags.addAll(word.getTags())); sensitiveWords.forEach(word -> tags.addAll(word.getTags()));
sensitiveWordTagsCache = tags; sensitiveWordTagsCache = tags;
// 写入 defaultSensitiveWordTrietagSensitiveWordTries 缓存 // 写入 defaultSensitiveWordTrietagSensitiveWordTries 缓存
initSensitiveWordTrie(sensitiveWords); initSensitiveWordTrie(sensitiveWords);
// 第三步设置最新的 maxUpdateTime用于下次的增量判断
this.maxUpdateTime = CollectionUtils.getMaxValue(sensitiveWords, SensitiveWordDO::getUpdateTime);
} }
private void initSensitiveWordTrie(List<SensitiveWordDO> wordDOs) { private void initSensitiveWordTrie(List<SensitiveWordDO> wordDOs) {

View File

@ -1,8 +1,6 @@
package cn.iocoder.yudao.module.system.service.sms; package cn.iocoder.yudao.module.system.service.sms;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelCreateReqVO;
@ -13,22 +11,19 @@ import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper; import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper;
import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer; import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collection; import java.util.Collection;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS;
/** /**
* 短信渠道Service实现类 * 短信渠道 Service 实现类
* *
* @author zzf * @author zzf
*/ */
@ -36,17 +31,6 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNE
@Slf4j @Slf4j
public class SmsChannelServiceImpl implements SmsChannelService { public class SmsChannelServiceImpl implements SmsChannelService {
/**
* 定时执行 {@link #schedulePeriodicRefresh()} 的周期
* 因为已经通过 Redis Pub/Sub 机制所以频率不需要高
*/
private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
/**
* 缓存菜单的最大更新时间用于后续的增量轮询判断是否有更新
*/
private volatile LocalDateTime maxUpdateTime;
@Resource @Resource
private SmsClientFactory smsClientFactory; private SmsClientFactory smsClientFactory;
@ -62,38 +46,13 @@ public class SmsChannelServiceImpl implements SmsChannelService {
@Override @Override
@PostConstruct @PostConstruct
public void initLocalCache() { public void initLocalCache() {
initLocalCacheIfUpdate(null); // 第一步查询数据
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
initLocalCacheIfUpdate(this.maxUpdateTime);
}
/**
* 刷新本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/
private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步基于 maxUpdateTime 判断缓存是否刷新
// 如果没有增量的数据变化则不进行本地缓存的刷新
if (maxUpdateTime != null
&& smsChannelMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return;
}
List<SmsChannelDO> channels = smsChannelMapper.selectList(); List<SmsChannelDO> channels = smsChannelMapper.selectList();
log.info("[initLocalCacheIfUpdate][缓存短信渠道,数量为:{}]", channels.size()); log.info("[initLocalCache][缓存短信渠道,数量为:{}]", channels.size());
// 第二步构建缓存创建或更新短信 Client // 第二步构建缓存创建或更新短信 Client
List<SmsChannelProperties> propertiesList = SmsChannelConvert.INSTANCE.convertList02(channels); List<SmsChannelProperties> propertiesList = SmsChannelConvert.INSTANCE.convertList02(channels);
propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties)); propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties));
// 第三步设置最新的 maxUpdateTime用于下次的增量判断
this.maxUpdateTime = getMaxValue(channels, SmsChannelDO::getUpdateTime);
} }
@Override @Override

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.system.service.sms; package cn.iocoder.yudao.module.system.service.sms;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
@ -20,15 +19,17 @@ import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsTemplateMapper; import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsTemplateMapper;
import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer; import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime; import java.util.Collection;
import java.util.*; import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -44,12 +45,6 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
@Slf4j @Slf4j
public class SmsTemplateServiceImpl implements SmsTemplateService { public class SmsTemplateServiceImpl implements SmsTemplateService {
/**
* 定时执行 {@link #schedulePeriodicRefresh()} 的周期
* 因为已经通过 Redis Pub/Sub 机制所以频率不需要高
*/
private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
/** /**
* 正则表达式匹配 {} 中的变量 * 正则表达式匹配 {} 中的变量
*/ */
@ -73,51 +68,18 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
* *
* 这里声明 volatile 修饰的原因是每次刷新时直接修改指向 * 这里声明 volatile 修饰的原因是每次刷新时直接修改指向
*/ */
@Getter // 为了方便测试这里提供 getter 方法
private volatile Map<String, SmsTemplateDO> smsTemplateCache; private volatile Map<String, SmsTemplateDO> smsTemplateCache;
/**
* 缓存短信模板的最大更新时间用于后续的增量轮询判断是否有更新
*/
private volatile LocalDateTime maxUpdateTime;
@Override @Override
@PostConstruct @PostConstruct
public void initLocalCache() { public void initLocalCache() {
// 获取短信模板列表如果有更新 // 第一步查询数据
List<SmsTemplateDO> smsTemplateList = this.loadSmsTemplateIfUpdate(maxUpdateTime); List<SmsTemplateDO> smsTemplateList = smsTemplateMapper.selectList();
if (CollUtil.isEmpty(smsTemplateList)) { log.info("[initLocalCache][缓存短信模版,数量为:{}]", smsTemplateList.size());
return;
}
// 写入缓存 // 第二步构建缓存
smsTemplateCache = CollectionUtils.convertMap(smsTemplateList, SmsTemplateDO::getCode); smsTemplateCache = CollectionUtils.convertMap(smsTemplateList, SmsTemplateDO::getCode);
maxUpdateTime = CollectionUtils.getMaxValue(smsTemplateList, SmsTemplateDO::getUpdateTime);
log.info("[initLocalCache][初始化 SmsTemplate 数量为 {}]", smsTemplateList.size());
}
/**
* 如果短信模板发生变化从数据库中获取最新的全量短信模板
* 如果未发生变化则返回空
*
* @param maxUpdateTime 当前短信模板的最大更新时间
* @return 短信模板列表
*/
private List<SmsTemplateDO> loadSmsTemplateIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步判断是否要更新
if (maxUpdateTime == null) { // 如果更新时间为空说明 DB 一定有新数据
log.info("[loadSmsTemplateIfUpdate][首次加载全量短信模板]");
} else { // 判断数据库中是否有更新的短信模板
if (smsTemplateMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
return null;
}
log.info("[loadSmsTemplateIfUpdate][增量加载全量短信模板]");
}
// 第二步如果有更新则从数据库加载所有短信模板
return smsTemplateMapper.selectList();
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
initLocalCache();
} }
@Override @Override

View File

@ -25,8 +25,7 @@ import javax.validation.Validator;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
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 cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.AUTH_LOGIN_BAD_CREDENTIALS; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.AUTH_LOGIN_USER_DISABLED;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;

View File

@ -1,7 +1,10 @@
package cn.iocoder.yudao.module.system.service.dept; package cn.iocoder.yudao.module.system.service.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO; import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO; import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO;
@ -9,9 +12,6 @@ import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper; import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper;
import cn.iocoder.yudao.module.system.enums.dept.DeptIdEnum; import cn.iocoder.yudao.module.system.enums.dept.DeptIdEnum;
import cn.iocoder.yudao.module.system.mq.producer.dept.DeptProducer; import cn.iocoder.yudao.module.system.mq.producer.dept.DeptProducer;
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -19,17 +19,15 @@ import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import static cn.hutool.core.bean.BeanUtil.getFieldValue;
import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@ -56,8 +54,7 @@ public class DeptServiceTest extends BaseDbUnitTest {
} }
@Test @Test
@SuppressWarnings("unchecked") public void testInitLocalCache() {
void testInitLocalCache() {
// mock 数据 // mock 数据
DeptDO deptDO1 = randomDeptDO(); DeptDO deptDO1 = randomDeptDO();
deptMapper.insert(deptDO1); deptMapper.insert(deptDO1);
@ -67,18 +64,15 @@ public class DeptServiceTest extends BaseDbUnitTest {
// 调用 // 调用
deptService.initLocalCache(); deptService.initLocalCache();
// 断言 deptCache 缓存 // 断言 deptCache 缓存
Map<Long, DeptDO> deptCache = (Map<Long, DeptDO>) getFieldValue(deptService, "deptCache"); Map<Long, DeptDO> deptCache = deptService.getDeptCache();
assertEquals(2, deptCache.size()); assertEquals(2, deptCache.size());
assertPojoEquals(deptDO1, deptCache.get(deptDO1.getId())); assertPojoEquals(deptDO1, deptCache.get(deptDO1.getId()));
assertPojoEquals(deptDO2, deptCache.get(deptDO2.getId())); assertPojoEquals(deptDO2, deptCache.get(deptDO2.getId()));
// 断言 parentDeptCache 缓存 // 断言 parentDeptCache 缓存
Multimap<Long, DeptDO> parentDeptCache = (Multimap<Long, DeptDO>) getFieldValue(deptService, "parentDeptCache"); Multimap<Long, DeptDO> parentDeptCache = deptService.getParentDeptCache();
assertEquals(2, parentDeptCache.size()); assertEquals(2, parentDeptCache.size());
assertPojoEquals(deptDO1, parentDeptCache.get(deptDO1.getParentId())); assertPojoEquals(deptDO1, parentDeptCache.get(deptDO1.getParentId()));
assertPojoEquals(deptDO2, parentDeptCache.get(deptDO2.getParentId())); assertPojoEquals(deptDO2, parentDeptCache.get(deptDO2.getParentId()));
// 断言 maxUpdateTime 缓存
LocalDateTime maxUpdateTime = (LocalDateTime) getFieldValue(deptService, "maxUpdateTime");
assertEquals(ObjectUtils.max(deptDO1.getUpdateTime(), deptDO2.getUpdateTime()), maxUpdateTime);
} }
@Test @Test

View File

@ -19,7 +19,6 @@ import java.util.Collections;
import java.util.Map; import java.util.Map;
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.framework.common.util.object.ObjectUtils.max;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
@ -28,10 +27,10 @@ import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
/** /**
* {@link OAuth2ClientServiceImpl} 的单元测试类 * {@link OAuth2ClientServiceImpl} 的单元测试类
* *
* @author 芋道源码 * @author 芋道源码
*/ */
@Import(OAuth2ClientServiceImpl.class) @Import(OAuth2ClientServiceImpl.class)
public class OAuth2ClientServiceImplTest extends BaseDbUnitTest { public class OAuth2ClientServiceImplTest extends BaseDbUnitTest {
@ -59,8 +58,6 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest {
assertEquals(2, clientCache.size()); assertEquals(2, clientCache.size());
assertPojoEquals(clientDO1, clientCache.get(clientDO1.getClientId())); assertPojoEquals(clientDO1, clientCache.get(clientDO1.getClientId()));
assertPojoEquals(clientDO2, clientCache.get(clientDO2.getClientId())); assertPojoEquals(clientDO2, clientCache.get(clientDO2.getClientId()));
// 断言 maxUpdateTime 缓存
assertEquals(max(clientDO1.getUpdateTime(), clientDO2.getUpdateTime()), oauth2ClientService.getMaxUpdateTime());
} }
@Test @Test
@ -158,27 +155,27 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest {
@Test @Test
public void testGetOAuth2ClientPage() { public void testGetOAuth2ClientPage() {
// mock 数据 // mock 数据
OAuth2ClientDO dbOAuth2Client = randomPojo(OAuth2ClientDO.class, o -> { // 等会查询到 OAuth2ClientDO dbOAuth2Client = randomPojo(OAuth2ClientDO.class, o -> { // 等会查询到
o.setName("潜龙"); o.setName("潜龙");
o.setStatus(CommonStatusEnum.ENABLE.getStatus()); o.setStatus(CommonStatusEnum.ENABLE.getStatus());
}); });
oauth2ClientMapper.insert(dbOAuth2Client); oauth2ClientMapper.insert(dbOAuth2Client);
// 测试 name 不匹配 // 测试 name 不匹配
oauth2ClientMapper.insert(cloneIgnoreId(dbOAuth2Client, o -> o.setName("凤凰"))); oauth2ClientMapper.insert(cloneIgnoreId(dbOAuth2Client, o -> o.setName("凤凰")));
// 测试 status 不匹配 // 测试 status 不匹配
oauth2ClientMapper.insert(cloneIgnoreId(dbOAuth2Client, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); oauth2ClientMapper.insert(cloneIgnoreId(dbOAuth2Client, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 准备参数 // 准备参数
OAuth2ClientPageReqVO reqVO = new OAuth2ClientPageReqVO(); OAuth2ClientPageReqVO reqVO = new OAuth2ClientPageReqVO();
reqVO.setName(""); reqVO.setName("");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
// 调用 // 调用
PageResult<OAuth2ClientDO> pageResult = oauth2ClientService.getOAuth2ClientPage(reqVO); PageResult<OAuth2ClientDO> pageResult = oauth2ClientService.getOAuth2ClientPage(reqVO);
// 断言 // 断言
assertEquals(1, pageResult.getTotal()); assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size()); assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbOAuth2Client, pageResult.getList().get(0)); assertPojoEquals(dbOAuth2Client, pageResult.getList().get(0));
} }
@Test @Test

View File

@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.service.permission;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.common.util.spring.SpringAopUtils; import cn.iocoder.yudao.framework.common.util.spring.SpringAopUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuCreateReqVO;
@ -20,7 +19,6 @@ import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
@ -51,32 +49,24 @@ public class MenuServiceTest extends BaseDbUnitTest {
private TenantService tenantService; private TenantService tenantService;
@Test @Test
public void testInitLocalCache_success() throws Exception { public void testInitLocalCache_success() {
MenuDO menuDO1 = createMenuDO(MenuTypeEnum.MENU, "xxxx", 0L); MenuDO menuDO1 = randomPojo(MenuDO.class);
menuMapper.insert(menuDO1); menuMapper.insert(menuDO1);
MenuDO menuDO2 = createMenuDO(MenuTypeEnum.MENU, "xxxx", 0L); MenuDO menuDO2 = randomPojo(MenuDO.class);
menuMapper.insert(menuDO2); menuMapper.insert(menuDO2);
// 调用 // 调用
menuService.initLocalCache(); menuService.initLocalCache();
// 校验 menuCache 缓存
// 获取代理对象 Map<Long, MenuDO> menuCache = menuService.getMenuCache();
MenuServiceImpl target = (MenuServiceImpl) SpringAopUtils.getTarget(menuService);
Map<Long, MenuDO> menuCache =
(Map<Long, MenuDO>) BeanUtil.getFieldValue(target, "menuCache");
Assert.isTrue(menuCache.size() == 2); Assert.isTrue(menuCache.size() == 2);
assertPojoEquals(menuDO1, menuCache.get(menuDO1.getId())); assertPojoEquals(menuDO1, menuCache.get(menuDO1.getId()));
assertPojoEquals(menuDO2, menuCache.get(menuDO2.getId())); assertPojoEquals(menuDO2, menuCache.get(menuDO2.getId()));
// 校验 permissionMenuCache 缓存
Multimap<String, MenuDO> permissionMenuCache = Multimap<String, MenuDO> permissionMenuCache = menuService.getPermissionMenuCache();
(Multimap<String, MenuDO>) BeanUtil.getFieldValue(target, "permissionMenuCache");
Assert.isTrue(permissionMenuCache.size() == 2); Assert.isTrue(permissionMenuCache.size() == 2);
assertPojoEquals(menuDO1, permissionMenuCache.get(menuDO1.getPermission())); assertPojoEquals(menuDO1, permissionMenuCache.get(menuDO1.getPermission()));
assertPojoEquals(menuDO2, permissionMenuCache.get(menuDO2.getPermission())); assertPojoEquals(menuDO2, permissionMenuCache.get(menuDO2.getPermission()));
LocalDateTime maxUpdateTime = (LocalDateTime) BeanUtil.getFieldValue(target, "maxUpdateTime");
assertEquals(ObjectUtils.max(menuDO1.getUpdateTime(), menuDO2.getUpdateTime()), maxUpdateTime);
} }
@Test @Test

View File

@ -3,18 +3,15 @@ package cn.iocoder.yudao.module.system.service.permission;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuBatchInsertMapper;
import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper; import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper;
import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleBatchInsertMapper;
import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper; import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper;
import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;
import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer; import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer;
@ -27,8 +24,10 @@ import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime; import java.util.Collection;
import java.util.*; import java.util.List;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
@ -42,8 +41,7 @@ import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@Import({PermissionServiceImpl.class, @Import({PermissionServiceImpl.class})
RoleMenuBatchInsertMapper.class, UserRoleBatchInsertMapper.class})
public class PermissionServiceTest extends BaseDbUnitTest { public class PermissionServiceTest extends BaseDbUnitTest {
@Resource @Resource
@ -52,11 +50,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
@Resource @Resource
private RoleMenuMapper roleMenuMapper; private RoleMenuMapper roleMenuMapper;
@Resource @Resource
private RoleMenuBatchInsertMapper roleMenuBatchInsertMapper;
@Resource
private UserRoleMapper userRoleMapper; private UserRoleMapper userRoleMapper;
@Resource
private UserRoleBatchInsertMapper userRoleBatchInsertMapper;
@MockBean @MockBean
private RoleService roleService; private RoleService roleService;
@ -71,7 +65,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
private PermissionProducer permissionProducer; private PermissionProducer permissionProducer;
@Test @Test
public void testInitLocalCacheIfUpdateForRoleMenu() { public void testInitLocalCacheForRoleMenu() {
// mock 数据 // mock 数据
RoleMenuDO roleMenuDO01 = randomPojo(RoleMenuDO.class, o -> o.setRoleId(1L).setMenuId(10L)); RoleMenuDO roleMenuDO01 = randomPojo(RoleMenuDO.class, o -> o.setRoleId(1L).setMenuId(10L));
roleMenuMapper.insert(roleMenuDO01); roleMenuMapper.insert(roleMenuDO01);
@ -79,7 +73,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
roleMenuMapper.insert(roleMenuDO02); roleMenuMapper.insert(roleMenuDO02);
// 调用 // 调用
permissionService.initLocalCacheIfUpdateForRoleMenu(null); permissionService.initLocalCacheForRoleMenu();
// 断言 roleMenuCache 缓存 // 断言 roleMenuCache 缓存
assertEquals(1, permissionService.getRoleMenuCache().keySet().size()); assertEquals(1, permissionService.getRoleMenuCache().keySet().size());
assertEquals(asList(10L, 20L), permissionService.getRoleMenuCache().get(1L)); assertEquals(asList(10L, 20L), permissionService.getRoleMenuCache().get(1L));
@ -87,13 +81,10 @@ public class PermissionServiceTest extends BaseDbUnitTest {
assertEquals(2, permissionService.getMenuRoleCache().size()); assertEquals(2, permissionService.getMenuRoleCache().size());
assertEquals(singletonList(1L), permissionService.getMenuRoleCache().get(10L)); assertEquals(singletonList(1L), permissionService.getMenuRoleCache().get(10L));
assertEquals(singletonList(1L), permissionService.getMenuRoleCache().get(20L)); assertEquals(singletonList(1L), permissionService.getMenuRoleCache().get(20L));
// 断言 maxUpdateTime 缓存
LocalDateTime maxUpdateTime = permissionService.getRoleMenuMaxUpdateTime();
assertEquals(ObjectUtils.max(roleMenuDO01.getUpdateTime(), roleMenuDO02.getUpdateTime()), maxUpdateTime);
} }
@Test @Test
public void testInitLocalCacheIfUpdateForUserRole() { public void testInitLocalCacheForUserRole() {
// mock 数据 // mock 数据
UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L));
userRoleMapper.insert(userRoleDO01); userRoleMapper.insert(userRoleDO01);
@ -101,13 +92,10 @@ public class PermissionServiceTest extends BaseDbUnitTest {
userRoleMapper.insert(roleMenuDO02); userRoleMapper.insert(roleMenuDO02);
// 调用 // 调用
permissionService.initLocalCacheIfUpdateForUserRole(null); permissionService.initLocalCacheForUserRole();
// 断言 roleMenuCache 缓存 // 断言 roleMenuCache 缓存
assertEquals(1, permissionService.getUserRoleCache().size()); assertEquals(1, permissionService.getUserRoleCache().size());
assertEquals(asSet(10L, 20L), permissionService.getUserRoleCache().get(1L)); assertEquals(asSet(10L, 20L), permissionService.getUserRoleCache().get(1L));
// 断言 maxUpdateTime 缓存
LocalDateTime maxUpdateTime = permissionService.getUserRoleMaxUpdateTime();
assertEquals(ObjectUtils.max(userRoleDO01.getUpdateTime(), roleMenuDO02.getUpdateTime()), maxUpdateTime);
} }
@Test @Test

View File

@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.service.permission;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
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.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO;
@ -21,11 +20,9 @@ import org.springframework.context.annotation.Import;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildLocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.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.framework.common.util.object.ObjectUtils.max;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
@ -61,8 +58,6 @@ public class RoleServiceTest extends BaseDbUnitTest {
Map<Long, RoleDO> roleCache = roleService.getRoleCache(); Map<Long, RoleDO> roleCache = roleService.getRoleCache();
assertPojoEquals(roleDO1, roleCache.get(roleDO1.getId())); assertPojoEquals(roleDO1, roleCache.get(roleDO1.getId()));
assertPojoEquals(roleDO2, roleCache.get(roleDO2.getId())); assertPojoEquals(roleDO2, roleCache.get(roleDO2.getId()));
// 断言 maxUpdateTime 缓存
assertEquals(max(roleDO1.getUpdateTime(), roleDO2.getUpdateTime()), roleService.getMaxUpdateTime());
} }
@Test @Test
@ -129,7 +124,7 @@ public class RoleServiceTest extends BaseDbUnitTest {
Long roleId = roleDO.getId(); Long roleId = roleDO.getId();
//调用 //调用
Set<Long> deptIdSet = Arrays.asList(1L, 2L, 3L, 4L, 5L).stream().collect(Collectors.toSet()); Set<Long> deptIdSet = new HashSet<>(Arrays.asList(1L, 2L, 3L, 4L, 5L));
roleService.updateRoleDataScope(roleId, DataScopeEnum.DEPT_CUSTOM.getScope(), deptIdSet); roleService.updateRoleDataScope(roleId, DataScopeEnum.DEPT_CUSTOM.getScope(), deptIdSet);
//断言 //断言
@ -137,7 +132,7 @@ public class RoleServiceTest extends BaseDbUnitTest {
assertEquals(DataScopeEnum.DEPT_CUSTOM.getScope(), newRoleDO.getDataScope()); assertEquals(DataScopeEnum.DEPT_CUSTOM.getScope(), newRoleDO.getDataScope());
Set<Long> newDeptIdSet = newRoleDO.getDataScopeDeptIds(); Set<Long> newDeptIdSet = newRoleDO.getDataScopeDeptIds();
assertTrue(deptIdSet.size() == newDeptIdSet.size()); assertEquals(deptIdSet.size(), newDeptIdSet.size());
deptIdSet.stream().forEach(d -> assertTrue(newDeptIdSet.contains(d))); deptIdSet.stream().forEach(d -> assertTrue(newDeptIdSet.contains(d)));
verify(roleProducer).sendRoleRefreshMessage(); verify(roleProducer).sendRoleRefreshMessage();
@ -166,7 +161,7 @@ public class RoleServiceTest extends BaseDbUnitTest {
o.setName("土豆"); o.setName("土豆");
o.setCode("tudou"); o.setCode("tudou");
o.setStatus(CommonStatusEnum.ENABLE.getStatus()); o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setCreateTime(DateUtils.buildLocalDateTime(2022, 2, 8)); o.setCreateTime(buildTime(2022, 2, 8));
}); });
roleMapper.insert(dbRole); roleMapper.insert(dbRole);
// 测试 name 不匹配 // 测试 name 不匹配
@ -174,13 +169,13 @@ public class RoleServiceTest extends BaseDbUnitTest {
// 测试 code 不匹配 // 测试 code 不匹配
roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCode("hong"))); roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCode("hong")));
// 测试 createTime 不匹配 // 测试 createTime 不匹配
roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCreateTime(DateUtils.buildLocalDateTime(2022, 2, 16)))); roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCreateTime(buildTime(2022, 2, 16))));
// 准备参数 // 准备参数
RoleExportReqVO reqVO = new RoleExportReqVO(); RoleExportReqVO reqVO = new RoleExportReqVO();
reqVO.setName("土豆"); reqVO.setName("土豆");
reqVO.setCode("tu"); reqVO.setCode("tu");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setCreateTime((new LocalDateTime[]{buildLocalDateTime(2022, 2, 1),buildLocalDateTime(2022, 2, 12)})); reqVO.setCreateTime((new LocalDateTime[]{buildTime(2022, 2, 1),buildTime(2022, 2, 12)}));
// 调用 // 调用
List<RoleDO> list = roleService.getRoleList(reqVO); List<RoleDO> list = roleService.getRoleList(reqVO);
@ -196,7 +191,7 @@ public class RoleServiceTest extends BaseDbUnitTest {
o.setName("土豆"); o.setName("土豆");
o.setCode("tudou"); o.setCode("tudou");
o.setStatus(CommonStatusEnum.ENABLE.getStatus()); o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setCreateTime(DateUtils.buildLocalDateTime(2022, 2, 8)); o.setCreateTime(buildTime(2022, 2, 8));
}); });
roleMapper.insert(dbRole); roleMapper.insert(dbRole);
// 测试 name 不匹配 // 测试 name 不匹配
@ -204,13 +199,13 @@ public class RoleServiceTest extends BaseDbUnitTest {
// 测试 code 不匹配 // 测试 code 不匹配
roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCode("hong"))); roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCode("hong")));
// 测试 createTime 不匹配 // 测试 createTime 不匹配
roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCreateTime(DateUtils.buildLocalDateTime(2022, 2, 16)))); roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCreateTime(buildTime(2022, 2, 16))));
// 准备参数 // 准备参数
RolePageReqVO reqVO = new RolePageReqVO(); RolePageReqVO reqVO = new RolePageReqVO();
reqVO.setName("土豆"); reqVO.setName("土豆");
reqVO.setCode("tu"); reqVO.setCode("tu");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setCreateTime((new LocalDateTime[]{buildLocalDateTime(2022, 2, 1),buildLocalDateTime(2022, 2, 12)})); reqVO.setCreateTime((new LocalDateTime[]{buildTime(2022, 2, 1),buildTime(2022, 2, 12)}));
// 调用 // 调用
PageResult<RoleDO> pageResult = roleService.getRolePage(reqVO); PageResult<RoleDO> pageResult = roleService.getRolePage(reqVO);

View File

@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.service.sensitiveword;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils; import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordExportReqVO;
@ -21,7 +20,7 @@ import java.time.LocalDateTime;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildLocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.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.framework.common.util.object.ObjectUtils.max; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
@ -61,8 +60,6 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
// 调用 // 调用
sensitiveWordService.initLocalCache(); sensitiveWordService.initLocalCache();
// 断言 maxUpdateTime 缓存
assertEquals(max(wordDO1.getUpdateTime(), wordDO2.getUpdateTime()), sensitiveWordService.getMaxUpdateTime());
// 断言 sensitiveWordTagsCache 缓存 // 断言 sensitiveWordTagsCache 缓存
assertEquals(SetUtils.asSet("论坛", "蔬菜"), sensitiveWordService.getSensitiveWordTags()); assertEquals(SetUtils.asSet("论坛", "蔬菜"), sensitiveWordService.getSensitiveWordTags());
// 断言 tagSensitiveWordTries 缓存 // 断言 tagSensitiveWordTries 缓存
@ -145,7 +142,7 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
o.setName("笨蛋"); o.setName("笨蛋");
o.setTags(Arrays.asList("论坛", "蔬菜")); o.setTags(Arrays.asList("论坛", "蔬菜"));
o.setStatus(CommonStatusEnum.ENABLE.getStatus()); o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setCreateTime(DateUtils.buildLocalDateTime(2022, 2, 8)); o.setCreateTime(buildTime(2022, 2, 8));
}); });
sensitiveWordMapper.insert(dbSensitiveWord); sensitiveWordMapper.insert(dbSensitiveWord);
// 测试 name 不匹配 // 测试 name 不匹配
@ -153,13 +150,13 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
// 测试 tags 不匹配 // 测试 tags 不匹配
sensitiveWordMapper.insert(cloneIgnoreId(dbSensitiveWord, o -> o.setTags(Arrays.asList("短信", "日用品")))); sensitiveWordMapper.insert(cloneIgnoreId(dbSensitiveWord, o -> o.setTags(Arrays.asList("短信", "日用品"))));
// 测试 createTime 不匹配 // 测试 createTime 不匹配
sensitiveWordMapper.insert(cloneIgnoreId(dbSensitiveWord, o -> o.setCreateTime(DateUtils.buildLocalDateTime(2022, 2, 16)))); sensitiveWordMapper.insert(cloneIgnoreId(dbSensitiveWord, o -> o.setCreateTime(buildTime(2022, 2, 16))));
// 准备参数 // 准备参数
SensitiveWordPageReqVO reqVO = new SensitiveWordPageReqVO(); SensitiveWordPageReqVO reqVO = new SensitiveWordPageReqVO();
reqVO.setName(""); reqVO.setName("");
reqVO.setTag("论坛"); reqVO.setTag("论坛");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setCreateTime((new LocalDateTime[]{buildLocalDateTime(2022, 2, 1),buildLocalDateTime(2022, 2, 12)})); reqVO.setCreateTime((new LocalDateTime[]{buildTime(2022, 2, 1),buildTime(2022, 2, 12)}));
// 调用 // 调用
PageResult<SensitiveWordDO> pageResult = sensitiveWordService.getSensitiveWordPage(reqVO); PageResult<SensitiveWordDO> pageResult = sensitiveWordService.getSensitiveWordPage(reqVO);
@ -176,7 +173,7 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
o.setName("笨蛋"); o.setName("笨蛋");
o.setTags(Arrays.asList("论坛", "蔬菜")); o.setTags(Arrays.asList("论坛", "蔬菜"));
o.setStatus(CommonStatusEnum.ENABLE.getStatus()); o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setCreateTime(DateUtils.buildLocalDateTime(2022, 2, 8)); o.setCreateTime(buildTime(2022, 2, 8));
}); });
sensitiveWordMapper.insert(dbSensitiveWord); sensitiveWordMapper.insert(dbSensitiveWord);
// 测试 name 不匹配 // 测试 name 不匹配
@ -184,13 +181,13 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
// 测试 tags 不匹配 // 测试 tags 不匹配
sensitiveWordMapper.insert(cloneIgnoreId(dbSensitiveWord, o -> o.setTags(Arrays.asList("短信", "日用品")))); sensitiveWordMapper.insert(cloneIgnoreId(dbSensitiveWord, o -> o.setTags(Arrays.asList("短信", "日用品"))));
// 测试 createTime 不匹配 // 测试 createTime 不匹配
sensitiveWordMapper.insert(cloneIgnoreId(dbSensitiveWord, o -> o.setCreateTime(DateUtils.buildLocalDateTime(2022, 2, 16)))); sensitiveWordMapper.insert(cloneIgnoreId(dbSensitiveWord, o -> o.setCreateTime(buildTime(2022, 2, 16))));
// 准备参数 // 准备参数
SensitiveWordExportReqVO reqVO = new SensitiveWordExportReqVO(); SensitiveWordExportReqVO reqVO = new SensitiveWordExportReqVO();
reqVO.setName(""); reqVO.setName("");
reqVO.setTag("论坛"); reqVO.setTag("论坛");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setCreateTime((new LocalDateTime[]{buildLocalDateTime(2022, 2, 1),buildLocalDateTime(2022, 2, 12)})); reqVO.setCreateTime((new LocalDateTime[]{buildTime(2022, 2, 1),buildTime(2022, 2, 12)}));
// 调用 // 调用
List<SensitiveWordDO> list = sensitiveWordService.getSensitiveWordList(reqVO); List<SensitiveWordDO> list = sensitiveWordService.getSensitiveWordList(reqVO);

View File

@ -1,18 +1,17 @@
package cn.iocoder.yudao.module.system.service.sms; package cn.iocoder.yudao.module.system.service.sms;
import cn.hutool.core.bean.BeanUtil;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelUpdateReqVO;
import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper;
import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
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.object.ObjectUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelUpdateReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper;
import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
@ -22,12 +21,11 @@ import java.time.LocalDateTime;
import java.util.function.Consumer; import java.util.function.Consumer;
import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN; import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildLocalDateTime;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS;
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.eq;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ -58,9 +56,6 @@ public class SmsChannelServiceTest extends BaseDbUnitTest {
// 调用 // 调用
smsChannelService.initLocalCache(); smsChannelService.initLocalCache();
// 校验 maxUpdateTime 属性
LocalDateTime maxUpdateTime = (LocalDateTime) BeanUtil.getFieldValue(smsChannelService, "maxUpdateTime");
assertEquals(max(smsChannelDO01.getUpdateTime(), smsChannelDO02.getUpdateTime()), maxUpdateTime);
// 校验调用 // 校验调用
verify(smsClientFactory, times(1)).createOrUpdateSmsClient( verify(smsClientFactory, times(1)).createOrUpdateSmsClient(
argThat(properties -> isPojoEquals(smsChannelDO01, properties))); argThat(properties -> isPojoEquals(smsChannelDO01, properties)));
@ -159,7 +154,7 @@ public class SmsChannelServiceTest extends BaseDbUnitTest {
SmsChannelDO dbSmsChannel = randomPojo(SmsChannelDO.class, o -> { // 等会查询到 SmsChannelDO dbSmsChannel = randomPojo(SmsChannelDO.class, o -> { // 等会查询到
o.setSignature("芋道源码"); o.setSignature("芋道源码");
o.setStatus(CommonStatusEnum.ENABLE.getStatus()); o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setCreateTime(buildLocalDateTime(2020, 12, 12)); o.setCreateTime(buildTime(2020, 12, 12));
}); });
smsChannelMapper.insert(dbSmsChannel); smsChannelMapper.insert(dbSmsChannel);
// 测试 signature 不匹配 // 测试 signature 不匹配
@ -167,12 +162,12 @@ public class SmsChannelServiceTest extends BaseDbUnitTest {
// 测试 status 不匹配 // 测试 status 不匹配
smsChannelMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsChannel, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); smsChannelMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsChannel, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 createTime 不匹配 // 测试 createTime 不匹配
smsChannelMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsChannel, o -> o.setCreateTime(buildLocalDateTime(2020, 11, 11)))); smsChannelMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsChannel, o -> o.setCreateTime(buildTime(2020, 11, 11))));
// 准备参数 // 准备参数
SmsChannelPageReqVO reqVO = new SmsChannelPageReqVO(); SmsChannelPageReqVO reqVO = new SmsChannelPageReqVO();
reqVO.setSignature("芋道"); reqVO.setSignature("芋道");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setCreateTime((new LocalDateTime[]{buildLocalDateTime(2020, 12, 1),buildLocalDateTime(2020, 12, 24)})); reqVO.setCreateTime((new LocalDateTime[]{buildTime(2020, 12, 1),buildTime(2020, 12, 24)}));
// 调用 // 调用
PageResult<SmsChannelDO> pageResult = smsChannelService.getSmsChannelPage(reqVO); PageResult<SmsChannelDO> pageResult = smsChannelService.getSmsChannelPage(reqVO);

View File

@ -34,7 +34,7 @@ import static cn.hutool.core.bean.BeanUtil.getFieldValue;
import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildLocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
@ -61,7 +61,6 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest {
private SmsProducer smsProducer; private SmsProducer smsProducer;
@Test @Test
@SuppressWarnings("unchecked")
void testInitLocalCache() { void testInitLocalCache() {
// mock 数据 // mock 数据
SmsTemplateDO smsTemplate01 = randomSmsTemplateDO(); SmsTemplateDO smsTemplate01 = randomSmsTemplateDO();
@ -72,13 +71,10 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest {
// 调用 // 调用
smsTemplateService.initLocalCache(); smsTemplateService.initLocalCache();
// 断言 deptCache 缓存 // 断言 deptCache 缓存
Map<String, SmsTemplateDO> smsTemplateCache = (Map<String, SmsTemplateDO>) getFieldValue(smsTemplateService, "smsTemplateCache"); Map<String, SmsTemplateDO> smsTemplateCache = smsTemplateService.getSmsTemplateCache();
assertEquals(2, smsTemplateCache.size()); assertEquals(2, smsTemplateCache.size());
assertPojoEquals(smsTemplate01, smsTemplateCache.get(smsTemplate01.getCode())); assertPojoEquals(smsTemplate01, smsTemplateCache.get(smsTemplate01.getCode()));
assertPojoEquals(smsTemplate02, smsTemplateCache.get(smsTemplate02.getCode())); assertPojoEquals(smsTemplate02, smsTemplateCache.get(smsTemplate02.getCode()));
// 断言 maxUpdateTime 缓存
LocalDateTime maxUpdateTime = (LocalDateTime) getFieldValue(smsTemplateService, "maxUpdateTime");
assertEquals(max(smsTemplate01.getUpdateTime(), smsTemplate02.getUpdateTime()), maxUpdateTime);
} }
@Test @Test
@ -205,7 +201,7 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest {
o.setContent("芋道源码"); o.setContent("芋道源码");
o.setApiTemplateId("yunai"); o.setApiTemplateId("yunai");
o.setChannelId(1L); o.setChannelId(1L);
o.setCreateTime(buildLocalDateTime(2021, 11, 11)); o.setCreateTime(buildTime(2021, 11, 11));
}); });
smsTemplateMapper.insert(dbSmsTemplate); smsTemplateMapper.insert(dbSmsTemplate);
// 测试 type 不匹配 // 测试 type 不匹配
@ -221,7 +217,7 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest {
// 测试 channelId 不匹配 // 测试 channelId 不匹配
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L))); smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L)));
// 测试 createTime 不匹配 // 测试 createTime 不匹配
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCreateTime(buildLocalDateTime(2021, 12, 12)))); smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12))));
// 准备参数 // 准备参数
SmsTemplatePageReqVO reqVO = new SmsTemplatePageReqVO(); SmsTemplatePageReqVO reqVO = new SmsTemplatePageReqVO();
reqVO.setType(SmsTemplateTypeEnum.PROMOTION.getType()); reqVO.setType(SmsTemplateTypeEnum.PROMOTION.getType());
@ -230,7 +226,7 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest {
reqVO.setContent("芋道"); reqVO.setContent("芋道");
reqVO.setApiTemplateId("yu"); reqVO.setApiTemplateId("yu");
reqVO.setChannelId(1L); reqVO.setChannelId(1L);
reqVO.setCreateTime((new LocalDateTime[]{buildLocalDateTime(2021, 11, 1),buildLocalDateTime(2021, 12, 1)})); reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 11, 1),buildTime(2021, 12, 1)}));
// 调用 // 调用
PageResult<SmsTemplateDO> pageResult = smsTemplateService.getSmsTemplatePage(reqVO); PageResult<SmsTemplateDO> pageResult = smsTemplateService.getSmsTemplatePage(reqVO);
@ -250,7 +246,7 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest {
o.setContent("芋道源码"); o.setContent("芋道源码");
o.setApiTemplateId("yunai"); o.setApiTemplateId("yunai");
o.setChannelId(1L); o.setChannelId(1L);
o.setCreateTime(buildLocalDateTime(2021, 11, 11)); o.setCreateTime(buildTime(2021, 11, 11));
}); });
smsTemplateMapper.insert(dbSmsTemplate); smsTemplateMapper.insert(dbSmsTemplate);
// 测试 type 不匹配 // 测试 type 不匹配
@ -266,7 +262,7 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest {
// 测试 channelId 不匹配 // 测试 channelId 不匹配
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L))); smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L)));
// 测试 createTime 不匹配 // 测试 createTime 不匹配
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCreateTime(buildLocalDateTime(2021, 12, 12)))); smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12))));
// 准备参数 // 准备参数
SmsTemplateExportReqVO reqVO = new SmsTemplateExportReqVO(); SmsTemplateExportReqVO reqVO = new SmsTemplateExportReqVO();
reqVO.setType(SmsTemplateTypeEnum.PROMOTION.getType()); reqVO.setType(SmsTemplateTypeEnum.PROMOTION.getType());
@ -275,8 +271,7 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest {
reqVO.setContent("芋道"); reqVO.setContent("芋道");
reqVO.setApiTemplateId("yu"); reqVO.setApiTemplateId("yu");
reqVO.setChannelId(1L); reqVO.setChannelId(1L);
reqVO.setCreateTime((new LocalDateTime[]{buildLocalDateTime(2021, 11, 1), reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 11, 1),buildTime(2021, 12, 1)}));
buildLocalDateTime(2021, 12, 1)}));
// 调用 // 调用
List<SmsTemplateDO> list = smsTemplateService.getSmsTemplateList(reqVO); List<SmsTemplateDO> list = smsTemplateService.getSmsTemplateList(reqVO);