newstyles项目实战(二十)jedis与Spring整合

Spring和Jedis结合配置:

Jedis连接池的配置:

<!-- 连接池配置 -->
	<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<!-- 最大连接数 -->
		<property name="maxTotal" value="30" />
		<!-- 最大空闲连接数 -->
		<property name="maxIdle" value="10" />
		<!-- 每次释放连接的最大数目 -->
		<property name="numTestsPerEvictionRun" value="1024" />
		<!-- 释放连接的扫描间隔(毫秒) -->
		<property name="timeBetweenEvictionRunsMillis" value="30000" />
		<!-- 连接最小空闲时间 -->
		<property name="minEvictableIdleTimeMillis" value="1800000" />
		<!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
		<property name="softMinEvictableIdleTimeMillis" value="10000" />
		<!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
		<property name="maxWaitMillis" value="1500" />
		<!-- 在获取连接的时候检查有效性, 默认false -->
		<property name="testOnBorrow" value="true" />
		<!-- 在空闲时检查有效性, 默认false -->
		<property name="testWhileIdle" value="true" />
		<!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
		<property name="blockWhenExhausted" value="false" />
	</bean>	

对于单机版的配置:

<!--     jedis单机版-->
	<bean id="redisClient" class="redis.clients.jedis.JedisPool">
		<constructor-arg name="host" value="192.168.59.129"></constructor-arg>
		<constructor-arg name="port" value="6379"></constructor-arg>
		<constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
	</bean>
	
		<bean id="jedisClient" class="com.newstyles.rest.dao.Impl.JedisClientSingle">
	</bean>

集群版的配置:

<!-- 	jedis集群版 -->
	<bean id="redisClient" class="redis.clients.jedis.JedisCluster">
		<constructor-arg name="nodes">
			<set>
				<bean  id="redis01" class="redis.clients.jedis.HostAndPort">
					<constructor-arg  name="host" value="192.168.59.129"></constructor-arg>
					<constructor-arg name="port" value="7001"></constructor-arg>
				</bean>
				<bean  id="redis02" class="redis.clients.jedis.HostAndPort">
					<constructor-arg  name="host" value="192.168.59.129"></constructor-arg>
					<constructor-arg name="port" value="7002"></constructor-arg>
				</bean>
				<bean  id="redis03" class="redis.clients.jedis.HostAndPort">
					<constructor-arg  name="host" value="192.168.59.129"></constructor-arg>
					<constructor-arg name="port" value="7003"></constructor-arg>
				</bean>
				<bean  id="redis04" class="redis.clients.jedis.HostAndPort">
					<constructor-arg  name="host" value="192.168.59.129"></constructor-arg>
					<constructor-arg name="port" value="7004"></constructor-arg>
				</bean>
				<bean  id="redis05" class="redis.clients.jedis.HostAndPort">
					<constructor-arg  name="host" value="192.168.59.129"></constructor-arg>
					<constructor-arg name="port" value="7005"></constructor-arg>
				</bean>
				<bean  id="redis06" class="redis.clients.jedis.HostAndPort">
					<constructor-arg  name="host" value="192.168.59.129"></constructor-arg>
					<constructor-arg name="port" value="7006"></constructor-arg>
				</bean>
			</set>
		</constructor-arg>
		<constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
	</bean>

		<bean id="jedisClientCluster" class="com.newstyles.rest.dao.Impl.JedisClientCluster">
	</bean>

当然,上述两种方式只能有一种存在,但是连接池时必须保留的,其规定了Jedis运行时候的相关的设置,在这个测试实例中,我们采用了Jedis单机版的方式完成这个工程,所以,应该讲集群版的注释掉。

单机版测试案例:

	public void testSpringJedisSingle() {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-*.xml");
		JedisPool pool = (JedisPool) applicationContext.getBean("redisClient");
		Jedis jedis = pool.getResource();
		String string = jedis.get("key1");
		System.out.println(string);
		jedis.close();
		pool.close();
	}

集群版测试案例:

	public void testSpringJedisCluster() {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-*.xml");
		JedisCluster jedisCluster =  (JedisCluster) applicationContext.getBean("redisClient");
		String string = jedisCluster.get("key1");
		System.out.println(string);
		jedisCluster.close();
	}

在这里我们测试过后,以Jedis单机版为例,整合到Spring框架中:

Dao层:

首先定义了一个接口,虽说以Jedis单机版为例子,但是我们同时也实现了Redis的集群版的实例的完成:

首先在JedisClient接口中定义了Jedis客户端常用到的操作:

public interface JedisClient {

	String get(String key);
	String set(String key, String value);
	String hget(String hkey,String key);
	long hset(String hkey,String key,String value);
	long incr(String key);
	long expire(String key,int second);
	long ttl(String key);
	long del(String key);
	long hdel(String hkey ,String key);
}

