Springboot 项目中使用redis 的List结构来实现缓存分页分页
1.自定义标签/*** @author gzy*元注解 标识需要缓存分页的方法*/@Documented@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface RedisCache {String cacheName() default Constants.REDIS_PAGE_CACHE;}2
·
1.自定义标签
/**
* @author gzy
* 元注解 标识需要缓存分页的方法
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCache {
String cacheName() default Constants.REDIS_PAGE_CACHE;
}
2.定义一个切面对使用自定义标签的方法进行处理
/**
* @author gzy
* @version : 1.0
* @date : 2020/1/6 0006
*/
@Aspect
@Component
@Order(3)
public class RedisCacheAspect {
private org.slf4j.Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
@Qualifier("pageCacheRedisTemplate")
private RedisTemplate<String, Object> redisTemplate;
/**
* 定义拦截规则:拦截下面的所有类中,有@RedisCache注解的方法。
*/
@Pointcut("execution(* com.cfcc.bigdata..service.*.*(..)) && @annotation(com.cfcc.bigdata.common.base.annotation.RedisCache)")
public void controllerMethodPointcut() {
}
@Around("controllerMethodPointcut()") //指定拦截器规则;也可以直接把“execution(* com.xjj.........)”写进这里
public Object Interceptor(ProceedingJoinPoint pjp) throws Throwable {
String className = getTargetClassName(pjp);
TwoTuple<Map<String, String>, EasyUIDatagridParam> methodParams = getMethodParams(pjp);
Map<String, String> param = methodParams.getVar1();
EasyUIDatagridParam easyUIDatagridParam = methodParams.getVar2();
TwoTuple<String, String> methodNameAndCacheName = getMethodNameAndCacheName(pjp);
String methodName = methodNameAndCacheName.getVar1();
String redisCacheName = methodNameAndCacheName.getVar2();
logger.info("请求开始,方法:{}", methodName);
int page = easyUIDatagridParam.getPage();
int rows = easyUIDatagridParam.getRows();
String redisKey = generateRedisKey(redisCacheName, className, methodName, param);
//从缓存中获取数据
PageInfo<Object> listPage = getListPage(redisKey, page, rows);
//如果缓存中的数据集合不为空
if (listPage.getList() != null) {
logger.info("redis中 key值:{}", redisKey);
return listPage;
}
//将数据库查询到的数据存储到redis 中,pip.proceed() 这里会执行标签标记的方法并把返回值返回。
Object dataFromDB = pjp.proceed();
if (dataFromDB instanceof PageInfo) {
PageInfo<Object> pageInfo = (PageInfo<Object>)dataFromDB;
List<Object> list = pageInfo.getList();
//如果数据库查询到的数据为空直接返回
if (list != null && list.size() > 0 ) {
addList(redisKey, list);
} else {
return new PageInfo<>(new ArrayList<>());
}
}
//根据条件分页查询
PageInfo<Object> result = getListPage(redisKey, page, rows);
return result;
}
/**
* 从 redis list 里面获取数据分页
* @param key list 对应的key
*
* @param page 当前页
* @param rows 页面的数据条数
* @return
*/
public PageInfo<Object> getListPage(String key, int page, int rows) {
//如果key 不存在,那么就被看作是空list,并且返回长度为0
Long size = redisTemplate.opsForList().size(key);
if (size <= 0) {
return new PageInfo<>();
}
//设置分页参数
Page param = new Page(page, rows);
param.setTotal(size);
int startRow = param.getStartRow();
int endRow = param.getEndRow();
List<Object> list = redisTemplate.opsForList().range(key, startRow, endRow > 0 ? endRow - 1 : 0);
PageInfo<Object> pageInfo = new PageInfo<>(param);
pageInfo.setSize(list.size());
pageInfo.setList(list);
return pageInfo;
}
/**
* redis 中的list是双向的
* leftPush 先进后出
* rightPush 先进先出
*
* @param key list 对应 key
* @param list 需要存储的集合对象
*/
public void addList(String key, List<Object> list) {
redisTemplate.opsForList().rightPushAll(key, list);
redisTemplate.expire(key,30, TimeUnit.MINUTES);
}
public String generateRedisKey(String cacheName, String className, String methodName, Map<String, String> params) {
StringBuilder sb = new StringBuilder();
sb.append(cacheName);
sb.append(":");
sb.append(className);
sb.append(".");
sb.append(methodName);
sb.append("#[");
for (Iterator<Map.Entry<String, String>> it = params.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<String, String> param = it.next();
sb.append("&");
sb.append(param.getKey());
sb.append(":");
sb.append(param.getValue());
}
sb.append("]");
return sb.toString();
}
/**
* 获取方法所在类的方法名
* @param pjp
* @return
*/
public String getTargetClassName(ProceedingJoinPoint pjp) {
//获取目标方法所在类
String target = pjp.getTarget().toString();
String className = target.split("@")[0];
return className;
}
/**
* 获取方法的参数
* @param pjp
* @return 返回参数对应元祖
**/
public TwoTuple<Map<String, String>, EasyUIDatagridParam> getMethodParams(ProceedingJoinPoint pjp) {
Object[] args = pjp.getArgs();
EasyUIDatagridParam easyUIDatagridParam = (EasyUIDatagridParam) args[0];
Map<String, String> param = new HashMap<>();
if (args[1] instanceof List) {
List<PropertyFilter> filters = (List<PropertyFilter>) args[1];
for (PropertyFilter filter : filters) {
param.put(filter.getPropertyName(), filter.getFilterValue());
}
}
TwoTuple<Map<String, String>, EasyUIDatagridParam> result = new TwoTuple<>(param, easyUIDatagridParam);
return result;
}
/**
* 获取方法名和缓存名
* @return TwoTupe<方法名, 缓存名>
*/
public TwoTuple<String, String> getMethodNameAndCacheName(ProceedingJoinPoint pjp) {
MethodSignature signature = (MethodSignature) pjp.getSignature();
//获取被拦截的方法
Method method = signature.getMethod();
//获取被拦截的方法名
String methodName = method.getName();
RedisCache annotation = method.getDeclaredAnnotation(RedisCache.class);
String redisCacheName = annotation.cacheName();
TwoTuple<String, String> result = new TwoTuple<>(methodName, redisCacheName);
return result;
}
}
3.在目标方法上添加标签
/**
* 根据通用条件进行分页查询,这里通过生成sql 查询数据库获取返回的数据
* 使用基于redis 的缓存分页
* @param param
* easyui传来的参数信息
* @param filters
* 通用条件
* @param entityClass
* 查询的实体对象类型
* @return
*/
@Transactional(readOnly = true)
@RedisCache
public PageInfo<T> selectPageByFilters(final EasyUIDatagridParam param, final List<PropertyFilter> filters, Class<?> entityClass) {
PageQueryHelper pageQueryHelper = new PageQueryHelper();
Example example = pageQueryHelper.generateExampleByFilters(param, filters, entityClass);
List<T> list = mapper.selectPageByExample(example);
return new PageInfo<>(list);
}
总结:这里当访问目标方法时会首先访问切面,切面中会判断当前方法的返回值是否被缓存过,如果没有缓存过,就从数据库中查出数据,并存储在缓存中,如果已经存在了,那么直接返回查询结果即可。
更多推荐
已为社区贡献3条内容
所有评论(0)