From 45714085901f473b72c05814b057799d874c0a64 Mon Sep 17 00:00:00 2001 From: fjlinhua Date: Wed, 15 Mar 2023 15:43:09 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=A2=9E=E5=8A=A0=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruoyi/cache/annotation/OrgCacheKey.java | 25 +++ .../cache/annotation/OrgCacheTypeNum.java | 11 ++ .../ruoyi/cache/annotation/OrgCacheValue.java | 25 +++ .../com/ruoyi/cache/domain/BaseCache.java | 34 ++++ .../com/ruoyi/cache/domain/CacheSysDept.java | 70 +++++++ .../com/ruoyi/cache/domain/CacheSysUser.java | 77 ++++++++ .../ruoyi/cache/service/CacheCallBack.java | 179 ++++++++++++++++++ .../ruoyi/cache/service/IOrgCacheService.java | 58 ++++++ .../com/ruoyi/system/CacheConfigurer.java | 29 +++ .../service/impl/OrgCacheServiceImpl.java | 160 ++++++++++++++++ .../com/ruoyi/util/IRedisNotifyHandle.java | 22 +++ .../com/ruoyi/util/ISpringLoadComplete.java | 12 ++ .../com/ruoyi/util/RedisNotifyService.java | 142 ++++++++++++++ .../com/ruoyi/util/SpringLoadComplete.java | 45 +++++ .../src/main/resources/ehcache.xml | 27 +++ .../system/service/CacheCallBackPojo.java | 56 ++++++ .../system/service/CacheCallBackPojo2.java | 59 ++++++ .../system/service/CacheCallBackTest.java | 36 ++++ .../impl/BulletinInfoServiceImplTest.java | 35 ++++ .../src/test/resources/bootstrap.yml | 25 +++ 20 files changed, 1127 insertions(+) create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/annotation/OrgCacheKey.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/annotation/OrgCacheTypeNum.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/annotation/OrgCacheValue.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/domain/BaseCache.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/domain/CacheSysDept.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/domain/CacheSysUser.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/service/CacheCallBack.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/service/IOrgCacheService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/CacheConfigurer.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrgCacheServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/IRedisNotifyHandle.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/ISpringLoadComplete.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/RedisNotifyService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/SpringLoadComplete.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/ehcache.xml create mode 100644 ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/CacheCallBackPojo.java create mode 100644 ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/CacheCallBackPojo2.java create mode 100644 ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/CacheCallBackTest.java create mode 100644 ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/impl/BulletinInfoServiceImplTest.java create mode 100644 ruoyi-modules/ruoyi-system/src/test/resources/bootstrap.yml diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/annotation/OrgCacheKey.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/annotation/OrgCacheKey.java new file mode 100644 index 00000000..0524ee07 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/annotation/OrgCacheKey.java @@ -0,0 +1,25 @@ +package com.ruoyi.cache.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 缓存的关键字ID + * @author Administrator + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +@Documented +public @interface OrgCacheKey { + String id() default "user"; + /** + * 缓存的类型:目前可以是CacheStaffInfo,CacheDeptInfo,CacheCompanyInfo + * @return + */ + OrgCacheTypeNum type() default OrgCacheTypeNum.CacheUserInfo; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/annotation/OrgCacheTypeNum.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/annotation/OrgCacheTypeNum.java new file mode 100644 index 00000000..aa88eb28 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/annotation/OrgCacheTypeNum.java @@ -0,0 +1,11 @@ +package com.ruoyi.cache.annotation; +/** + * 缓存的类型 + * @author Administrator + * + */ +public enum OrgCacheTypeNum { + CacheUserInfo, //员工的cache + CacheDeptInfo,//部门的cache + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/annotation/OrgCacheValue.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/annotation/OrgCacheValue.java new file mode 100644 index 00000000..2ad432ca --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/annotation/OrgCacheValue.java @@ -0,0 +1,25 @@ +/** + * + */ +package com.ruoyi.cache.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 获取组织架构的缓存,声明一个pojo的属性映射值 + * @author Condy + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +@Documented +public @interface OrgCacheValue { + //CacheValueNum value() default CacheStaffInfoNum.staffId; + String value() default ""; + String id() default "user"; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/domain/BaseCache.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/domain/BaseCache.java new file mode 100644 index 00000000..1db3d618 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/domain/BaseCache.java @@ -0,0 +1,34 @@ +package com.ruoyi.cache.domain; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +import org.nutz.dao.entity.annotation.Column; +import org.nutz.lang.Mirror; + +public class BaseCache { + + /** + * POJO转换成Map + * @return + */ + public Map toMap(){ + Mirror mirror = Mirror.me(getClass()); + Field[] flds = mirror.getFields(); + Map pojoMap=new HashMap(); + for (Field fld : flds) { + Object v = mirror.getValue(this, fld); + if (null == v) {//等与null就不生成map + continue; + } else if(fld.isAnnotationPresent(Column.class)){ + String cv = fld.getAnnotation(Column.class).value(); + pojoMap.put(cv, v.toString()); + } else{ + pojoMap.put(fld.getName(), v.toString()); + } + } + return pojoMap; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/domain/CacheSysDept.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/domain/CacheSysDept.java new file mode 100644 index 00000000..3edf8849 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/domain/CacheSysDept.java @@ -0,0 +1,70 @@ +package com.ruoyi.cache.domain; + +import com.ruoyi.system.api.domain.SysDept; + +public class CacheSysDept extends BaseCache{ + /** + * @OrgCacheValue的 value类型 + */ + public final static String ANNOTAION_DEPT_ID="deptId"; + public final static String ANNOTAION_PARENT_ID="parentId"; + public final static String ANNOTAION_DEPT_NAME="deptName"; + public final static String ANNOTAION_PARENT_NAME="parentName"; + + /** 部门ID */ + private Long deptId; + + /** 父部门ID */ + private Long parentId; + + /** 部门名称 */ + private String deptName; + + /** 父部门名称 */ + private String parentName; + + public CacheSysDept(SysDept dept) { + this.deptId=dept.getDeptId(); + this.parentId=dept.getParentId(); + this.deptName=dept.getDeptName(); + this.parentName=dept.getParentName(); + } + + public CacheSysDept() { + + } + + public Long getDeptId() { + return deptId; + } + + public void setDeptId(Long deptId) { + this.deptId = deptId; + } + + public Long getParentId() { + return parentId; + } + + public void setParentId(Long parentId) { + this.parentId = parentId; + } + + public String getDeptName() { + return deptName; + } + + public void setDeptName(String deptName) { + this.deptName = deptName; + } + + public String getParentName() { + return parentName; + } + + public void setParentName(String parentName) { + this.parentName = parentName; + } + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/domain/CacheSysUser.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/domain/CacheSysUser.java new file mode 100644 index 00000000..4fd5a6d6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/domain/CacheSysUser.java @@ -0,0 +1,77 @@ +package com.ruoyi.cache.domain; + +import com.ruoyi.system.api.domain.SysUser; +/** + * 存储在redis上的用户缓存 + * @author condy + * + */ +public class CacheSysUser extends BaseCache { + /** + * @OrgCacheValue的 value类型 + */ + public final static String ANNOTAION_USER_ID="userId"; + public final static String ANNOTAION_USER_NAME="userName"; + public final static String ANNOTAION_DEPT_ID="deptId"; + public final static String ANNOTAION_EMAIL="email"; + public final static String ANNOTAION_PHONENUMBER="phonenumber"; + + + + private Long userId; + private String userName; + private Long deptId; + private String nickName; + private String email; + private String phonenumber; + + public CacheSysUser(SysUser user) { + this.userId=user.getUserId(); + this.userName=user.getUserName(); + this.deptId=user.getDeptId(); + this.nickName=user.getNickName(); + this.email=user.getEmail(); + this.phonenumber=user.getEmail(); + } + public CacheSysUser() + { + + } + public Long getUserId() { + return userId; + } + public void setUserId(Long userId) { + this.userId = userId; + } + public String getUserName() { + return userName; + } + public void setUserName(String userName) { + this.userName = userName; + } + public Long getDeptId() { + return deptId; + } + public void setDeptId(Long deptId) { + this.deptId = deptId; + } + public String getNickName() { + return nickName; + } + public void setNickName(String nickName) { + this.nickName = nickName; + } + public String getEmail() { + return email; + } + public void setEmail(String email) { + this.email = email; + } + public String getPhonenumber() { + return phonenumber; + } + public void setPhonenumber(String phonenumber) { + this.phonenumber = phonenumber; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/service/CacheCallBack.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/service/CacheCallBack.java new file mode 100644 index 00000000..a7b43d7e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/service/CacheCallBack.java @@ -0,0 +1,179 @@ +package com.ruoyi.cache.service; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.nutz.lang.ContinueLoop; +import org.nutz.lang.Each; +import org.nutz.lang.ExitLoop; +import org.nutz.lang.LoopException; +import org.nutz.lang.Mirror; +import org.nutz.log.Log; +import org.nutz.log.Logs; + +import com.ruoyi.cache.annotation.OrgCacheKey; +import com.ruoyi.cache.annotation.OrgCacheTypeNum; +import com.ruoyi.cache.annotation.OrgCacheValue; +import com.ruoyi.cache.domain.BaseCache; +import com.ruoyi.cache.domain.CacheSysDept; +import com.ruoyi.cache.domain.CacheSysUser; +import com.ruoyi.common.core.utils.SpringUtils; + +/** + * @OrgCacheKey + * @OrgCacheValue的注解的处理类 + * @author + * + * @param + */ +public class CacheCallBack implements Each { + private Log log=Logs.get(); + private class InnerCacheCallBack { + //@OrgCacheKey的注解的属性 + private Field orgCacheKeyField; + private OrgCacheKey orgCacheKey;// @OrgCacheKey对象 + //与OrgCacheKey的key相关的OrgCacheValue注解对象及对象的Field + private Map orgCacheValueFieldMap=new HashMap(); + //CacheStaffInfo,CacheDeptInfo,CacheCopanyInfo的放射封装类 + private Mirror cacheBaseMirror; + public Field getOrgCacheKeyField() { + return orgCacheKeyField; + } + public void setOrgCacheKeyField(Field orgCacheKeyField) { + this.orgCacheKeyField = orgCacheKeyField; + } + + public Mirror getCacheBaseMirror() { + return cacheBaseMirror; + } + public void setCacheBaseMirror(Mirror cacheBaseMirror) { + this.cacheBaseMirror = cacheBaseMirror; + } + public OrgCacheKey getOrgCacheKey() { + return orgCacheKey; + } + public void setOrgCacheKey(OrgCacheKey orgCacheKey) { + this.orgCacheKey = orgCacheKey; + } + + public void addOrgCacheValueField(OrgCacheValue orgCacheValue,Field orgCacheValueField){ + orgCacheValueFieldMap.put(orgCacheValue,orgCacheValueField); + } + public Map getOrgCacheValueFieldMap() { + return orgCacheValueFieldMap; + } + + } + + /** + * 采用默认的orgCacheService类 + */ + public CacheCallBack(){ + this.orgCacheService=SpringUtils.getBean(IOrgCacheService.class); + } + /** + * 通过传递参数的方式. + * @param orgCacheService + */ + public CacheCallBack(IOrgCacheService orgCacheService){ + this.orgCacheService=orgCacheService; + } + private IOrgCacheService orgCacheService; + private Mirror elemirror=null; + private Map innerCacheCallBackMap=new HashMap(); + + /** + * 初始化循环映射的参数. + * @param ele + */ + private void init(T ele){ + elemirror = Mirror.me(ele.getClass());//获取ele对象的反射类 + //获取含有:OrgCacheKey的属性对象,初始化InnerCacheCallBack对象. + Field[] orgCacheKeyField=elemirror.getFields(OrgCacheKey.class); + for (int i = 0; i < orgCacheKeyField.length; i++) { + InnerCacheCallBack innerCacheCallBack=new InnerCacheCallBack(); + innerCacheCallBack.setOrgCacheKeyField(orgCacheKeyField[i]); + innerCacheCallBack.setOrgCacheKey(orgCacheKeyField[i].getAnnotation(OrgCacheKey.class)); + innerCacheCallBackMap.put(innerCacheCallBack.getOrgCacheKey().id(), innerCacheCallBack); + OrgCacheTypeNum typeNum=innerCacheCallBack.getOrgCacheKey().type(); + switch(typeNum){ + case CacheUserInfo: + innerCacheCallBack.setCacheBaseMirror( Mirror.me(CacheSysUser.class)); + break; + case CacheDeptInfo: + innerCacheCallBack.setCacheBaseMirror( Mirror.me(CacheSysDept.class)); + break; + default: + log.warnf("无法识别的枚举类型:%s",typeNum.toString()); + continue; + } + } + Field[] aOrgCacheValueField=elemirror.getFields(OrgCacheValue.class); + for (int i = 0; i < aOrgCacheValueField.length; i++) { + OrgCacheValue orgCacheValue=aOrgCacheValueField[i].getAnnotation(OrgCacheValue.class); + if(innerCacheCallBackMap.containsKey(orgCacheValue.id())){ + innerCacheCallBackMap.get(orgCacheValue.id()).addOrgCacheValueField(orgCacheValue,aOrgCacheValueField[i]); + } else{ + log.warnf("找不到id:%s对应的Cache对象.请检查的@OrgCacheValue注解 id值,类:%s,属性:%s注解", + orgCacheValue.id(),ele.getClass(),aOrgCacheValueField[i].getName()); + } + } + } + @Override + public void invoke(int index, T ele, int length) throws ExitLoop, ContinueLoop, LoopException { + if(elemirror==null){ + init(ele); + } + for (Iterator> iterator = innerCacheCallBackMap.entrySet().iterator(); iterator.hasNext();) { + /** + * 获取BaseCache对象. + */ + Map.Entry type = iterator.next(); + InnerCacheCallBack innerCacheCallBack=type.getValue(); + Mirror cacheBaseMirror=innerCacheCallBack.getCacheBaseMirror(); + Object orgCacheKeyFieldValue=cacheBaseMirror.getValue(ele, innerCacheCallBack.getOrgCacheKeyField()); + if(orgCacheKeyFieldValue==null)//获取的orgCacheKeyFieldValue 对应的值为null 就不需要在进入后续的循环了. + continue; + OrgCacheTypeNum typeNum=innerCacheCallBack.getOrgCacheKey().type(); + BaseCache baseCache=null; + switch(typeNum){ + case CacheUserInfo: + baseCache=orgCacheService.getSysUser((Long)orgCacheKeyFieldValue).orElse(null); + if(baseCache==null){ + log.warnf("userId:%s获取到CacheStaffInfo的缓存数据是空。请检查Redis服务器.",orgCacheKeyFieldValue); + continue; + } + break; + case CacheDeptInfo: + baseCache=orgCacheService.getDeptInfo((Long)orgCacheKeyFieldValue).orElse(null); + if(baseCache==null){ + log.warnf("deptId:%s获取到CacheDeptInfo的缓存数据是空。请检查Redis服务器.",orgCacheKeyFieldValue); + continue; + } + break; + default: + log.warnf("无法识别的枚举类型:%s",typeNum.toString()); + continue; + + } + /** + * 将BaseCache对象的值设置到ele对象里面. + */ + for (Iterator> iterator2 = innerCacheCallBack.getOrgCacheValueFieldMap().entrySet().iterator(); iterator2.hasNext();) { + Map.Entry type2 = iterator2.next(); + OrgCacheValue orgCacheValue=type2.getKey(); + Field orgCacheValueField=type2.getValue(); + Object orgCacheValueFieldValue=cacheBaseMirror.getValue(baseCache, orgCacheValue.value()); + elemirror.setValue(ele, orgCacheValueField, orgCacheValueFieldValue); + + } + + + } + + + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/service/IOrgCacheService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/service/IOrgCacheService.java new file mode 100644 index 00000000..fa66db1a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/cache/service/IOrgCacheService.java @@ -0,0 +1,58 @@ +package com.ruoyi.cache.service; + +import java.util.Optional; + +import com.ruoyi.cache.domain.CacheSysDept; +import com.ruoyi.cache.domain.CacheSysUser; + +/** + * 组织架构的缓存类 + * 一级缓存,本地ecache缓存. 二级缓存:redis缓存. + * @author Condy + * + */ +public interface IOrgCacheService { + + /** + * 把员工信息存储到redis服务器上. + * @param staffInfo + * @return + */ + public CacheSysUser saveSysUser(CacheSysUser cacheSysUser); + + /** + * 删除员工 + * @param userId + */ + public void deleteSysUser(Long userId); + + /** + * 从redis上获取员工信息,先读取ecache缓存,没有的话到redis服务器读取. + * @param staffId + * @return CacheStaffInfo 取不到staffId对应的信息时会返回null + */ + public Optional getSysUser(long userId); + + /** + * 从redis服务器中获取部门信息. + * @param deptId + * @return 如果取不到部门信息会返回null + */ + public Optional getDeptInfo(long deptId); + + /** + * 将部门数据存储到redis缓存中 + * @param cacheDeptInfo + * @return + */ + public CacheSysDept saveDeptInfo(CacheSysDept cacheDeptInfo); + /** + * 删除部分 + * @param deptId + */ + public void deleteDeptInfo(Long deptId); + + + + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/CacheConfigurer.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/CacheConfigurer.java new file mode 100644 index 00000000..6eb24d6d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/CacheConfigurer.java @@ -0,0 +1,29 @@ +package com.ruoyi.system; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +import com.ruoyi.common.redis.service.RedisService; +import com.ruoyi.util.RedisNotifyService; +import com.ruoyi.util.SpringLoadComplete; + +@Configuration +@EnableCaching +@Component +public class CacheConfigurer { + @Autowired + private RedisService redisService; + @Bean + public SpringLoadComplete getSpringLoadComplete() { + return new SpringLoadComplete(); + } + @Bean + public RedisNotifyService getRedisNotifyService() { + RedisNotifyService notifyService= new RedisNotifyService(redisService); + return notifyService; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrgCacheServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrgCacheServiceImpl.java new file mode 100644 index 00000000..4ad9ea6e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrgCacheServiceImpl.java @@ -0,0 +1,160 @@ +package com.ruoyi.system.service.impl; + +import java.util.Optional; + +import org.nutz.lang.util.NutMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Component; + +import com.ruoyi.cache.domain.CacheSysDept; +import com.ruoyi.cache.domain.CacheSysUser; +import com.ruoyi.cache.service.IOrgCacheService; +import com.ruoyi.common.redis.service.RedisService; +import com.ruoyi.system.api.domain.SysDept; +import com.ruoyi.system.api.domain.SysUser; +import com.ruoyi.system.mapper.SysDeptMapper; +import com.ruoyi.system.mapper.SysUserMapper; +import com.ruoyi.util.IDUtil; +import com.ruoyi.util.IRedisNotifyHandle; +import com.ruoyi.util.RedisNotifyService; +@Component +/** + * 处理组织架构的缓存 + * @author condy + * + */ +public class OrgCacheServiceImpl implements IOrgCacheService,IRedisNotifyHandle { + + @Autowired + private RedisService redisService; + @Autowired + private RedisNotifyService redisNotifyService; + @Autowired + private CacheManager cacheManager; + @Autowired + private SysDeptMapper sysDeptMapper; + @Autowired + private SysUserMapper sysUserMapper; + + private final String USER_PRE="RUOYI_USER:"; + private final String DEPT_PRE="RUOYI_DEPT:"; + + private long selfId=IDUtil.getId(); + private Logger log=LoggerFactory.getLogger(getClass()); + public OrgCacheServiceImpl() { + RedisNotifyService.register(this); + } + + @Override + @CachePut(value="org",key="'RUOYI_USER:'+#cacheSysUser.getUserId()") + public CacheSysUser saveSysUser(CacheSysUser cacheSysUser) { + if(cacheSysUser==null || cacheSysUser.getUserId()==null) { + log.warn("保存员工到缓存错误, 员工ID是空的"); + return null; + } + redisService.setCacheObject(USER_PRE+cacheSysUser.getUserId(), cacheSysUser); + NutMap params=NutMap.NEW().addv("type", "RUOYI_USER").addv("userId", cacheSysUser.getUserId()); + params.addv("selfId", selfId); + redisNotifyService.publish(getRegisterId(), params); + return cacheSysUser; + } + + @Override + @Cacheable(value="org",key="'RUOYI_USER:'+#userId") + public Optional getSysUser(long userId) { + CacheSysUser cacheSysUser=redisService.getCacheObject(USER_PRE+userId); + if(cacheSysUser==null) { + SysUser sysUser=sysUserMapper.selectUserById(userId); + if(sysUser!=null) { + cacheSysUser=new CacheSysUser(sysUser); + saveSysUser(cacheSysUser); + } + } + return Optional.ofNullable(cacheSysUser); + } + + //除非,#result是空,就不缓存 + @Override + @Cacheable(value="org",key="'RUOYI_DEPT:'+#deptId") + public Optional getDeptInfo(long deptId) { + CacheSysDept cacheSysDept=redisService.getCacheObject(DEPT_PRE+deptId); + if(cacheSysDept==null) { + SysDept sysDept=sysDeptMapper.selectDeptById(deptId); + if(sysDept!=null) { + cacheSysDept=new CacheSysDept(sysDept); + saveDeptInfo(cacheSysDept); + } + } + return Optional.ofNullable(cacheSysDept); + } + + @Override + @CachePut(value="org",key="'RUOYI_DEPT:'+#cacheDeptInfo.getDeptId()") + public CacheSysDept saveDeptInfo(CacheSysDept cacheDeptInfo) { + if(cacheDeptInfo==null || cacheDeptInfo.getDeptId()==null) { + log.warn("保存部门到缓存错误, 部门ID是空的"); + return null; + } + redisService.setCacheObject(DEPT_PRE+cacheDeptInfo.getDeptId(), cacheDeptInfo); + NutMap params=NutMap.NEW().addv("type", "RUOYI_DEPT").addv("deptId", cacheDeptInfo.getDeptId()); + params.addv("selfId", selfId); + redisNotifyService.publish(getRegisterId(), params); + return cacheDeptInfo; + } + + @Override + public void handle(String methodName,NutMap params) { + String type=params.getString("type"); + long notifySelfId=params.getLong("selfId"); + if(notifySelfId==selfId) { + log.info("selfId:{} 是自己发出的,不做任何处理"); + return ; + } + if(USER_PRE.substring(0, USER_PRE.length()-1).equals(type)) { + log.info("把组织架构的staffId:{}的缓存作废",params.getLong("userId")); + cacheManager.getCache("org").evict(USER_PRE+params.getLong("userId")); + } else if (DEPT_PRE.substring(0, DEPT_PRE.length()-1).equals(type)) { + //把某个部门缓存作废. + log.info("把组织架构的deptId:{}的缓存作废",params.getLong("deptId")); + cacheManager.getCache("org").evict(DEPT_PRE+params.getLong("deptId")); + } else { + log.warn("无法识别的type:{}", type); + } + } + + @Override + public String getRegisterId() { + return "OrgCacheService"; + } + + @Override + @CacheEvict(value="org",key="'RUOYI_USER:'+#userId") + public void deleteSysUser(Long userId) { + if(userId==null) { + return ; + } + redisService.deleteObject(USER_PRE+userId); + NutMap params=NutMap.NEW().addv("type", "RUOYI_USER").addv("userId", userId); + params.addv("selfId", selfId); + redisNotifyService.publish(getRegisterId(), params); + } + + @Override + @CacheEvict(value="org",key="'RUOYI_DEPT:'+#deptId") + public void deleteDeptInfo(Long deptId) { + if(deptId==null) { + return ; + } + redisService.deleteObject(DEPT_PRE+deptId); + NutMap params=NutMap.NEW().addv("type", "RUOYI_DEPT").addv("deptId", deptId); + params.addv("selfId", selfId); + redisNotifyService.publish(getRegisterId(), params); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/IRedisNotifyHandle.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/IRedisNotifyHandle.java new file mode 100644 index 00000000..874d6b7e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/IRedisNotifyHandle.java @@ -0,0 +1,22 @@ +package com.ruoyi.util; + +import org.nutz.lang.util.NutMap; + +/** + * 接收到HttpServerRedis消息的处理类 + * @author 林桦 + * + */ +public interface IRedisNotifyHandle { + /** + * 处理json格式的消息 + * @param jsonMessage + */ + public void handle(String method,NutMap params); + /** + * 获取注册的ID,不同的ID之间不能重复. + * @return + */ + public String getRegisterId(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/ISpringLoadComplete.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/ISpringLoadComplete.java new file mode 100644 index 00000000..3b358447 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/ISpringLoadComplete.java @@ -0,0 +1,12 @@ +package com.ruoyi.util; + +import org.springframework.context.ApplicationContext; + +public interface ISpringLoadComplete { + /** + * 回调实现类 + * @param applicationContext + */ + void callback(ApplicationContext applicationContext); + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/RedisNotifyService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/RedisNotifyService.java new file mode 100644 index 00000000..9171debb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/RedisNotifyService.java @@ -0,0 +1,142 @@ +package com.ruoyi.util; + +import java.util.HashMap; +import java.util.Map; + +import org.nutz.json.Json; +import org.nutz.lang.util.NutMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.data.redis.connection.Message; +import org.springframework.data.redis.connection.MessageListener; +import org.springframework.data.redis.listener.PatternTopic; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; +import org.springframework.stereotype.Component; + +import com.ruoyi.common.redis.service.RedisService; + + +/** + * 应用服务器监听从redis上发过来的消息,例如:重读服务的参数,以及一些命令. + * @author 林桦 + * + */ +@Component +public class RedisNotifyService implements MessageListener,ISpringLoadComplete { + private static Map registerMap=new HashMap(); + private static Logger LOGGER=LoggerFactory.getLogger(RedisNotifyService.class); + public static final String CHANNEL="ruoyiMessageNotify"; + + private RedisService redisService; + public RedisNotifyService(RedisService redisService) { + this.redisService=redisService; + SpringLoadComplete.addCallBack(this); + } + + /** + * 注册具体方法 + * @param redisHandle + * @return + */ + public static boolean register(IRedisNotifyHandle redisHandle){ + if(registerMap.containsKey(redisHandle.getRegisterId())){ + LOGGER.info("已经存在:"+redisHandle.getRegisterId()+",无法注册成功!"); + return false; + }else{ + LOGGER.info("注册ID:"+redisHandle.getRegisterId()+",注册成功,处理类:"+redisHandle.getClass()); + registerMap.put(redisHandle.getRegisterId(), redisHandle); + return true; + } + + } + /** + * 取消注册. + * @param redisHandle + * @return + */ + public static boolean unRegister(IRedisNotifyHandle redisHandle){ + return unRegister(redisHandle.getRegisterId()); + } + /** + * 取消注册 + * @param registerId + * @return + */ + public static boolean unRegister(String registerId){ + if(registerId==null) + return false; + if(registerMap.containsKey(registerId)){ + LOGGER.info("注册ID:"+registerId+",取消注册成功!"); + registerMap.remove(registerId); + return true; + } else{ + return false; + } + } + /** + * 判断是否有注册 + * @param registerId + * @return + */ + public static boolean containRedisHandle(String registerId){ + if(registerId==null) + return false; + return registerMap.containsKey(registerId); + } + /** + * 判断是否有注册. + * @param redisHandle + * @return + */ + public static boolean containRedisHandle(IRedisNotifyHandle redisHandle){ + return containRedisHandle(redisHandle.getRegisterId()); + } + /** + * 发送JsonRpc + * @param method 方法名 + * @param params params的参数 + */ + public void publish(String method,NutMap params) { + NutMap jsonRpc=NutMap.NEW().addv("method", method).addv("params", params); + redisService.redisTemplate.convertAndSend(CHANNEL,Json.toJson(jsonRpc) ); + } + + + @Override + public void onMessage(Message message, byte[] pattern) { + /** + * Message的消息类型:{ "method": "sayHello", "params": ["Hello JSON-RPC"], "id": 1} + */ + try { + NutMap jsonMessage=Json.fromJson(NutMap.class,new String(message.getBody(),"UTF-8")); + String registerId=jsonMessage.getString("method",null); + if(containRedisHandle(registerId)){ + IRedisNotifyHandle redisHandle=registerMap.get(registerId); + if("casLogout".equals(registerId)) //签出的消息比多,更改为debug级别. + LOGGER.debug("recive httpServerRedis message:"+message+",submit to handle class:"+redisHandle.getClass()); + else + LOGGER.info("recive httpServerRedis message:"+message+",submit to handle class:"+redisHandle.getClass()); + NutMap params=Json.fromJson(NutMap.class,jsonMessage.getString("params","{}")); + redisHandle.handle(registerId,params); + } else{ + if("casLogout".equals(registerId)) + LOGGER.debug("recive httpServerRedis message:"+message+",but not find any handle class"); + else + LOGGER.info("recive httpServerRedis message:"+message+",but not find any handle class"); + } + } catch(Exception e) { + LOGGER.error("recive httpServerRedis handle error:"+message,e); + } + + } + + @Override + public void callback(ApplicationContext applicationContext) { + RedisMessageListenerContainer redisMessageListenerContainer=applicationContext.getBean(RedisMessageListenerContainer.class); + redisMessageListenerContainer.addMessageListener(this, new PatternTopic(CHANNEL)); + LOGGER.info("启动监听redis,channel:"+CHANNEL); + + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/SpringLoadComplete.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/SpringLoadComplete.java new file mode 100644 index 00000000..e8b01492 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/util/SpringLoadComplete.java @@ -0,0 +1,45 @@ +package com.ruoyi.util; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; + +@Component +/** + * spring启动完成,调用回调类 + * @author condy + * + */ +public class SpringLoadComplete implements ApplicationListener{ + + private static List callbackList=new ArrayList<>(); + private Logger log=LoggerFactory.getLogger(SpringLoadComplete.class); + /** + * 将回调方法加入到回调队列 + * @param callback + */ + public static void addCallBack(ISpringLoadComplete callback) { + if(!callbackList.contains(callback)) + callbackList.add(callback); + } + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + if(event.getApplicationContext().getParent() == null){ + try { + for (ISpringLoadComplete callback : callbackList) { + log.info("Spring启动完成,调用回调处理类:{}",callback); + callback.callback(event.getApplicationContext()); + } + } catch(Exception e) { + log.error("初始化回调方法错误",e); + } + } + + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/ehcache.xml b/ruoyi-modules/ruoyi-system/src/main/resources/ehcache.xml new file mode 100644 index 00000000..9842a844 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/ehcache.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/CacheCallBackPojo.java b/ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/CacheCallBackPojo.java new file mode 100644 index 00000000..a6008cb2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/CacheCallBackPojo.java @@ -0,0 +1,56 @@ +package com.ruoyi.system.service; + +import com.ruoyi.cache.annotation.OrgCacheKey; +import com.ruoyi.cache.annotation.OrgCacheTypeNum; +import com.ruoyi.cache.annotation.OrgCacheValue; +import com.ruoyi.cache.domain.CacheSysUser; + +public class CacheCallBackPojo { + @OrgCacheKey + private Long userId; + @OrgCacheValue(value = CacheSysUser.ANNOTAION_DEPT_ID) + private Long deptId; + @OrgCacheValue(value = CacheSysUser.ANNOTAION_USER_NAME) + private String userName; + @OrgCacheValue(value = CacheSysUser.ANNOTAION_PHONENUMBER) + private String phoneNumber; + private String detpName; + public Long getUserId() { + return userId; + } + public void setUserId(Long userId) { + this.userId = userId; + } + public Long getDeptId() { + return deptId; + } + public void setDeptId(Long deptId) { + this.deptId = deptId; + } + public String getUserName() { + return userName; + } + public void setUserName(String userName) { + this.userName = userName; + } + public String getPhoneNumber() { + return phoneNumber; + } + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + public String getDetpName() { + return detpName; + } + public void setDetpName(String detpName) { + this.detpName = detpName; + } + @Override + public String toString() { + return "CacheCallBackPojo [userId=" + userId + ", deptId=" + deptId + ", userName=" + userName + + ", phoneNumber=" + phoneNumber + ", detpName=" + detpName + "]"; + } + + + +} diff --git a/ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/CacheCallBackPojo2.java b/ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/CacheCallBackPojo2.java new file mode 100644 index 00000000..b878ce43 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/CacheCallBackPojo2.java @@ -0,0 +1,59 @@ +package com.ruoyi.system.service; + +import com.ruoyi.cache.annotation.OrgCacheKey; +import com.ruoyi.cache.annotation.OrgCacheTypeNum; +import com.ruoyi.cache.annotation.OrgCacheValue; +import com.ruoyi.cache.domain.CacheSysDept; +import com.ruoyi.cache.domain.CacheSysUser; + +public class CacheCallBackPojo2 { + @OrgCacheKey(id = "user",type = OrgCacheTypeNum.CacheUserInfo) + private Long userId; + @OrgCacheValue(value = CacheSysUser.ANNOTAION_DEPT_ID) + @OrgCacheKey(id = "dept",type = OrgCacheTypeNum.CacheDeptInfo) + private Long deptId; + @OrgCacheValue(value = CacheSysUser.ANNOTAION_USER_NAME) + private String userName; + @OrgCacheValue(value = CacheSysUser.ANNOTAION_PHONENUMBER) + private String phoneNumber; + @OrgCacheValue(id="dept",value = CacheSysDept.ANNOTAION_DEPT_NAME) + private String detpName; + public Long getUserId() { + return userId; + } + public void setUserId(Long userId) { + this.userId = userId; + } + public Long getDeptId() { + return deptId; + } + public void setDeptId(Long deptId) { + this.deptId = deptId; + } + public String getUserName() { + return userName; + } + public void setUserName(String userName) { + this.userName = userName; + } + public String getPhoneNumber() { + return phoneNumber; + } + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + public String getDetpName() { + return detpName; + } + public void setDetpName(String detpName) { + this.detpName = detpName; + } + @Override + public String toString() { + return "CacheCallBackPojo [userId=" + userId + ", deptId=" + deptId + ", userName=" + userName + + ", phoneNumber=" + phoneNumber + ", detpName=" + detpName + "]"; + } + + + +} diff --git a/ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/CacheCallBackTest.java b/ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/CacheCallBackTest.java new file mode 100644 index 00000000..f1f1c746 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/CacheCallBackTest.java @@ -0,0 +1,36 @@ +package com.ruoyi.system.service; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; +import org.nutz.lang.Lang; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import com.ruoyi.cache.service.CacheCallBack; +import com.ruoyi.cache.service.IOrgCacheService; +@SpringBootTest +class CacheCallBackTest { + + @Autowired + private IOrgCacheService orgCacheService; + @Test + void testInvoke() { + CacheCallBackPojo pojo=new CacheCallBackPojo(); + pojo.setUserId(1L); + Lang.each(Lang.list(pojo), new CacheCallBack<>()); + assertNotNull(pojo.getUserName()); + System.out.println(pojo.toString()); + } + + @Test + void testInvoke2() { + CacheCallBackPojo2 pojo=new CacheCallBackPojo2(); + pojo.setUserId(1L); + pojo.setDeptId(103L); + Lang.each(Lang.list(pojo), new CacheCallBack<>()); + assertNotNull(pojo.getUserName()); + System.out.println(pojo.toString()); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/impl/BulletinInfoServiceImplTest.java b/ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/impl/BulletinInfoServiceImplTest.java new file mode 100644 index 00000000..2799fe91 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/test/java/com/ruoyi/system/service/impl/BulletinInfoServiceImplTest.java @@ -0,0 +1,35 @@ +package com.ruoyi.system.service.impl; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import com.ruoyi.common.core.constant.SecurityConstants; +import com.ruoyi.common.core.context.SecurityContextHolder; +import com.ruoyi.system.domain.BulletinInfo; +import com.ruoyi.system.service.IBulletinInfoService; +@SpringBootTest +class BulletinInfoServiceImplTest { + + @Autowired + private IBulletinInfoService bulletinInfoService; + @BeforeEach + void setUser() { + SecurityContextHolder.set(SecurityConstants.DETAILS_USER_ID, 1); + + } + @Test + void testSelectBulletinInfoList() { + BulletinInfo bulletinInfo=new BulletinInfo(); + bulletinInfo.setSts("C"); + List list=bulletinInfoService.selectBulletinInfoList(bulletinInfo); + assertTrue(list.size()>0); + System.out.println("aaaaaaaaaaaaaaaa:"+list.get(0).getCreateUserId()+"="+list.get(0).getCreateBy()); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/test/resources/bootstrap.yml b/ruoyi-modules/ruoyi-system/src/test/resources/bootstrap.yml new file mode 100644 index 00000000..32364a97 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/test/resources/bootstrap.yml @@ -0,0 +1,25 @@ +# Tomcat +server: + port: 9201 + +# Spring +spring: + application: + # 应用名称 + name: ruoyi-system + profiles: + # 环境配置 + active: dev + cloud: + nacos: + discovery: + # 服务注册地址 + server-addr: 192.168.0.17:8848 + config: + # 配置中心地址 + server-addr: 192.168.0.17:8848 + # 配置文件格式 + file-extension: yml + # 共享配置 + shared-configs: + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}