1、导入redis的配置文件,因为要交给web容器管理,所以直接命名为ApplicationContext-redis.xml,具体配置如下:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> <!-- 构建连接池配置信息 --> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!-- 最大连接数 --> <property name="maxTotal" value="${redis.maxTotal}" /> </bean> <bean id="jedisShardInfo1" class="redis.clients.jedis.JedisShardInfo"> <constructor-arg index="0" value="${redis.node1.ip}" /> <constructor-arg index="1" value="${redis.node1.port}" type="int" /> </bean> <bean id="jedisShardInfo2" class="redis.clients.jedis.JedisShardInfo"> <constructor-arg index="0" value="${redis.node2.ip}" /> <constructor-arg index="1" value="${redis.node2.port}" type="int" /> <!-- 端口必须为int类型,如果不写的话,默认是字符串类型,这是时候不起作用,所以端口就是默认端口,会造成分片失败 --> </bean> <bean id="jedisShardInfo3" class="redis.clients.jedis.JedisShardInfo"> <constructor-arg index="0" value="${redis.node3.ip}" /> <constructor-arg index="1" value="${redis.node3.port}" type="int" /> </bean> <!-- 定义集群连接池 --> <bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool" destroy-method="close"> <constructor-arg index="0" ref="jedisPoolConfig" /> <constructor-arg index="1"> <list> <ref bean="jedisShardInfo1" /> <ref bean="jedisShardInfo2" /> <ref bean="jedisShardInfo3"/> </list> </constructor-arg> </bean> </beans>
需要说明的是,这里是通过jedis进行操作的(jedis即java版的redis)
2、写伪service工具类
伪service--封装一个新的技术,融合进业务,而不是真正的业务层需要,但是本质还是service,目的是为了在controller中注入方便。经过伪service封装可以屏蔽掉底层的api
package com.jt.common.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import redis.clients.jedis.ShardedJedis; import redis.clients.jedis.ShardedJedisPool; @Service public class RedisService { //有的工程需要,有的工程不需要。设置required=false,有就注入,没有就不注入。 @Autowired(required = false) private ShardedJedisPool shardedJedisPool; private <T> T execute(Function<ShardedJedis, T> function) { ShardedJedis shardedJedis = null; try { // 从连接池中获取到jedis分片对象 shardedJedis = shardedJedisPool.getResource(); return function.execute(shardedJedis); } catch (Exception e) { e.printStackTrace(); } finally { if (null != shardedJedis) { // 关闭,检测连接是否有效,有效则放回到连接池中,无效则重置状态 shardedJedis.close(); } } return null; } /** * 保存数据到redis中 * * @param key * @param value * @return */ public String set(final String key, final String value) { return this.execute(new Function<ShardedJedis, String>() { @Override public String execute(ShardedJedis shardedJedis) { return shardedJedis.set(key, value); } }); } /** * 保存数据到redis中,生存时间单位是:秒 * * @param key * @param value * @param seconds * @return */ public String set(final String key, final String value, final Integer seconds) { return this.execute(new Function<ShardedJedis, String>() { @Override public String execute(ShardedJedis shardedJedis) { String result = shardedJedis.set(key, value); shardedJedis.expire(key, seconds);//设置生存时间 return result; } }); } /** * 从redis中获取数据 * * @param key * @return */ public String get(final String key) { return this.execute(new Function<ShardedJedis, String>() { @Override public String execute(ShardedJedis shardedJedis) { return shardedJedis.get(key); } }); } /** * 设置key生存时间,单位:秒 * * @param key * @param seconds * @return */ public Long expire(final String key, final Integer seconds) { return this.execute(new Function<ShardedJedis, Long>() { @Override public Long execute(ShardedJedis shardedJedis) { return shardedJedis.expire(key, seconds); } }); } /** * 从redis中删除数据 * * @param key * @return */ public Long del(final String key) { return this.execute(new Function<ShardedJedis, Long>() { @Override public Long execute(ShardedJedis shardedJedis) { return shardedJedis.del(key); } }); } }
3、在对应的执行业务的service中添加缓存方法
我这里因为是要做的查询的一个三级树目录,通过点击前台页面的父选项,传递父ID给后台,查询对应的子类,并将子类集合返回
原代码如下:
package com.jt.manage.service;
import java.io.IOException;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jt.common.service.BaseService;
import com.jt.common.service.RedisService;
import com.jt.manage.mapper.ItemCatMapper;
import com.jt.manage.pojo.ItemCat;
@Service
public class ItemCatService extends BaseService<ItemCat> {
@Autowired
private ItemCatMapper itemCatMapper;
public List<ItemCat> findItemCarList(Long parentId) {
itemCat.setParentId(parentId);
<!--这里采用的是JPA的方式,自动构建sql语句,查询的时候如果传入的是对象,那么会根据对象的属性当做where条件进行对应的匹配-->
return itemCatMapper.select(itemCat);
}
修改后的代码如下:
package com.jt.manage.service; import java.io.IOException; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.jt.common.service.BaseService; import com.jt.common.service.RedisService; import com.jt.manage.mapper.ItemCatMapper; import com.jt.manage.pojo.ItemCat; @Service public class ItemCatService extends BaseService<ItemCat> { @Autowired private ItemCatMapper itemCatMapper; @Autowired private RedisService redisService; private static final ObjectMapper MAPPER = new ObjectMapper(); public List<ItemCat> findItemCarList(Long parentId) { /* * 如果传入的是对象,查询时就会根据对象的属性值添加where条件 写null表示不需要where条件 */ ItemCat itemCat = new ItemCat(); /* * 1、在执行业务前判断缓存总是否所有数据,如果有数据,就获取数据,直接返回结果 * 2、如果没有数据,继续执行业务,访问数据库,获取返回的值 * 3、再返回业务之前,把获取的数据在缓存中存放一份,然后再返回 * 4、放缓存:kv(String) 把java对象变成json字符串 * 5、拿缓存:把字符串转换成java对象List<ItemCat> */ itemCat.setParentId(parentId); // 判断缓存中有无数据 // 定义键 String ITEM_CAT_KEY = "ITEM_CAT_" + parentId; // 根据键获取数据 String jsonData = redisService.get(ITEM_CAT_KEY); if (StringUtils.isNotEmpty(jsonData)) { // 缓存中有数据 try { // 直接从缓存中获取数据,把json串转换为java对象 JsonNode jsonNode = MAPPER.readTree(jsonData); Object obj = null; if (jsonNode.isArray() && jsonNode.size() > 0) { obj = MAPPER.readValue(jsonNode.traverse(), MAPPER.getTypeFactory().constructCollectionType(List.class, ItemCat.class)); return (List<ItemCat>) obj; } } catch (Exception e) { e.printStackTrace(); } } else {//如果缓存中没有数据,执行业务 try { //从数据库中获取数据 List<ItemCat> itemCatList = itemCatMapper.select(itemCat); //将数据保存一份在缓存中 //将数据转换成json对象 String json = MAPPER.writeValueAsString(itemCatList); //将对象保存进缓存 redisService.set(ITEM_CAT_KEY, json); //返回需要的对象 return itemCatList; } catch (JsonProcessingException e) { e.printStackTrace(); } } return null; } }