Guns框架学习记录-6-数据范围控制+缓存管理
11.数据范围控制
同⼀⾓⾊⽤户会受到数据范围的限制,显⽰的数据内容会有所不同。
例如:在Guns框架中,同⾓⾊⽤户subject所属部门不同,该⽤户所能访问到的数据也不同。
在权限管理的基础上添加数据范围控制:Guns中通过⽤户subject的部门字段(可⾃定义)进⾏数据范围控制。
数据范围控制原理:对原有SQL查询语句进⾏包装后进⾏含DataScope的SQL查询。
例:查询⽤户信息列表
原语句: select id, account, name, birthday, sex, email, avatar, phone, roleid, deptid, status, createtime, version from user where status != 3
被包装后: select * from (select id, account, name, birthday, sex, email, avatar, phone, roleid, deptid, status, createtime, version from user where status != 3 ) temp_data_scope where temp_data_scope.deptid in (25,26,27,24)
看SQL语句本⾝,包装即为:select * from (sql) temp_data_scope where temp_data_scope.deptid in (25,26,27,24)。
意思就是包装后进⾏了嵌套查询,最外层⼜添加了查询条件,并限定了数据范围(where后部分)。
那么开展下⼀个问题,如何添加数据范围控制?
1. 定义DataScope
public class DataScope {
/**
* 限制范围的字段名称
*/
private String scopeName = "deptid";
/**
* 具体的数据范围
*/
private List<Integer> deptIds;
//getter、setter⽅法
cacheable}
这⾥需要注意的是,限制范围的字段名称需要和数据库字段⼀致,数据范围是⼀个列表(总公司下数据范围应该为所有部门)。
如何获取具体的数据范围?
答案是:通过shiro权限管理⼯具类:DeptDataScope()来进⾏具体数据范围的获取。
/**
* 获取当前⽤户的部门数据范围的集合
*/
public static List<Integer> getDeptDataScope() {
//获取当前⽤户的部门ID
Integer deptId = getUser().getDeptId();
//根据当前获取的⽤户部门ID进⾏⼦部门查询,返回当前部门的所有⼦部门ID
List<Integer> subDeptIds = ().getSubDeptId(deptId);
//将⾃⾝部门ID加⼊这样具体的部门范围就构成了
subDeptIds.add(deptId);
return subDeptIds;
}
当⾃定义数据范围字段:dataScope.setScopeName("xxx");的时候对应的具体数据范围获取⽅法应该同步更改。
2. 在需要进⾏数据范围过滤的查询⽅法上,在⽅法参数上,增加DataScope对象
坐标UserMgrDao.java
/**
* 根据条件查询⽤户列表
*/
List<Map<String, Object>> selectUsers(@Param("dataScope") DataScope dataScope, @Param("name") String name, ...)
DataScope dataScope 添加到了⽅法参数上,表明当前的⽅法要进⾏数据范围控制。
对应的Controller:
//获取具体数据范围
DataScope dataScope = new DeptDataScope());
//执⾏查询
List<Map<String, Object>> users = managerDao.selectUsers(dataScope, name, beginTime, endTime, deptid);
List<Map<String, Object>> users = managerDao.selectUsers(dataScope, name, beginTime, endTime, deptid);
3. 配置Mybatis,对所需执⾏的SQL语句进⾏拦截处理
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class DataScopeInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
//通⽤配置省略
//查参数中包含DataScope类型的参数
DataScope dataScope = findDataScopeObject(parameterObject);
//如果没有DataScope对象,直接放⾏。
if (dataScope == null) {
return invocation.proceed();
} else {
//获取DataScope的范围字段。
String scopeName = ScopeName();
//获取DataScope的具体数据范围
List<Integer> deptIds = DeptIds();
//集合⼯具类通过conjunction为分隔符将集合转换为字符串
String join = CollectionKit.join(deptIds, ",");
//拼接新的SQL语句
originalSql = "select * from (" + originalSql + ") temp_data_scope where temp_data_scope." + scopeName + " in (" + join + ")";
metaStatementHandler.setValue("delegate.boundSql.sql", originalSql);
//放⾏
return invocation.proceed();
}
}
/**
* 查参数是否包括DataScope对象
*/
public DataScope findDataScopeObject(Object parameterObj) {
if (parameterObj instanceof DataScope) {
return (DataScope) parameterObj;
} else if (parameterObj instanceof Map) {
for (Object val : ((Map<?, ?>) parameterObj).values()) {
if (val instanceof DataScope) {
return (DataScope) val;
}
}
}
return null;
}
}
拦截策略:判断参数列表中是否含有DataScope对象,如果没有就拦截通过。反之,从DataScope中获
取具体数据范围,重新拼装SQL语句,之后放⾏。通过数据范围控制结合权限管理对数据展⽰进⾏了进⼀步的控制,有利于数据的合理管理和展⽰。
12.缓存管理
对经常访问的数据信息进⾏存储,⽅⾯再次访问,减轻数据检索压⼒,提⾼系统性能。
关于缓存管理需要注意的地⽅:
1. Spring的缓存技术
2. 常⽤缓存的配置
**1.**Spring中的缓存技术
Spring 3.1引⼊了基于注释(annotation)的缓存(cache)技术,它本质上不是⼀个具体的缓存实现⽅案(例如EhCache或Redis),⽽是⼀个对缓存使⽤的抽象。
通过在既有代码中添加少量它定义的各种annotation,即能够达到缓存⽅法的返回对象的效果。
特点:
通过少量的配置annotation注释即可使得既有代码⽀持缓存
⽀持开箱即⽤Out-Of-The-Box,即不⽤安装和部署额外第三⽅组件即可使⽤缓存
⽀持Spring Express Language,能使⽤对象的任何属性或者⽅法来定义缓存的key和condition
⽀持AspectJ,并通过其实现任何⽅法的缓存⽀持
⽀持⾃定义key和⾃定义缓存管理者,具有相当的灵活性和扩展性
Spring提供了4个注解来声明缓存规则:以下注解均是添加到⽅法上。
1.@Cacheable表明在调⽤⽅法之前,⾸先应该在缓存中查⽅法的返回值,如果这个值能够到,则会返回缓存的值,否则执⾏该⽅法,并将返回值放到缓存中(qu ery)
参数:
value、cacheNames:两个等同的参数(cacheNames为Spring 4新增,作为value的别名),⽤于指定缓存存储的集合名。由于Spring 4中新增了@CacheCon fig,因此在Spring 3中原本必须有的value属性,也成为⾮必需项了
key:缓存对象存储在Map集合中的key值,⾮必需,缺省按照函数的所有参数组合作为key值,若⾃⼰配置需使⽤SpEL表达式,
如:@Cacheable(key = "#p0"):使⽤函数第⼀个参数作为缓存的key值。
condition:缓存对象的条件,⾮必需,也需使⽤SpEL表达式,只有满⾜表达式条件的内容才会被缓存,
如:@Cacheable(key = "#p0", condition = "#p0.length() < 3"),表⽰只有当第⼀个参数的长度⼩于3的时候才会被缓存。
unless:另外⼀个缓存条件参数,⾮必需,需使⽤SpEL表达式。它不同于condition参数的地⽅在于它的判断时机,该条件是在函数被调⽤之后才做判断的,所以它可以通过对result进⾏判断。
2.@CachePut表明在⽅法调⽤前不会检查缓存,⽅法始终都会被调⽤,调⽤之后把结果放到缓存中(insert)
3.@CacheEvict表明spring会清除⼀个或者多个缓存(update或delete)
4.@Caching分组的注解,可以同时应⽤多个其他缓存注解,可以相同类型或者不同类型
使⽤注解⽅式实现缓存管理实质就是Spring AOP的动态代理技术,关于AOP动态代理,会在后续事务管理后做学习记录。
**2.**EhCache的配置
需要提供⼀个CacheManager接⼝的实现,这个接⼝告诉spring有哪些cache实例,spring会根据cache的名字查cache的实例。
@Configuration
@EnableCaching //声明开启缓存
public class EhCacheConfig {
/**
* EhCache的配置
*/
@Bean
public EhCacheCacheManager cacheManager(CacheManager cacheManager) {
return new EhCacheCacheManager(cacheManager);
}
/**
* EhCache的配置
*/
@Bean
public EhCacheManagerFactoryBean ehcache() {
EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
//读取XML中的缓存相关配置
ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("l"));
return ehCacheManagerFactoryBean;
}
}
当声明了@EnableCaching后,springboot会根据以下顺序去检索缓存提供者。
Spring Boot根据实现⾃动配置合适的CacheManager,只要缓存⽀持通过@EnableCaching注释启⽤即可。
* Generic
* JCache (JSR-107)
* EhCache 2.x
* Hazelcast
* Infinispan
* Redis
* Guava
* Simple
配置⽂件:l
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="/ehcache.xsd"
xsi:noNamespaceSchemaLocation="/ehcache.xsd"
updateCheck="false">
<!--磁盘缓存地址-->
<diskStore path="pdir/ehcache"/>
<defaultCache
eternal="false"
maxElementsInMemory="1000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="0"
timeToLiveSeconds="600" />
<!-- ⾃定义缓存策略通过name进⾏缓存策略的区分 Guns这⾥采⽤了CONSTANT为缓存策略命名-->
<cache
name="CONSTANT"
eternal="false"
maxElementsInMemory="100"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="0"
timeToLiveSeconds="300"
memoryStoreEvictionPolicy="LRU" />
</ehcache>
配置参数:以下资料来源⽹络
diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。
defaultCache:默认缓存策略,当ehcache不到定义的缓存时,则使⽤这个缓存策略。只能定义⼀个。
name:缓存名称。
maxElementsInMemory:缓存最⼤数⽬
maxElementsOnDisk:硬盘最⼤缓存个数。
eternal:对象是否永久有效,⼀但设置了,timeout将不起作⽤。
overflowToDisk:是否保存到磁盘,当系统当机时
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使⽤,可选属性,默认值是0,也就是可闲置时间⽆穷⼤。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最⼤时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使⽤,默认是0.,也就是对象存活时间⽆穷⼤。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.diskSpoolBuff erSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区⼤⼩。默认是30MB。每个Cache都应该有⾃⼰的⼀个缓冲区。diskExpiryThreadIntervalSeconds:磁盘失效线程运⾏时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使⽤)。你可以设置为FIFO(先进先出)或是LFU(较少使⽤)。
clearOnFlush:内存数量最⼤时是否清除。
memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使⽤,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。