易课寄在线购课系统开发笔记(十八)--完成首页轮播图动态展示功能

首页轮播图动态展示

功能分析

根据分类 id 查询内容列表,把内容展示到首页。

内容分类 id 需要是固定的。可以配置到属性文件中。

展示首页之前,先查询内容列表,然后展示到首页。

Dao层

单表查询。可以使用逆向工程。

Service层

参数:内容分类id

返回值:List

业务逻辑:

根据分类 id 查询内容列表

@Override
public List<EcoursesContent> getContentListByCid(long cid) {
    //查询缓存
    try {
        //如果缓存中有直接响应结果
        String json = jedisClient.hget(CONTENT_LIST, cid + "");
        if (StringUtils.isNotBlank(json)) {
            List<EcoursesContent> list = JsonUtils.jsonToList(json, EcoursesContent.class);
            return list;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    //如果没有查询数据库
    EcoursesContentExample example = new EcoursesContentExample();
    Criteria criteria = example.createCriteria();
    //设置查询条件
    criteria.andCategoryIdEqualTo(cid);
    //执行查询
    List<EcoursesContent> list = contentMapper.selectByExampleWithBLOBs(example);
    //把结果添加到缓存
    try {
        jedisClient.hset(CONTENT_LIST, cid + "", JsonUtils.objectToJson(list));
    } catch (Exception e) {
        e.printStackTrace();
    }
    return list;
}

需要把接口安装到本地仓库。

表现层

引用服务:

易课寄在线购课系统开发笔记(十八)--完成首页轮播图动态展示功能_第1张图片
springmvc.xml 中添加引用:

<dubbo:reference interface="cn.ecourses.content.service.ContentService" id="contentService" />

需要在展示首页的 Controller 中添加业务逻辑。

Redis

Redis 的安装

请参阅下面这篇笔记:

CentOS 6学习笔记(九)–CentOS6环境安装Redis

Redis 五种数据类型

String:key-value(做缓存)

Redis 中所有的数据都是字符串。命令不区分大小写,key 是区分大小写的。Redis 是单线程的,Redis 中不适合保存内容大的数据。

get、set、

incr:加一(生成 id)

Decr:减一

Hash:key-fields-values(做缓存)

相当于一个 key 对应一个 map,map 中还有 key-value

使用 hash 对 key 进行归类。

Hset:向 hash 中添加内容

Hget:从 hash 中取内容

List:有顺序可重复

> lpush list1 a b c d
(integer) 4
> lrange list1 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
> rpush list1 1 2 3 4
(integer) 8
> lrange list1 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
5) "1"
6) "2"
7) "3"
8) "4"
> 
> lpop list1 
"d"
> lrange list1 0 -1
1) "c"
2) "b"
3) "a"
4) "1"
5) "2"
6) "3"
7) "4"
> rpop list1
"4"
> lrange list1 0 -1
1) "c"
2) "b"
3) "a"
4) "1"
5) "2"
6) "3"
> 

Set:元素无顺序,不能重复

> sadd set1 a b c c c d
(integer) 4
> smembers set1
1) "b"
2) "c"
3) "d"
4) "a"
> srem set1 a
(integer) 1
> smembers set1
1) "b"
2) "c"
3) "d"
> 

还有集合运算命令。

SortedSet(zset):有顺序,不能重复

> zadd zset1 2 a 5 b 1 c 6 d
(integer) 4
> zrange zset1 0 -1
1) "c"
2) "a"
3) "b"
4) "d"
> zrem zset1 a
(integer) 1
> zrange zset1 0 -1
1) "c"
2) "b"
3) "d"
> zrevrange zset1 0 -1
1) "d"
2) "b"
3) "c"
> zrange zset1 0 -1 withscores
1) "c"
2) "1"
3) "b"
4) "5"
5) "d"
6) "6"
> zrevrange zset1 0 -1 withscores
1) "d"
2) "6"
3) "b"
4) "5"
5) "c"
6) "1"
> 

