文章目录
1、首页轮播图的展示
1.1、功能分析
1.2、Dao层
1.3、Service层
1.4、表现层
1.5、测试
2、首页大广告展示流程图
3、Redis的安装及使用
3.1、redis的下载
3.2、redis的安装
3.3、连接redis
3.4、redis五种数据类型
3.5、key 命令
3.6、redis持久化方案
4、Redis集群的搭建
4.1、redis-cluster架构图
4.2、redis集群的搭建
4.3、集群的使用方法
5、Java客户端Jedis的使用方法
5.1、通过单实例连接redis服务器单机版
5.2、通过连接池连接redis服务器单机版
5.3、使用spring整合JedisPool连接redis服务器单机版
5.4、使用JedisCluster类连接redis集群版
5.5、使用spring整合JedisCluster连接redis服务器集群版
6、向业务逻辑中添加缓存
6.1、接口封装
6.2、封装代码测试
6.3、向业务逻辑中添加缓存
6.4、缓存同步
 
课程计划:
第五天
1、首页轮播图的展示
2、首页大广告展示流程图
3、Redis的安装及使用
4、Redis集群的搭建
5、向业务逻辑中添加缓存
6、Jedis的使用(redis的客户端)
7、缓存同步
8、Solr服务器安装
回到顶部
1、首页轮播图的展示
taotao-portal-web工程中,动态展示内容信息。
前端团队:负责JS,html等开发。
后端团队:负责后台的开发并提供数据给前端。
1.1、功能分析
只需要动态生成一个json数据,轮播图就可以动态展示。
taotao-portal-web工程下的index.jsp中:
Json数据格式:
[
    {
        "srcB": "http://image.taotao.com/images/2015/03/03/2015030304360302109345.jpg",
        "height": 240,
        "alt": "",
        "width": 670,
        "src": "http://image.taotao.com/images/2015/03/03/2015030304360302109345.jpg",
        "widthB": 550,
        "href": "http://sale.jd.com/act/e0FMkuDhJz35CNt.html?cpdad=1DLSUE",
        "heightB": 240
    },
    {
        "srcB": "http://image.taotao.com/images/2015/03/03/2015030304353109508500.jpg",
        "height": 240,
        "alt": "",
        "width": 670,
        "src": "http://image.taotao.com/images/2015/03/03/2015030304353109508500.jpg",
        "widthB": 550,
        "href": "http://sale.jd.com/act/UMJaAPD2VIXkZn.html?cpdad=1DLSUE",
        "heightB": 240
    },
    ......
]
分析:
  taotao-portal-web 需要自己自定义的POJO的类型数据的列表。
  taotao-content 是服务层公用的,可以被其他的系统(表现层的系统)来调用。
  为了通用性:taotao-content 服务层中获取tb_content的内容列表 即:list
  taotao-portal-web 表现层需要拿到tb_content的列表,然后进行转换成自定义的类型的数据列表即可。
  从tb_content表中取数据,根据(叶子节点)内容分类id查询列表(内容列表)。
  内容分类id固定,需要配置在属性文件中。
  图片的width、height配置在属性文件中。
  alt属性从字段sub_title中获取。
  src --> pic
  srcB --> pic2
  href --> url
URL:/index 
参数:无。
返回值:首页页面(数据是JSON,设置在Model中)
业务逻辑:
  1、根据分类的id 查询内容列表(List)
  2、服务层发布服务。
  3、表现层引入服务。
  4、调用服务,转换成自定义的数据类型(Ad1Node)的列表。
  5、将数据列表设置到Model中,返回给页面。
需要创建一个pojo转换成页面需要的json数据格式。放入taotao-portal-web工程的com.taotao.portal.pojo中。
AD1Node.java
/**
 * 前台大广告位需要的pojo数据类型
 * @author chenmingjun
 * @date 2018年11月18日下午4:03:34
 * @version 1.0
 */