首先,单机版的Jedis客户端的实现:

/**
 * 单机版
 * @author ***********
 *
 */
public class JedisClientSingle implements JedisClient {

	//需要JedisPool这个类型的对象来进行操作
	@Autowired
	private JedisPool jedisPool;
	@Override
	public String get(String key) {
		Jedis jedis = jedisPool.getResource();
		String string = jedis.get(key);
		jedis.close();
		return string;
	}

	@Override
	public String set(String key, String value) {
		Jedis jedis = jedisPool.getResource();
		String string = jedis.set(key,value);
		jedis.close();
		return string;
	}

	@Override
	public String hget(String hkey, String key) {
		Jedis jedis = jedisPool.getResource();
		String string = jedis.hget(hkey,key);
		jedis.close();
		return string;
	}

	@Override
	public long hset(String hkey, String key, String value) {
		Jedis jedis = jedisPool.getResource();
		long result = jedis.hset(hkey,key,value);
		jedis.close();
		return result;
	}

	@Override
	public long incr(String key) {
		Jedis jedis = jedisPool.getResource();
		long result = jedis.incr(key);
		jedis.close();
		return result;
	}

	@Override
	public long expire(String key, int second) {
		Jedis jedis = jedisPool.getResource();
		long result = jedis.expire(key, second);
		jedis.close();
		return result;
	}

	@Override
	public long ttl(String key) {
		Jedis jedis = jedisPool.getResource();
		long result = jedis.ttl(key);
		jedis.close();
		return result;
	}

	@Override
	public long del(String key) {
		Jedis jedis = jedisPool.getResource();
		long result = jedis.del(key);
		jedis.close();
		return result;
	}

	@Override
	public long hdel(String hkey, String key) {
		Jedis jedis = jedisPool.getResource();
		long result = jedis.hdel(hkey,key);
		jedis.close();
		return result;
	}
}

集群版Redis客户端的实现:

/**
 * 集群版
 * @author ***************
 *
 */
public class JedisClientCluster implements JedisClient{

	@Autowired
	private JedisCluster jedisCluster;
	
	@Override
	public String get(String key) {
		return jedisCluster.get(key);
	}

	@Override
	public String set(String key, String value) {
		return jedisCluster.set(key, value);
	}

	@Override
	public String hget(String hkey, String key) {
		return jedisCluster.hget(hkey, key);
	}

	@Override
	public long hset(String hkey, String key, String value) {
		return jedisCluster.hset(hkey, key, value);
	}

	@Override
	public long incr(String key) {
		return jedisCluster.incr(key);
	}

	@Override
	public long expire(String key, int second) {
		return jedisCluster.expire(key, second);
	}

	@Override
	public long ttl(String key) {
		return jedisCluster.ttl(key);
	}

	@Override
	public long del(String key) {
		return jedisCluster.del(key);
	}

	@Override
	public long hdel(String hkey, String key) {
		return jedisCluster.hdel(hkey, key);
	}

	
}

两者实现的最主要的区别在于单机版利用的是JedisPool来获取Jedis客户端的实例,而集群版则是利用JedisCluster来获取,获取使用的实例,其方法的包装和调用东较为相似,虽然实现原理不同,但是对于Jedis的使用,使用上述接口定义的操作,则能够满足呀大部分的操作。

Service层:

定义一个接口ContentService接口,其中定义了获取ContentList的操作:

public interface ContentService {
	List<TbContent> getContentList(long contentCid);
}

随后实现这个接口:

@Service
public class ContentServiceImpl implements ContentService {
 
	@Autowired
	private JedisClient jedisClient;
	@Autowired
	private TbContentMapper contentMapper;
	
	@Value("${INDEX_CONTENT_REDIS_KEY}")
	private String INDEX_CONTENT_REDIS_KEY;
	
	@Override
	public List<TbContent> getContentList(long contentCid) {
		//缓存的添加不能影响正常的业务逻辑
		//1.从缓存中取内容
		try{
			String reslut = jedisClient.hget(INDEX_CONTENT_REDIS_KEY,contentCid+"");
			if(!StringUtils.isBlank(reslut)){
				List<TbContent> resultList = JsonUtils.jsonToList(reslut, TbContent.class);
				return resultList;
			}
		}catch(Exception e){
			e.printStackTrace();
		}

		//根据内容分类id查询列表
		TbContentExample example = new TbContentExample();
		Criteria criteria = example.createCriteria();
		criteria.andCategoryIdEqualTo(contentCid);
		List<TbContent> list = contentMapper.selectByExample(example);
		
		//2.向缓存中添加内容
		try{
			//将list转换成字符串
			String cacheString = JsonUtils.objectToJson(list);
			jedisClient.hset(INDEX_CONTENT_REDIS_KEY, contentCid+"", cacheString);
		}catch(Exception e){
			e.printStackTrace();
		}
		return list;
	}

}

