SpringBoot+Thymeleaf+Redis实现页面缓存
Redis操作工具类
去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片
.
package com.hz1202.miaosha.service;
import com.alibaba.fastjson.JSON;
import com.hz1202.miaosha.redis.KeyPrefix;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
/**
* @Author: mol
* @Description:
* @Date: create in 13:19 2018/5/3
*/
@Service
public class RedisService {
@Autowired
JedisPool jedisPool;
/**
* redis get方法(该工具中为了保证所有key都唯一 所以给每一个key都加了前缀)
* @param prefix 前缀
* @param key key值
* @param clazz 获取后要转换成的对象类型
* @return 转换后的对象
*/
public <T> T get(KeyPrefix prefix,String key, Class<T> clazz){
Jedis jedis = null;
try {
//获取jedis
jedis = jedisPool.getResource();
//获取真正的key
String realKey = prefix.getPrefix()+key;
String str = jedis.get(realKey);
//将获取到的String转换成clazz对象
T t = StringToBean(str,clazz);
return t;
}finally {
//完成后回收资源
returnToPool(jedis);
}
}
/**
* redis set方法(该工具中为了保证所有key都唯一 所以给每一个key都加了前缀)
* @param prefix 前缀
* @param key key值
* @param value 要保存的数据
*/
public <T> Boolean set(KeyPrefix prefix,String key,T value){
Jedis jedis = null;
try {
//获取jedis
jedis = jedisPool.getResource();
//将对象转换为字符串
String str = beanToString(value);
if(str == null || str.length() <= 0){
return false;
}
//生成真正的key
String realKey = prefix.getPrefix()+key;
//获取key有效时间
int seconds = prefix.expireSeconds();
//如果有效时间小于等于0,说名该key值永久有效,否则在保存数据时需要加入有效时间
if(seconds <= 0){
jedis.set(realKey,str);
}else{
jedis.setex(realKey,seconds,str);
}
return true;
}finally {
returnToPool(jedis);
}
}
/**
* 判断key是否存在
* @param prefix 前缀
* @param key key值
* @return
*/
public Boolean exists(KeyPrefix prefix,String key){
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
//生成真正的key
String realKey = prefix.getPrefix()+key;
jedis.exists(realKey);
return true;
}finally {
returnToPool(jedis);
}
}
/**
* 给当前的key对应的value + 1
* @param prefix 前缀
* @param key key值
* @return
*/
public Boolean incr(KeyPrefix prefix,String key){
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
//生成真正的key
String realKey = prefix.getPrefix()+key;
jedis.incr(realKey);
return true;
}finally {
returnToPool(jedis);
}
}
/**
* 给当前key对应的value - 1
* @param prefix 前缀
* @param key key
* @return
*/
public Boolean decr(KeyPrefix prefix,String key){
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
//生成真正的key
String realKey = prefix.getPrefix()+key;
jedis.decr(realKey);
return true;
}finally {
returnToPool(jedis);
}
}
/**
* 将对象转换为字符串
* @param value
* @param <T>
* @return
*/
private <T> String beanToString(T value) {
if(value == null){
return null;
}
Class<?> clazz = value.getClass();
if(clazz == int.class || clazz == Integer.class){
return value+"";
}else if(clazz == String.class){
return (String) value;
}else if(clazz == Long.class || clazz == long.class){
return value+"";
}else{
return JSON.toJSONString(value);
}
}
/**
* 将String 转换为对象
* @param str
* @param clazz
* @param <T>
* @return
*/
@SuppressWarnings("unchecked")
private <T> T StringToBean(String str,Class<T> clazz) {
if(str == null || str.length() <= 0 || clazz == null){
return null;
}
if(clazz == int.class || clazz == Integer.class){
return (T)Integer.valueOf(str);
}else if(clazz == String.class){
return (T)str;
}else if(clazz == Long.class || clazz == long.class){
return (T)Long.valueOf(str);
}else{
return JSON.toJavaObject(JSON.parseObject(str),clazz);
}
}
/**
* 回收redis资源
* @param jedis
*/
private void returnToPool(Jedis jedis) {
if(jedis!=null){
jedis.close();
}
}
}
前缀和有效时间
package com.hz1202.miaosha.redis;
/**
* @Author: mol
* @Description:
* @Date: create in 14:46 2018/5/3
*/
public abstract class BasePrefix implements KeyPrefix{
//有效时间
private int expireSeconds;
//前缀
private String prefix;
public BasePrefix(String prefix) {
this.expireSeconds = 0;
this.prefix = prefix;
}
public BasePrefix(int expireSeconds, String prefix) {
this.expireSeconds = expireSeconds;
this.prefix = prefix;
}
@Override
public int expireSeconds() {//默认0代表永不过期
return expireSeconds;
}
@Override
public String getPrefix() {
String simpleName = getClass().getSimpleName();
return simpleName+":"+prefix;
}
}
package com.hz1202.miaosha.redis;
/**
* @Author: mol
* @Description:
* @Date: create in 14:44 2018/5/3
*/
public interface KeyPrefix {
int expireSeconds();
String getPrefix();
}
各个模块的前缀和有效时间都可以通过继承 BasePrefix 来控制
例如商品模块
package com.hz1202.miaosha.redis;
public class GoodsKey extends BasePrefix {
private GoodsKey(String prefix,int expireSeconds) {
super(expireSeconds,prefix);
}
//前缀为“gl”有效时间为“60”秒
public static GoodsKey getGoodsList =new GoodsKey("gl",60);
//前缀为“gd”有效时间为“60”秒
public static GoodsKey getGoodsDetail =new GoodsKey("gd",60);
}
正常情况下我们可能通过以下代码进入商品列表页面
@RequestMapping(value = "/to_list")
public String toListHtml(Model model){
List<GoodsVo> goodsVos = goodsService.listGoodsVo();
model.addAttribute("goodsList",goodsVos);
return "goods_list";
}
在做页面缓存时,我们直接将一个HTML代码返回给前端页面
@RequestMapping(value = "/to_list",produces="text/html")
@ResponseBody
public String toListHtml(Model model, MiaoShaUser user, HttpServletRequest request,
HttpServletResponse response){
//取缓存
String str = redisService.get(GoodsKey.getGoodsList, "", String.class);
if(!StringUtils.isEmpty(str)){
return str;
}
//缓存中没有,我们先获取商品信息
List<GoodsVo> goodsVos = goodsService.listGoodsVo();
model.addAttribute("goodsList",goodsVos);
model.addAttribute("user",user);
//然后进行手动渲染
SpringWebContext swc = new SpringWebContext(request,response,request.getServletContext(),
request.getLocale(),model.asMap(),application);
//goods_list 指的是前端页面模版(即你要将数据返回到哪个页面)
str = thymeleafViewResolver.getTemplateEngine().process("goods_list", swc);
//存入redis
if(!StringUtils.isEmpty(str)){
redisService.set(GoodsKey.getGoodsList,"",str);
}
return str;
}
以上我们看到处理页面缓存,只需要在原有的基础上做以下处理:
1、在RequestMapping中加上 produces = “text/html”,表示该方法将产生HTML代码数据
2、先从redis中获取数据
3、如果redis中没有数据则通过业务逻辑获取相关的数据后进行手动渲染,生成HTML代码,然后存入redis,最后将生成的代码返回给模板
4.如果将redis去掉,也是可以的。这样thymeleaf就直接访问DB