public class AD1Node implements Serializable {
    private static final long serialVersionUID = 1L;
    private String srcB;
    private Integer height;
    private String alt;
    private Integer width;
    private String src;
    private Integer widthB;
    private String href;
    private Integer heightB;
    public String getSrcB() {
        return srcB;
    }
    public void setSrcB(String srcB) {
        this.srcB = srcB;
    }
    public Integer getHeight() {
        return height;
    }
    public void setHeight(Integer height) {
        this.height = height;
    }
    public String getAlt() {
        return alt;
    }
    public void setAlt(String alt) {
        this.alt = alt;
    }
    public Integer getWidth() {
        return width;
    }
    public void setWidth(Integer width) {
        this.width = width;
    }
    public String getSrc() {
        return src;
    }
    public void setSrc(String src) {
        this.src = src;
    }
    public Integer getWidthB() {
        return widthB;
    }
    public void setWidthB(Integer widthB) {
        this.widthB = widthB;
    }
    public String getHref() {
        return href;
    }
    public void setHref(String href) {
        this.href = href;
    }
    public Integer getHeightB() {
        return heightB;
    }
    public void setHeightB(Integer heightB) {
        this.heightB = heightB;
    }
    @Override
    public String toString() {
        return "AD1Node [srcB=" + srcB + ", height=" + height + ", alt=" + alt + ", width=" + width + ", src=" + src
                + ", widthB=" + widthB + ", href=" + href + ", heightB=" + heightB + "]";
    }
}
1.2、Dao层
从tb_content表中取出数据,根据内容分类id查询内容列表。可以使用逆向工程生成的Mapper。
1.3、Service层
参数:Long categoryId
返回值:List
    @Override
    public List getContentListByCategoryId(Long categoryId) {
        TbContentExample contentExample = new TbContentExample();
        Criteria criteria = contentExample.createCriteria();
        criteria.andCategoryIdEqualTo(categoryId);
        List list = contentMapper.selectByExample(contentExample);
        return list;
    }
1.3.1、发布服务
在taotao-content-service工程applicationContext-service.xml中发布服务
1.4、表现层
在taotao-portal-web中实现,查询首页轮播图的内容。
1.4.1、引用服务
先在taotao-protal-web项目中引入对taotao-content-interface的依赖,如图:
在taotao-content-web工程springmvc.xml中引入服务
1.4.2、Controller
在首页展示之前,对数据进行处理,然后展示首页,需要在IndexController中实现。
/**
 * 前台首页展示Controller
 * @author    chenmingjun
 * @date    2018年11月14日下午11:22:22
 * @version 1.0
 */