Key命令

设置key的过期时间。

Expire key second:设置 key 的过期时间

Ttl key:查看 key 的有效期

Persist key:清除 key 的过期时间。key 持久化。

> expire Hello 100
(integer) 1
> ttl Hello
(integer) 77

Redis的持久化方案

Redis 的所有数据都是保存到内存中的。

Rdb:快照形式,定期把内存中当前时刻的数据保存到磁盘。Redis 默认支持的持久化方案。

aof 形式:append only file。把所有对 Redis 数据库操作的命令,增删改操作的命令,保存到文件中。数据库恢复时把所有的命令执行一遍即可。

在redis.conf配置文件中配置。

Rdb:

易课寄在线购课系统开发笔记(十八)--完成首页轮播图动态展示功能_第2张图片
aof 的配置:

易课寄在线购课系统开发笔记(十八)--完成首页轮播图动态展示功能_第3张图片
两种持久化方案同时开启,使用 aof 文件来恢复数据库。

Redis 集群的搭建

请参阅下面这篇笔记:

CentOS 6学习笔记(十二)–CentOS6环境搭建Redis集群

架构细节:
(1) 所有的 Redis 节点彼此互联 (PING-PONG 机制),内部使用二进制协议优化传输速度和带宽。
(2) 节点的 fail 是通过集群中超过半数的节点检测失效时才生效。
(3) 客户端与 Redis 节点直连,不需要中间 proxy 层。客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
(4) redis-cluster 把所有的物理节点映射到 [0-16383]slot 上,cluster 负责维护 node<->slot<->value

Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,Redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,Redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。

Jedis

需要把 Jedis 依赖的 jar 包添加到工程中。Maven 工程中需要把 Jedis 的坐标添加到依赖。

<dependency>
  <groupId>redis.clientsgroupId>
  <artifactId>jedisartifactId>
dependency>

向业务逻辑中添加缓存

接口封装

常用的操作 Redis 的方法提取出一个接口,分别对应单机版和集群版创建两个实现类。

接口定义

package cn.ecourses.common.jedis;
public interface JedisClient {
	String set(String key, String value);
	String get(String key);
	Boolean exists(String key);
	Long expire(String key, int seconds);
	Long ttl(String key);
	Long incr(String key);
	Long hset(String key, String field, String value);
	String hget(String key, String field);
	Long hdel(String key, String... field);
	Boolean hexists(String key, String field);
	List<String> hvals(String key);
	Long del(String key);
}

单机版实现类

package cn.ecourses.common.jedis;
public class JedisClientPool implements JedisClient {

	private JedisPool jedisPool;

	public JedisPool getJedisPool() {
		return jedisPool;
	}

	public void setJedisPool(JedisPool jedisPool) {
		this.jedisPool = jedisPool;
	}

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

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

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

	@Override
	public Long expire(String key, int seconds) {
		Jedis jedis = jedisPool.getResource();
		Long result = jedis.expire(key, seconds);
		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 incr(String key) {
		Jedis jedis = jedisPool.getResource();
		Long result = jedis.incr(key);
		jedis.close();
		return result;
	}

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

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

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

	@Override
	public Boolean hexists(String key, String field) {
		Jedis jedis = jedisPool.getResource();
		Boolean result = jedis.hexists(key, field);
		jedis.close();
		return result;
	}

	@Override
	public List<String> hvals(String key) {
		Jedis jedis = jedisPool.getResource();
		List<String> result = jedis.hvals(key);
		jedis.close();
		return result;
	}

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

}

配置:applicationContext-redis.xml

<bean id="jedisClientPool" class="cn.ecourses.common.jedis.JedisClientPool">
    <property name="jedisPool" ref="jedisPool">property>
bean>
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
    <constructor-arg name="host" value="redis"/>
    <constructor-arg name="port" value="6379"/>
bean>

集群版实现类

package cn.ecourses.common.jedis;
public class JedisClientCluster implements JedisClient {

	private JedisCluster jedisCluster;
	
