1.Redis集群
1.1 Redis分区说明
Redis分区只负责 数据应该存储到哪里的问题.至于是否能存储的下 完全由Redis内存决定.
特点:
1.hash(key1)%16384 = 3000
2.hash(key2)%16384 = 3000 key1和key2 都归第一个节点进行管理.
1.2 Redis hash槽与一致性 hash算法的区别
1.运算位置不同.
1.redis分片机制在业务服务器中完成的运算.
2.redis分区算法在连接Redis之后,由redis进行计算.
2.算法不同 一致性hash算法/hash槽算法.
3.redis分片可以随意的进行数据的保存. redis分区不能随机存储.分区中只能保存属于我的key.
1.3 Redis面试题
1.Redis集群中的主机最多 多少台? 16384个.
Redis集群内存多少最多可以扩展到原有redis多少倍.
2.Redis中存储的数据最多16384个??? 不对的. 16384只是分区的大小.至于能存储多少数据,完全由内存决定.
1.4 Redis集群宕机条件说明
说明: redis集群中 只要有一台Redis 主机宕机. 则整个Redis集群崩溃(可以进行高可用)
问题分析:
1.如果有6台Redis搭建集群,问: 最少宕机多少台Redis集群崩溃??? 宕机2台集群崩溃
2.如果搭建9台Redis.3台主机, 问 :最少宕机Redis台 集群奔溃??? 宕机5台集群崩溃
补充说明:如果想让集群尽可能不宕机,则适当增加从节点的数量. 2-3个从即可.
1.5 什么是脑裂现象
说明:在集群的机制中,由主机进行选举,当主机在进行选举时如果连续3次出现平票的结果时,则可能引发脑裂现象.
问题:出现脑裂现象的概率是多少? 答: 1/8=12.5%
如何有效降低脑裂现象: 可以通过增加主机的数量来有效降低脑裂的发生
1.6Spring整合Redis集群
1.6.1 编辑pro配置文件
# 配置单台redis
#redis.host=192.168.126.129
#redis.port=6379
配置多台redis
#redis.nodes=192.168.126.129:6379,192.168.126.129:6380,192.168.126.129:6381
配置Redis集群
redis.nodes=192.168.126.129:7000,192.168.126.129:7001,192.168.126.129:7002,192.168.126.129:7003,192.168.126.129:7004,192.168.126.129:7005
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
1.6.2 编辑配置类
package com.jt.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import redis.clients.jedis.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Configuration //标识我是配置类
@PropertySource(“classpath:/properties/redis.properties”)
public class RedisConfig {
<span class="token comment">/**
* 引入redis集群配置
*/</span>
<span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${redis.nodes}"</span><span class="token punctuation">)</span>
<span class="token keyword">private</span> String nodes<span class="token punctuation">;</span> <span class="token comment">//node,node,node</span>
<span class="token annotation punctuation">@Bean</span>
<span class="token keyword">public</span> JedisCluster <span class="token function">jedisCluster</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
String<span class="token punctuation">[</span><span class="token punctuation">]</span> strNodes <span class="token operator">=</span> nodes<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//[node1,nod2,nod3.....]</span>
Set<span class="token generics function"><span class="token punctuation"><</span>HostAndPort<span class="token punctuation">></span></span> set <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashSet</span><span class="token operator"><</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span><span class="token punctuation">(</span>String node <span class="token operator">:</span> strNodes<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">//node=host:port</span>
String host <span class="token operator">=</span> node<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">":"</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> port <span class="token operator">=</span> Integer<span class="token punctuation">.</span><span class="token function">parseInt</span><span class="token punctuation">(</span>node<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">":"</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
set<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">HostAndPort</span><span class="token punctuation">(</span>host<span class="token punctuation">,</span>port<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">JedisCluster</span><span class="token punctuation">(</span>set<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
/* @Value("${redis.nodes}")
private String nodes; //node,node,node
*/</span><span class="token comment">/**
* spring整合redis分片机制
*/</span><span class="token comment">/*
@Bean
public ShardedJedis shardedJedis(){
//1.获取每个节点的信息
String[] strNodes = nodes.split(",");
List<JedisShardInfo> shards = new ArrayList<>();
//2.遍历所有node.为list集合赋值
for(String node :strNodes){ //node=ip:port
String host = node.split(":")[0];
int port = Integer.parseInt(node.split(":")[1]);
JedisShardInfo info = new JedisShardInfo(host,port);
shards.add(info);
}
ShardedJedis shardedJedis = new ShardedJedis(shards);
return shardedJedis;
}*/</span>
/* @Value("
r
e
d
i
s
.
h
o
s
t
"
)
p
r
i
v
a
t
e
S
t
r
i
n
g
h
o
s
t
;
@
V
a
l
u
e
(
"
{redis.host}") private String host; @Value("
redis.host")privateStringhost;@Value("{redis.port}")
private Integer port;
//SpringBoot管理 Spring框架的优化的API
@Bean
public Jedis jedis(){
return new Jedis(host,port);
}*/</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
1.6.3 修改CacheAOP注入项
说明:在CacheAOP中 注入RedisCluster 对象
2. JT-WEB服务器构建
2.1 分布式环境搭建流程
2.2 创建JT-WEB
2.2.1 创建项目
2.2.2 添加继承/依赖/插件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <!--继承父级--> <parent> <artifactId>jt</artifactId> <groupId>com.jt</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>jt-web</artifactId> <!--指定打包类型--> <packaging>war</packaging>
<span class="token operator"><</span><span class="token operator">!</span><span class="token operator">--</span>添加依赖信息<span class="token operator">--</span><span class="token operator">></span> <span class="token generics function"><span class="token punctuation"><</span>dependencies<span class="token punctuation">></span></span> <span class="token generics function"><span class="token punctuation"><</span>dependency<span class="token punctuation">></span></span> <span class="token generics function"><span class="token punctuation"><</span>groupId<span class="token punctuation">></span></span>com<span class="token punctuation">.</span>jt<span class="token operator"><</span><span class="token operator">/</span>groupId<span class="token operator">></span> <span class="token generics function"><span class="token punctuation"><</span>artifactId<span class="token punctuation">></span></span>jt<span class="token operator">-</span>common<span class="token operator"><</span><span class="token operator">/</span>artifactId<span class="token operator">></span> <span class="token generics function"><span class="token punctuation"><</span>version<span class="token punctuation">></span></span><span class="token number">1.0</span><span class="token operator">-</span>SNAPSHOT<span class="token operator"><</span><span class="token operator">/</span>version<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>dependency<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>dependencies<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">!</span><span class="token operator">--</span>添加插件<span class="token operator">--</span><span class="token operator">></span> <span class="token generics function"><span class="token punctuation"><</span>build<span class="token punctuation">></span></span> <span class="token generics function"><span class="token punctuation"><</span>plugins<span class="token punctuation">></span></span> <span class="token generics function"><span class="token punctuation"><</span>plugin<span class="token punctuation">></span></span> <span class="token generics function"><span class="token punctuation"><</span>groupId<span class="token punctuation">></span></span>org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>boot<span class="token operator"><</span><span class="token operator">/</span>groupId<span class="token operator">></span> <span class="token generics function"><span class="token punctuation"><</span>artifactId<span class="token punctuation">></span></span>spring<span class="token operator">-</span>boot<span class="token operator">-</span>maven<span class="token operator">-</span>plugin<span class="token operator"><</span><span class="token operator">/</span>artifactId<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>plugin<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>plugins<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>build<span class="token operator">></span>
</project>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
2.2.3 导入web资源
说明:将课前资料中的文件导入IDEA中即可
2.2.4 编辑IDEA启动项
2.2.5启动效果
2.2.6关于主启动类的注解说明
说明:该报错信息由SpringBoot启动时报的.
1).在jt. pom.xml文件中引入数据源的jar包文件.当SpringBoot程序启动时,必然要加载数据源.
2).但是jt-web服务器yml配置文件中没有添加数据源,所以启动报错!!!
1).pom.xml文件包信息
<!--引入数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
<span class="token operator"><</span><span class="token operator">!</span><span class="token operator">--</span>springBoot数据库连接 <span class="token operator">--</span><span class="token operator">></span> <span class="token generics function"><span class="token punctuation"><</span>dependency<span class="token punctuation">></span></span> <span class="token generics function"><span class="token punctuation"><</span>groupId<span class="token punctuation">></span></span>org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>boot<span class="token operator"><</span><span class="token operator">/</span>groupId<span class="token operator">></span> <span class="token generics function"><span class="token punctuation"><</span>artifactId<span class="token punctuation">></span></span>spring<span class="token operator">-</span>boot<span class="token operator">-</span>starter<span class="token operator">-</span>jdbc<span class="token operator"><</span><span class="token operator">/</span>artifactId<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>dependency<span class="token operator">></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
2).YML配置信息
server:
port: 8092
spring: #定义springmvc视图解析器
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3).解决方案 说明:在主启动类中添加该注解即可.
2.3 nginx实现反向代理
2.3.1 规则
说明: 要求用户使用http://www.jt.com:80的方式来访问localhost:8092服务器.
2.3.2 修改hosts文件
# 京淘配置
#左侧写IP地址 右侧写域名 中间使用空格分隔
#为了实现Linux发布修改如下
#192.168.126.129 image.jt.com
#192.168.126.129 manager.jt.com
127.0.0.1 image.jt.com
127.0.0.1 manager.jt.com
127.0.0.1 www.jt.com
127.0.0.1 sso.jt.com
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2.3.3 修改nginx配置文件
说明: 修改windows中的nginx服务器.
# 配置前台服务器 server { listen 80; server_name www.jt.com;
location <span class="token operator">/</span> <span class="token punctuation">{</span> proxy_pass http<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>localhost<span class="token operator">:</span><span class="token number">8092</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2.4 关于web服务器网址访问报错说明
2.4.1 解決浏览器使用https的方法
1).在浏览器中键入 "chrome://net-internals/#hsts:“
2.5 实现伪静态
2.5.1 导入配置类
说明: 将课前资料中的配置类导入项目中.
2).导入项目
2.5.2 京东商城商品页面分析
思考: 当前的页面是在后端服务器中真实存在的,还是由一个页面动态填充数据实现的!!!
说明: 经过分析 京东的商品的展现由一个页面动态的填充. 只要服务器接收商品ID即可.并且应该拦截.html为后缀的页面请求.
2.5.3 什么是伪静态
伪静态是相对真实静态来讲的,通常我们为了增强搜索引擎的友好面,都将文章内容生成静态页面,但是有的朋友为了实时的显示一些信息。或者还想运用动态脚本解决一些问题。不能用静态的方式来展示网站内容。但是这就损失了对搜索引擎的友好面。怎么样在两者之间找个中间方法呢,这就产生了伪静态技术。伪静态技术是指展示出来的是以html一类的静态页面形式,但其实是用ASP一类的动态脚本来处理的。
总结: 以.html为结尾的展现的动态页面的脚本技术.
2.5.4 搜索引擎工作原理(铺垫)
2.5.5 当前使用场景
大前端技术发展比较火. 完全的前后端分离 node.js 作为脚手架 存.html的页面 .jsp技术可能落后了. 通过vue/jquery 动态实现页面数据回显. VUE
3. 京淘跨域问题实现
3.1 实现用户登录/注册跳转
登录路径: http://www.jt.com/user/login.html
注册路径: http://www.jt.com/user/register.html
3.2 编辑UserController
package com.jt.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {
<span class="token comment">/**
* 业务说明:要求用一个方法实现页面的通用跳转.
* http://www.jt.com/user/login.html 跳转页面 login.jsp
* http://www.jt.com/user/register.html 跳转页面register.jsp
* 自己完成该功能!!!!
*/</span>
<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">"/{moduleName}"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> String <span class="token function">moduleName</span><span class="token punctuation">(</span><span class="token annotation punctuation">@PathVariable</span> String moduleName<span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">return</span> moduleName<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
3.3 跨域问题说明
3.3.1 用户注册业务说明
业务说明:当用户输入用户名时,应该向后端服务器获取数据库信息.校验数据库中是否存在该数据.
并且给用户友好的提示.
问题: 如何实现由jt-web服务器 访问jt-sso呢???
解决方案: 利用ajax形式实现远程数据调用!!! (http)
讨论: 利用ajax是否实现远程数据的访问呢???
3.3.2 ajax跨域访问测试(一)
说明:测试时 挑选在jt-manager中的页面和数据进行ajax测试
1).页面结构如下
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>测试JSON跨域问题</title>
<script type="text/javascript" src="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
$.get("http://manage.jt.com/test.json",function(data){
alert(data.name);
})
})
</script>
</head>
<body>
<h1>JSON跨域请求测试</h1>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
2).访问的数据类型
{"id":"1","name":"tom"}
- 1
3).测试效果
页面网址: http://manager.jt.com/test.html
页面中ajax请求网址: http://manager.jt.com/test.json
结论: ajax访问同一个域名的数据,访问正常!!!
3.3.3 ajax跨域访问测试(二)
测试说明: 由jt-web的页面 发起ajax请求.访问jt-manager中的text.json数据.
特点: 页面的访问网址 http://www.jt.com/test.html 与ajax访问的网址http://manager.jt.com/test.json 网址不同.
1).页面信息
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>测试JSON跨域问题</title>
<script type="text/javascript" src="http://manager.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript">
/*$(){}结构必然是jQuery函数类库导入后才能正确执行*/
$(function(){
alert("我执行了AJAX");
//利用jQuery发起AJAX请求
$.get("http://manager.jt.com/test.json",function(data){
alert(data.name);
})
})
</script>
</head>
<body>
<h1>JSON跨域请求测试</h1>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
测试结论: 发现在不同的域名中访问.请求不能正常的进行.,报错信息如下
3.3.4 同源策略说明
说明:浏览器中规定 Ajax请求 协议://域名:端口三者必须全部相同时,才能实现数据访问(同域请求),如果违反上述规则中的任意一个则该请求就是跨域访问.
如果浏览器进行跨域访问,则浏览器不予解析返回值.
3.4 跨域实现-jsonp
3.4.1 JSONP跨域访问入门案例
核心思路:
1.利用javaScript中的src属性进行跨域!!!.
<script type="text/javascript" src="http://manager.jt.com/test.json"></script>
- 1
补充说明:一般src属性负责资源的加载.如果 需要使用数据,则需要函数进行调用才行.
2.自定义回调函数
- 1
- 2
- 3
<script type="text/javascript">
/*JS是解释执行的语言 */
/*定义回调函数 */
function hello(data){
alert(data.name);
}
</script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
3.将返回值的结果 进行特殊的格式封装!!!
- 1
hello({"id":"1","name":"tom"})
- 1
整体页面JS分析
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>测试JSON跨域问题</title>
<script type="text/javascript">
/*JS是解释执行的语言 */
/*定义回调函数 */
function hello(data){
alert(data.name);
}
</script>
<!--该json一直保存到浏览器中等待调用,但是没有函数名称无法调用 -->
<script type="text/javascript" src="http://manager.jt.com/test.json"></script>
<script type="text/javascript" src="http://manager.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
</script>
</head>
<body>
<h1>JS跨域问题</h1>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
3.4.2 JSONP介绍
艺名:json"胖"
JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的
3.4.3 jQuery实现JSONP
需求:jsonp的方式如果采用原生的调用方式,则配置繁琐 1.javascript 2.自定义回调函数 3.特殊格式封装.
则jQuery负责封装JSONP.像常规ajax调用一样的方便.
页面封装:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSONP测试</title>
<script type="text/javascript" src="http://manager.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
alert("测试访问开始!!!!!")
$.ajax({
url:"http://manager.jt.com/web/testJSONP",
type:"get", //jsonp只能支持get请求 src只能进行get请求.
dataType:"jsonp", //dataType表示返回值类型 必须标识
//jsonp: "callback", //指定参数名称
//jsonpCallback: "hello", //指定回调函数名称
success:function (data){ //data经过jQuery封装返回就是json串
alert(data.id);
alert(data.name);
}
});
})
</script>
</head>
<body>
<h1>JSON跨域请求测试</h1>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
页面请求网址:
3.4.4 编辑jt-manager中的Controller
package com.jt.web.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class JSONPController {
<span class="token comment">/**
* 完成JSONP的调用
* url:http://manager.jt.com/web/testJSONP?callback=jQuery111101021758391465013_1597656788213&_=1597656788214
* 规定:返回值结果,必须经过特殊的格式封装.callback(json)
*/</span>
<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">"/web/testJSONP"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> String <span class="token function">jsonp</span><span class="token punctuation">(</span>String callback<span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">return</span> callback<span class="token operator">+</span><span class="token string">"({'id':'100','name':'tomcat猫'})"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
</div><div data-report-view="{"mod":"1585297308_001","dest":"https://blog.csdn.net/qq_16804847/article/details/108049964","extend1":"pc","ab":"new"}"><div></div></div>
<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-e0530931f4.css" rel="stylesheet">
</div>