@Controller
public class IndexController {
    @Autowired
    private ContentService contentService;
    @Value("${AD1_CATEGORY_ID}")
    private Long AD1_CATEGORY_ID;
    @Value("${AD1_HEIGHT}")
    private Integer AD1_HEIGHT;
    @Value("${AD1_HEIGHT_B}")
    private Integer AD1_HEIGHT_B;
    @Value("${AD1_WIDTH}")
    private Integer AD1_WIDTH;
    @Value("${AD1_WIDTH_B}")
    private Integer AD1_WIDTH_B;
    /**
     * 展示前台首页,并展示首页轮播图
     * @return
     */
    @RequestMapping("/index")
    public String showIndex(Model model) {
        // 1、引入服务
        // 2、注入服务
        // 3、调用方法查询TbContent的列表
        List contentList = contentService.getContentListByCategoryId(AD1_CATEGORY_ID);
        // 4、把TbContent的列表转换为AD1Node列表
        List aD1NodeList = new ArrayList<>();
        for (TbContent tbContent : contentList) {
            AD1Node aD1Node = new AD1Node();
            aD1Node.setAlt(tbContent.getSubTitle());
            aD1Node.setHref(tbContent.getUrl());
            aD1Node.setSrc(tbContent.getPic());
            aD1Node.setSrcB(tbContent.getPic2());
            aD1Node.setHeight(AD1_HEIGHT);
            aD1Node.setHeightB(AD1_HEIGHT_B);
            aD1Node.setWidth(AD1_WIDTH);
            aD1Node.setWidthB(AD1_WIDTH_B);
            aD1NodeList.add(aD1Node);
        }
        // 5、把AD1Node列表转换为JSON数据
        String json = JsonUtils.objectToJson(aD1NodeList);
        // 6、把JSON数据设置到request域中去(Model)
        model.addAttribute("ad1", json);
        return "index";
    }
}
属性文件所在位置:
在taotao-portal-web中的springmvc.xml中还需要配置:
    
    
1.5、测试
后台数据如下图所示:
前台浏览器显示界面:
其他广告位同理。
回到顶部
2、首页大广告展示流程图
  首页是系统的门户,也就是系统的入口。所以首页的访问量是这个系统最大的。如果每次展示首页都从数据库中查询首页的内容信息,那么势必会对数据库造成很大的压力,所以需要使用缓存来减轻数据库压力。
  实现缓存的工具有很多,现在比较流行的是redis。
  首页大广告展示流程:
  展示流程:先从缓存取,如果不存在,从数据库取出来,写入缓存,再返回页面;如果存在key,直接从缓存中取出来,展示到页面。
  同步缓存:当事务提交(更新,删除,插入)后,需要同步缓存,直接根据Key删除redis的key(清空缓存),再展示时 由上边的流程展示。
回到顶部
3、Redis的安装及使用
3.1、redis的下载
  官网地址:http://redis.io/
  下载地址:http://download.redis.io/releases/redis-3.0.0.tar.gz
3.2、redis的安装
  安装redis需要c语言的编译环境,如果没有gcc需要在线安装。如下命令:
[root@itheima ~]# yum -y install gcc-c++
  检测是否有gcc环境,只需输入命令:
[root@itheima ~]# gcc
[root@itheima ~]# gcc
gcc: 致命错误:没有输入文件
编译中断。
[root@itheima ~]# 
出现如上所述内容,表示gcc安装成功。
安装步骤:
  第一步:将redis的源码包上传到linux系统。
  第二步:解压缩redis的源码包。
  第三步:进行编译。cd到解压后的目录,输入命令:make 
  第四步:进行安装。输入命令:make install PREFIX=/usr/local/redis
  第五步:检查目录是否存在。在/usr/local/redis下有bin目录,则说明安装成功。
3.3、连接redis
3.3.1、redis的启动
前端启动:在redis的安装目录下直接启动redis-server
[root@itheima ~]# ./redis-server
后台启动:
把/root/redis-3.0.0/redis.conf复制到/usr/local/redis/bin目录下
[root@itheima redis-3.0.0]# cp redis.conf /usr/local/redis/bin/
修改配置文件:将daemonize由no改为yes
再次启动redis:
[root@itheima bin]# ./redis-server redis.conf 
查看redis进程:
[root@itheima bin]# ps aux | grep redis
root       5845  0.4  0.2 140888  2104 ?        Ssl  22:51   0:00 ./redis-server *:6379
root       5858  0.0  0.0 112720   980 pts/1    R+   22:51   0:00 grep --color=auto redis
[root@itheima bin]# 
前端启动,不能更换终端,影响下一步操作。而后台启动,只在进程中悄悄启动。推荐使用后台启动。
3.3.2、客户端redis-cli连接redis
使用redis-cli建立连接:
[root@itheima bin]# ./redis-cli 
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> 
默认连接localhost运行在6379端口的redis服务。
连接其他ip和端口:
[root@itheima bin]# ./redis-cli -h 192.168.25.153 -p 6379
192.168.25.153:6379> ping
PONG
192.168.25.153:6379> 
  -h:连接的服务器的地址
  -p:服务的端口号