	public JedisCluster getJedisCluster() {
		return jedisCluster;
	}

	public void setJedisCluster(JedisCluster jedisCluster) {
		this.jedisCluster = jedisCluster;
	}

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

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

	@Override
	public Boolean exists(String key) {
		return jedisCluster.exists(key);
	}

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

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

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

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

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

	@Override
	public Long hdel(String key, String... field) {
		return jedisCluster.hdel(key, field);
	}

	@Override
	public Boolean hexists(String key, String field) {
		return jedisCluster.hexists(key, field);
	}

	@Override
	public List<String> hvals(String key) {
		return jedisCluster.hvals(key);
	}

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

配置:applicationContext-redis.xml


<bean id="jedisClientCluster" class="cn.ecourses.common.jedis.JedisClientCluster">
    <property name="jedisCluster" ref="jedisCluster"/>
bean>
<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
    <constructor-arg name="nodes">
        <set>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg name="host" value="redis">constructor-arg>
                <constructor-arg name="port" value="7001">constructor-arg>
            bean> 
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg name="host" value="redis">constructor-arg>
                <constructor-arg name="port" value="7002">constructor-arg>
            bean> 
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg name="host" value="redis">constructor-arg>
                <constructor-arg name="port" value="7003">constructor-arg>
            bean> 
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg name="host" value="redis">constructor-arg>
                <constructor-arg name="port" value="7004">constructor-arg>
            bean> 
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg name="host" value="redis">constructor-arg>
                <constructor-arg name="port" value="7005">constructor-arg>
            bean> 
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg name="host" value="redis">constructor-arg>
                <constructor-arg name="port" value="7006">constructor-arg>
            bean> 
        set>
    constructor-arg>
bean> 

注意:单机版和集群版不能共存,使用单机版时注释集群版的配置。使用集群版时,要把单机版注释。

添加缓存

功能分析

查询内容列表时添加缓存:

1、查询数据库之前先查询缓存;

2、查询到结果,直接响应结果;

3、查询不到,缓存中没有需要查询数据库;

4、把查询结果添加到缓存中;

5、返回结果。

向 Redis 中添加缓存:

Key:cid

Value:内容列表。需要把 Java 对象转换成 JSON。

使用 hash 对 key 进行归类。

  • HASH_KEY:HASH
    • KEY:VALUE
    • KEY:VALUE
    • KEY:VALUE
    • KEY:VALUE

注意:添加缓存不能影响正常业务逻辑。

代码实现

@Override
public List<EcoursesContent> getContentListByCid(long cid) {
    //查询缓存
    try {
        //如果缓存中有直接响应结果
        String json = jedisClient.hget(CONTENT_LIST, cid + "");
        if (StringUtils.isNotBlank(json)) {
            List<EcoursesContent> list = JsonUtils.jsonToList(json, EcoursesContent.class);
            return list;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    //如果没有查询数据库
    EcoursesContentExample example = new EcoursesContentExample();
    Criteria criteria = example.createCriteria();
    //设置查询条件
    criteria.andCategoryIdEqualTo(cid);
    //执行查询
    List<EcoursesContent> list = contentMapper.selectByExampleWithBLOBs(example);
    //把结果添加到缓存
    try {
        jedisClient.hset(CONTENT_LIST, cid + "", JsonUtils.objectToJson(list));
    } catch (Exception e) {
        e.printStackTrace();
    }
    return list;
}

缓存同步

对内容信息做增删改操作后只需要把对应缓存删除即可。

可以根据 cid 删除。

@Override
public ECoursesResult addContent(EcoursesContent content) {
    //将内容数据插入到内容表
    content.setCreated(new Date());
    content.setUpdated(new Date());
    //插入到数据库
    contentMapper.insert(content);
    //缓存同步,删除缓存中对应的数据。
    jedisClient.hdel(CONTENT_LIST, content.getCategoryId().toString());
    return ECoursesResult.ok();
}

你可能感兴趣的:(项目开发笔记)