上文我们一起分析了下如何在商品详情页面展示时添加缓存,本文我会带领大家一起实现商品详情页面展示时缓存的添加。
首先,我们要想清楚缓存应该加到哪个工程当中,目前我们有两个工程可以选择,第一个工程是taotao-item-web(商品详情展示工程),如果把缓存加到这个工程的话,由于该工程是个web工程,不被其它工程所共用,那么这块缓存的功能就只能被它自己使用。第二个工程是taotao-manager(商品服务工程),由于多个工程都可以依赖taotao-manager,因此缓存的功能可以被多个工程所共用。很显然,我们应该选择第二个工程来添加缓存,即在taotao-manager工程中添加缓存。还有,要使用到Redis缓存技术,因此还须在该工程中添加对Redis的依赖,如下图所示。
添加完依赖之后,taotao-manager-service工程中还需要添加对Redis操作的接口及实现类,由于咱们在taotao-content-service工程中已经写过了,因此我们只需要把该工程中关于jedis接口的包、接口及其实现类都拷贝过来,并将包名由原来的com.taotao.content.jedis改为ccom.taotao.manager.jedis,如下图所示。
然后,咱们还需要把taotao-conent-service工程中的applicationContext-redis.xml配置文件给复制过来,如下图所示。
打开以上配置文件,如下图所示,可以看到有单机版和集群版两种配置,但我目前使用的是单机版的Redis配置。
在上文中我们制定了通过添加Redis缓存前缀来区分key的策略,而且这个前缀我们又不能写死到代码当中,所以我们最好将其设置到配置文件当中,还有就是商品的过期时间,这个也应该是要进行配置的,因此我们需要在taotao-manager-service工程中添加一个如下resource.properties配置文件,如下图所示。
其中,resource.properties配置文件中的内容如下所示:
# Redis中缓存商品信息的前缀
ITEM_INFO_KEY=ITEM_INFO
# 设置商品数据缓存的过期时间,默认为1天
ITEM_INFO_KEY_EXPIRE=86400
添加好了以上配置文件之后,那么就要让Spring容器能够扫描到它,因此在applicationContext-dao.xml配置文件中我们要确保properties目录下的所有配置文件都可以被扫描到。
接着,我们开始要真正编写有关添加缓存的代码了,在ItemServiceImpl类中的获取商品基本信息方法(getItemById)和获取商品描述信息方法(getItemDescById)中添加缓存代码,添加完缓存后,该类的完整代码如下所示。
package com.taotao.service.impl;
import java.util.Date;
import java.util.List;
import javax.annotation.Resource;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Service;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.taotao.common.pojo.EasyUIDataGridResult;
import com.taotao.common.pojo.TaotaoResult;
import com.taotao.common.utils.IDUtils;
import com.taotao.common.utils.JsonUtils;
import com.taotao.manager.jedis.JedisClient;
import com.taotao.mapper.TbItemDescMapper;
import com.taotao.mapper.TbItemMapper;
import com.taotao.pojo.TbItem;
import com.taotao.pojo.TbItemDesc;
import com.taotao.pojo.TbItemExample;
import com.taotao.service.ItemService;
@Service
public class ItemServiceImpl implements ItemService {
@Autowired
private TbItemMapper tbItemMapper;
@Autowired
private TbItemDescMapper itemDescMapper;
@Autowired
private JmsTemplate jmsTemplate;
@Resource(name="topicDestination")
private Destination destination;
@Autowired
private JedisClient client;
@Value("${ITEM_INFO_KEY}")
private String ITEM_INFO_KEY;
@Value("${ITEM_INFO_KEY_EXPIRE}")
private Integer ITEM_INFO_KEY_EXPIRE;
@Override
public TbItem getItemById(Long itemId) {
// 添加缓存,有一个原则,即不能影响正常的业务逻辑
// 1. 从缓存中获取数据,如果有就直接返回
try {
String jsonstr = client.get(ITEM_INFO_KEY + ":" + itemId + ":BASE");
if (StringUtils.isNotBlank(jsonstr)) {
// 还得重新设置商品的有效期
client.expire(ITEM_INFO_KEY + ":" + itemId + ":BASE", ITEM_INFO_KEY_EXPIRE); // 设置缓存的有效期为一天
return JsonUtils.jsonToPojo(jsonstr, TbItem.class);
}
} catch (Exception e1) {
e1.printStackTrace();
}
// 2. 如果没有数据,就从数据库中查询
// 注入Mapper
// 调用方法
TbItem item = tbItemMapper.selectByPrimaryKey(itemId);
// 返回TbItem对象
// 3. 添加缓存到Redis数据库中
try {
// 注入JedisClient
client.set(ITEM_INFO_KEY + ":" + itemId + ":BASE", JsonUtils.objectToJson(item));
// 设置缓存的有效期,以提供我们缓存的利用率
client.expire(ITEM_INFO_KEY + ":" + itemId + ":BASE", ITEM_INFO_KEY_EXPIRE); // 设置缓存的有效期为一天
} catch (Exception e) {
e.printStackTrace();
}
return item;
}
@Override
public EasyUIDataGridResult getItemList(Integer page, Integer rows) {
// 1. 设置分页的信息,使用PageHelper
if (page == null) {
page = 1;
}
if (rows == null) {
rows = 30;
}
PageHelper.startPage(page, rows);
// 2. 注入Mapper
// 3. 创建一个TbItemExample对象,而且不需要设置查询条件
TbItemExample example = new TbItemExample();
// 4. 根据Mapper调用查询所有数据的方法
List<TbItem> list = tbItemMapper.selectByExample(example);
// 5. 获取分页信息
PageInfo<TbItem> info = new PageInfo<TbItem>(list);
// 6. 封装到EasyUIDataGridResult对象中并返回
EasyUIDataGridResult result = new EasyUIDataGridResult();
result.setTotal((int)info.getTotal());
result.setRows(info.getList());
return result;
}
@Override
public TaotaoResult addItem(TbItem item, String desc) {
// 生成商品id
long itemId = IDUtils.genItemId();
// 补全item对象的属性
item.setId(itemId);
// 商品状态,1:正常,2:下架,3:删除
item.setStatus((byte) 1);
item.setCreated(new Date());
item.setUpdated(new Date());
// 向商品表中插入数据
tbItemMapper.insert(item);
// 创建一个商品描述表对应的pojo
TbItemDesc itemDesc = new TbItemDesc();
// 补全pojo的属性
itemDesc.setItemId(itemId);
itemDesc.setItemDesc(desc);
itemDesc.setCreated(new Date());
itemDesc.setUpdated(new Date());
// 向商品描述表中插入数据
itemDescMapper.insert(itemDesc);
// 添加一个发送消息的业务逻辑
jmsTemplate.send(destination, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
// 发送消息,发送的消息的内容就是商品id
return session.createTextMessage(itemId + "");
}
});
// 返回结果
return TaotaoResult.ok();
}
@Override
public TbItemDesc getItemDescById(Long itemId) {
// 添加缓存,有一个原则,即不能影响正常的业务逻辑
// 1. 从缓存中获取数据,如果有就直接返回
try {
String jsonstr = client.get(ITEM_INFO_KEY + ":" + itemId + ":DESC");
if (StringUtils.isNotBlank(jsonstr)) {
// 还得重新设置商品的有效期
System.out.println("有缓存");
client.expire(ITEM_INFO_KEY + ":" + itemId + ":DESC", ITEM_INFO_KEY_EXPIRE); // 设置缓存的有效期为一天
return JsonUtils.jsonToPojo(jsonstr, TbItemDesc.class);
}
} catch (Exception e1) {
e1.printStackTrace();
}
// 2.如果没有查到数据,则从数据库中查询
TbItemDesc itemDesc = itemDescMapper.selectByPrimaryKey(itemId);
// 3. 添加缓存到Redis数据库中
try {
// 注入JedisClient
client.set(ITEM_INFO_KEY + ":" + itemId + ":DESC", JsonUtils.objectToJson(itemDesc));
// 设置缓存的有效期,以提供我们缓存的利用率
client.expire(ITEM_INFO_KEY + ":" + itemId + ":DESC", ITEM_INFO_KEY_EXPIRE); // 设置缓存的有效期为一天
} catch (Exception e) {
e.printStackTrace();
}
return itemDesc;
}
}
其中新注入的内容用如下图所示的红色大框框标注出来了。
代码写好了之后,最后我们便要进行测试了,重启taotao-manager这个工程,重启成功后,我们再来访问商品详情页面,第一次访问是查询数据库,然后我们再刷新页面,第二次访问就是查询的缓存了,缓存中存储的商品基本信息如下图所示。
存储的商品描述信息如下图所示。