3.3.3、使用redis的桌面程序连接redis
先安装:redis-desktop-manager-0.7.9.809.exe
安装好后,双击打开软件
redis默认有16个库,如果不指定库,默认存储在索引为0的库中。
退出连接:
第一种方式:
[root@itheima bin]# ./redis-cli 
127.0.0.1:6379> quit
[root@itheima bin]# 
第二种方式:
[root@itheima bin]# ./redis-cli 
127.0.0.1:6379> exit
[root@itheima bin]# 
第三种方式:
Ctrl+C
3.3.4、关闭redis服务
第一种:通过连接上客户端进行关闭,使用shutdown 命令。
[root@itheima bin]# ./redis-cli 
127.0.0.1:6379> shutdown
not connected> 
第二种:使用 kill 命令。
找到对应的redis的进程id 然后使用命令:(pid为进程id)
[root@itheima bin]# kill -9 pid
3.4、redis五种数据类型
3.4.1、String:key-value
redis命令不区分大小写,但是key区分大小写的。
redis中所有的数据都是字符串。
redis是单线程的,所以不适合存储比较大的数据,最好要存小且能快速处理完的东西。
使用incr命令,如果key不存在,会自动创建key并自动+1。
  set key value   设置值
  get key   获取值
  incr key   加一
  decr key   减一
127.0.0.1:6379> set key1 2
OK
127.0.0.1:6379> set key2 value2
OK
127.0.0.1:6379> get key1
"2"
127.0.0.1:6379> get key2
"value2"
127.0.0.1:6379> Get key2
"value2"
127.0.0.1:6379> incr key1
(integer) 3
127.0.0.1:6379> decr key1
(integer) 2
127.0.0.1:6379> 
3.4.2、Hash: key-field-value
相当于一个key对应一个map (map中又是key-value),一般应用于归类。
  hset key field value
  hget key field 
  hincrby key field num
127.0.0.1:6379> hset hkey1 filed1 value1
(integer) 1
127.0.0.1:6379> hset hkey1 filed2 2
(integer) 1
127.0.0.1:6379> hget hkey1 filed1
"value1"
127.0.0.1:6379> hget hkey1 filed2
"2"
127.0.0.1:6379> hincrby hkey1 filed2 1
(integer) 3
127.0.0.1:6379> hincrby hkey1 filed2 -1
(integer) 2
127.0.0.1:6379> 
3.4.3、List
List是有顺序可重复(数据结构中的:双链表,队列)。
可作为链表,可以从左添加元素,也可以从右添加元素。
  lpush list a b c d   (从左添加元素)
  rpush list 1 2 3 4   (从右边添加元素)
  lrange list 0 -1   (从 0 到 -1 元素查看:也就表示查看所有)
  lpop list   (从左边取,删除)
  rpop list   (从右边取,删除)
127.0.0.1:6379> lpush list1 a b c d
(integer) 4
127.0.0.1:6379> lrange list1 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
127.0.0.1:6379> rpush list1 1 2 3 4
(integer) 8
127.0.0.1:6379> lrange list1 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
5) "1"
6) "2"
7) "3"
8) "4"
127.0.0.1:6379> lpop list1
"d"
127.0.0.1:6379> lrange list1 0 -1
1) "c"
2) "b"
3) "a"
4) "1"
5) "2"
6) "3"
7) "4"
127.0.0.1:6379> rpop list1
"4"
127.0.0.1:6379> lrange list1 0 -1
1) "c"
2) "b"
3) "a"
4) "1"
5) "2"
6) "3"
127.0.0.1:6379> 
3.4.4、Set
Set无顺序,不能重复。
  sadd set1 a b c d d   (向set1中添加元素)元素不重复
  smembers set1   (查询元素)
  srem set1 a   (删除元素)