其中那些使用Value获取的值都统一定义在一个properties文件中:

#首页内容信息在redis中存储保存的key
INDEX_CONTENT_REDIS_KEY = INDEX_CONTENT_REDIS_KEY
Controller层:
@Controller
@RequestMapping("/content")
public class ContentController {

	@Autowired
	private ContentService contentService;
	
	@RequestMapping("/list/{contentCategoryId}")
	@ResponseBody
	public NewstylesResult getContentList(@PathVariable long contentCategoryId){
		try{
			List<TbContent> list = contentService.getContentList(contentCategoryId);
			return NewstylesResult.ok(list);
		}catch(Exception e){
			e.printStackTrace();
			return NewstylesResult.build(500, ExceptionUtil.getStackTrace(e));
		}
	}
}

测试一下:


可以看到,发布的rest服务能够正常的调用。

缓存同步:

先观察下面的流程图:


可以看到,我们所调用的服务都经过rest层,那么如何才能够实现在整个工程中既不影响正常的业务逻辑,又能够很好的进行同步更新,也是实说,在taotao-rest工程中发布一个服务。当后台管理系统修改内容后,调用此服务,同步缓存。要求是当后台中对某些有关于redis缓存中的内容进行更新时,也要更新redis缓存。

Dao层:

使用上一步实现的JedisClient来实现(以单机版Jedis为例)。

Service层:

接收内容分类id,调用dao删除redis中对应的hash中key为分类id的项。
参数:内容分类id
返回值:NewstylesResult

定义一个RedisService接口,定义一个同步的操作:

public interface RedisService {

	NewstylesResult syncContent(long contentCid);
}

实现这个接口:

@Service
public class RedisServiceImpl implements RedisService {

	@Autowired
	private JedisClient jedisClient;
	
	@Value("${INDEX_CONTENT_REDIS_KEY}")
	private String INDEX_CONTENT_REDIS_KEY;

	@Override
	public NewstylesResult syncContent(long contentCid) {
		try{
			jedisClient.hdel(INDEX_CONTENT_REDIS_KEY, contentCid+"");	
		}catch(Exception e){
			e.printStackTrace();
			return NewstylesResult.build(500, ExceptionUtil.getStackTrace(e));
		}
		return NewstylesResult.ok();
	}
}
Controller层:
/**
 * 缓存同步Controller
 * @author ***********
 *
 */
@Controller
@RequestMapping("/cache/sync")
public class RedisController {
	
	@Autowired
	private RedisService redisService;
	
	@RequestMapping("/content/{contentCid}")
	@ResponseBody
	public NewstylesResult contentCacheSync(@PathVariable long contentCid ){
		NewstylesResult result = redisService.syncContent(contentCid);
		return result;
	}
}

测试后,发现服务可以进行,但是我们还需要我们的后台当发生适应的条件时进行调用此服务,所以我们还需要在后台的工程中添加一个调用的服务,此服务的调用则是在后台的插入的方法中添加的:所以当有变化的时候删除原来的缓存,添加变化后的新元素,删除的时候也会调用,删除原来的缓存。newstyles-manager-web工程Service层中的有关缓存的修改:

首先插入:

	@Override
	public NewstylesResult insertContent(TbContent content) {
		//补全POJO的内容
		content.setCreated(new Date());
		content.setUpdated(new Date());
		contentMapper.insert(content);
		//添加同步缓存逻辑
		try{
			HttpClientUtil.doGet(REST_BASE_URL+REST_CONTENT_SYNC_URL + content.getCategoryId());		
		}catch(Exception e){
			e.printStackTrace();
		}
		
		return NewstylesResult.ok();
	}
删除原来的缓存:
	@Override
	public NewstylesResult deleteContentById(String ids){
	     String a[] =ids.split(",");
	     if(a.length != 0){
	    	 for(int i=0;i<a.length;i++){
	    		 TbContent tbContent = contentMapper.selectByPrimaryKey(Long.parseLong(a[i].trim()));
	    		 try {
					pictureService.deleteFilesPic(tbContent.getPic());
					pictureService.deleteFilesPic(tbContent.getPic2());
					HttpClientUtil.doGet(REST_BASE_URL+REST_CONTENT_SYNC_URL + tbContent.getCategoryId());
				} catch (Exception e) {
					e.printStackTrace();
				}		 
	    		 contentMapper.deleteByPrimaryKey(Long.parseLong(a[i].trim()));
	    	 }
	     }else{
    		 return NewstylesResult.build(500,"Misserror");
    	 }
		 return NewstylesResult.ok();
	}
此时完成了对于展示大广告业务的Redis的缓存的存储和更新。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值