127.0.0.1:6379> sadd set1 a a a b b c
(integer) 3
127.0.0.1:6379> smembers set1
1) "c"
2) "b"
3) "a"
127.0.0.1:6379> srem set1 a
(integer) 1
127.0.0.1:6379> smembers set1
1) "c"
2) "b"
127.0.0.1:6379> 
3.4.5、SortedSet(zset)
SortedSet有顺序,不能重复。
适合做排行榜 排序需要一个分数属性。
  zadd zset1 8 a 4 b 5 c 1 d   (添加元素:zadd key score member)
  zrange key start stop [WITHSCORES]   (查看所有元素:zrange key 0 -1 withscores) 
    如果要查看分数,需要加上withscores
  zrange zset1 0 -1   (从小到大)
  zrevrange zset1 0 -1   (从大到小)
  zincrby zset1 score member   (对元素 member 增加 score)
127.0.0.1:6379> zadd zset1 8 a 4 b 5 c 1 d
(integer) 4
127.0.0.1:6379> zrange zset1 0 -1
1) "d"
2) "b"
3) "c"
4) "a"
127.0.0.1:6379> zadd zset1 9 a
(integer) 0
127.0.0.1:6379> zrange zset1 0 -1
1) "d"
2) "b"
3) "c"
4) "a"
127.0.0.1:6379> zrange zset1 0 -1 withscores
1) "d"
2) "1"
3) "b"
4) "4"
5) "c"
6) "5"
7) "a"
8) "9"
127.0.0.1:6379> zrevrange zset1 0 -1
1) "a"
2) "c"
3) "b"
4) "d"
127.0.0.1:6379> zrevrange zset1 0 -1 withscores
1) "a"
2) "9"
3) "c"
4) "5"
5) "b"
6) "4"
7) "d"
8) "1"
127.0.0.1:6379> 
3.5、key 命令
expire key second   设置key的过期时间
ttl key             查看剩余时间(-2 表示不存在,-1 表示已被持久化(永不过期),正数表示剩余的时间)
persist key         清除过期时间,也即持久化,持久化成功体提示 1,不成功提示 0
del key             删除key  
exists key          若key存在,返回1,否则返回0。
select 0            表示选择0号数据库。默认是0号数据库。
redis 默认有16个库 select num 从0开始换库
keys *              获取redis里面所有的key
dbsize              查看当前数据库的key的数量
flushdb             清空当前库的所有key
flushall            清空所有库的key
exists key          是否存在该key
move key db         把当前库的key移到db号库中
type key            查看key的类型
3.6、redis持久化方案
redis 数据都放在内存中。如果机器挂掉,内存的数据就不存在。
需要做持久化处理,将内存中的数据保存在磁盘,下一次启动的时候就可以恢复数据到内存中。
  方案1:RDB 快照形式(定期将当前时刻的数据保存磁盘中)会产生一个dump.rdb文件。
    特点:会存在数据丢失,性能较好,数据备份。
  方案2:AOF:append only file (所有对redis的操作命令记录在aof文件中),恢复数据,重新执行一遍即可。
    特点:每秒保存(也可能会存在数据丢失),数据比较完整,耗费性能。其实也可以设置成每次保存,但是此就失去了缓存的意义了。
redis默认开启RDB。如下图:
redis.conf 中默认设置了保存规则及时间间隔。
save 开头的一行就是持久化配置,可以配置多个条件(每行配置一个条件),每个条件之间是“或”的关系。
    save 900 1      表示15分钟(900秒)内至少1个键被更改则进行快照。
    save 300 10     表示5分钟(300秒)内至少10个键被更改则进行快照。
    save 60 10000   表示1分钟(60秒)内至少10000个键被更改则进行快照。
AOF开启设置,修改 redis.conf 文件,如下图:
将appendonly设置为yes即可。
同时开启两个持久化方案,则按照AOF的持久化放案恢复数据。
默认是按照RDB的方式恢复数据,如果开启了AOF,就是用AOF恢复数据,数据是存在于/usr/local/redis/bin/appendonly.aof文件中。
回到顶部
4、Redis集群的搭建
4.1、redis-cluster架构图
架构细节详解如下:
架构细节:
    (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 会根据节点数量`大致均等`的将哈