1.Dubbo框架介绍
1.1 Dubbo框架通讯的方式
说明:只要使用Dubbo框架 ,在内部使用了dubbo协议进行通讯,其中的IP地址是动态生成的.并且端口号是访问服务的唯一标识信息.
1.2 ZK存储数据的结构
说明:zk中的数据的存储的方式是树形结构的.一般三级.
1.3 关于负载均衡的说明
1.3.1 集中式的负载均衡
说明:由于nginx处于负载均衡的中心,所以什么样的服务都会经过nginx之后转向到不同的服务器中. 所以会造成nginx的负载压力很大.
nginx的主要的作用是反向代理.
1.3.2 客户端的负载均衡
说明:在微服务调用过程中每个服务的消费者都可以在客户端实现负载均衡的操作,在每次请求之前通过服务列表获取将要访问的服务信息.实现了压力私有化.
1.3.3 Dubbo负载均衡的方式
名称都是类名的前半部分都小写即可.
1.RandomLoadBalance 随机负载均衡 语法: random 默认的
2.RoundRobinLoadBalance 轮询策略 语法: roundrobin
3.ConsistentHashLoadBalance 一致性hash算法 将消费者与服务提供者绑定 语法: consistenthash
4.LeastActiveLoadBalance 挑选负载压力小的服务器进行访问 语法: leastactive
2 京淘项目Dubbo改造
2.1 改造计划
1.jt-common充当接口项目
2.jt-sso 充当用户的提供者 服务端口号20880 服务名称 provider-sso 接口DubboUserService
3.jt-web 充当用户的消费者
2.2 导入Dobbu jar包
<!--引入dubbo配置 -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
2.3 编辑Dubbo接口
说明:在jt-common中添加Dubbo的业务接口
2.4 编辑jt-sso的服务提供者
2.4.1 编辑Service实现类
2.4.2 编辑YML配置文件
server:
port: 8093
servlet:
context-path: /
spring:
datasource:
#引入druid数据源
#type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
password: root
#提供了MVC的支持
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
#mybatis-plush配置
mybatis-plus:
type-aliases-package: com.jt.pojo
mapper-locations: classpath:/mybatis/mappers/*.xml
configuration:
map-underscore-to-camel-case: true
logging:
level:
com.jt.mapper: debug
#关于Dubbo配置
dubbo:
scan:
basePackages: com.jt #指定dubbo的包路径
application: #应用名称
name: provider-sso #一个接口对应一个服务名称
registry: #zk集群 主机中的信息与从机中的信息一致的 从zk中获取数据的时候链接的从机 主机的作用就是监控集群
address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
protocol: #指定协议
name: dubbo #使用dubbo协议(tcp-ip) web-controller直接调用sso-Service
port: 20880 #每一个服务都有自己特定的端口 不能重复.
2.5 编辑服务消费者
2.5.1 编辑UserController
注入UserService注解
2.5.2 编辑YML配置文件
server:
port: 8092
spring: #定义springmvc视图解析器
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
dubbo:
scan:
basePackages: com.jt
application:
name: consumer-web #定义消费者名称
registry: #注册中心地址
address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
3 用户模块实现
3.1 用户注册
3.1.1 页面分析
3.1.2 页面JS分析
说明:根据页面url地址 查找页面JS的位置
3.1.3 编辑UserController
/**
* 完成用户注册操作.
* url地址: http://www.jt.com/user/doRegister
* 参数: {password:_password,username:_username,phone:_phone}
* 返回值: SysResult对象 返回的是JSON串
* 业务说明:通过dubbo框架将user信息RPC传入jt-sso实现数据的入库操作.
* */
@RequestMapping("/doRegister")
@ResponseBody
public SysResult saveUser(User user){
dubboUserService.saveUser(user);
return SysResult.success();
}
3.1.4 编辑UserService
package com.jt.service;
import com.alibaba.dubbo.config.annotation.Service;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import com.jt.vo.SysResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
@Service //dubbo的注解
public class DubboUserServiceImpl implements DubboUserService{
@Autowired
private UserMapper userMapper;
/**
* 1.邮箱暂时使用电话号码代替
* 2.需要将密码进行加密处理 md5/md5-hash
* @param user
* @return
*/
@Override
@Transactional
public void saveUser(User user) {
//1.获取明文
String password = user.getPassword();
//2.利用Spring的工具API进行加密操作
password = DigestUtils.md5DigestAsHex(password.getBytes());
user.setPassword(password).setEmail(user.getPhone());
userMapper.insert(user);
}
}
3.1.4 关于POJO转化异常说明
报错说明: 由于SpringBoot配置了热部署的工具,当代码进行修改之后,程序就会重新启动. 在重启的过程中程序又会再次链接zookeeper注册中心.由于zk的心跳检测机制存在超时时间,可能在zk中会出现2条一模一样的服务的提供者的信息.
解决方案: 需要手动的重启服务器即可.
3.2 单点登录实现策略
3.2.1 需求说明
要求用户只需要登录一次,那么就可以访问其他的认证系统,无需用户再次登录.
如果采用如下的配置,则必然会出现用户频繁登录的现象.
3.2.2 SSO介绍
单点登录(SingleSignOn,SSO),就是通过用户的一次性鉴别登录。当用户在身份认证服务器上登录一次以后,即可获得访问单点登录系统中其他关联系统和应用软件的权限,同时这种实现是不需要管理员对用户的登录状态或其他信息进行修改的,这意味着在多个应用系统中,用户只需一次登录就可以访问所有相互信任的应用系统。这种方式减少了由登录产生的时间消耗,辅助了用户管理,是目前比较流行的 一种登录方式
3.2.3 单点登录实现策略
步骤:
1.当用户输入用户名和密码时需要将数据传递给jt-web服务器进行登录操作.
2.jt-web服务器需要将数据传到jt-sso服务器中进行数据的校验.
3.jt-sso根据username/password查询数据库校验数据是否有效.
4.如果用户名和密码正确则将数据经过处理之后保存到redis中 KEY=UUID(每次生成的都不一样) VALUE=“userJSON”
5.如果用户写入redis成功,之后需要将用户的登录的凭证返回给客户端.
6.JT-WEB服务器将获取的TICKET信息保存到客户端的Cookie中,方便下次使用. 并且要求cookie共享的.
3.3 用户登录具体实现
3.3.1 用户登录页面分析
1.url分析
2.参数分析
3.页面JS分析
$.ajax({
type: "POST",
url: "/user/doLogin?r=" + Math.random(),
contentType: "application/x-www-form-urlencoded; charset=utf-8",
data: {
username:_username,password:_password},
dataType : "json",
error: function () {
$("#nloginpwd").attr({
"class": "text highlight2" });
$("#loginpwd_error").html("网络超时,请稍后再试").show().attr({
"class": "error" });
$("#loginsubmit").removeAttr("disabled");
$this.removeAttr("disabled");
},
success: function (result) {
//如果数据不为null时执行
if (result) {
var obj = eval(result);
if (obj.status == 200) {
obj.success = "http://www.jt.com";
.....
3.3.2 编辑UserController
/**
* 完成用户的登录操作
* url地址:http://www.jt.com/user/doLogin?r=0.8989367429030823
* 参数: username/password
* 返回值: SysResult对象 的JSON的数据.
*
* cookie.setMaxAge(-1); 关闭浏览器会话时删除
* cookie.setMaxAge(0); 立即删除cookie
* cookie.setMaxAge(100); cookie可以存储的时间单位是秒
*
* http://www.jt.com/saveUser/xxx
* cookie.setPath("/");
* cookie.setPath("/add");
*/
@RequestMapping("/doLogin")
@ResponseBody
public SysResult doLogin(User user, HttpServletResponse response){
//1.实现用户的登录操作!!!
String ticket = dubboUserService.doLogin(user);
//2.校验ticket是否有值.
if(StringUtils.isEmpty(ticket)){
//用户名或者密码错误
return SysResult.fail();
}
//3.如果用户的ticket不为null,则表示登录正确,需要将数据保存到cookie中
//Cookie要求 1.7天有效 2.要求cookie可以在jt.com的域名中共享 3.cookie权限 /
Cookie cookie = new Cookie("JT_TICKET",ticket);
cookie.setMaxAge(7*24*3600);
cookie.setDomain("jt.com"); //在jt.com中实现页面共享.
cookie.setPath("/"); //定于cookie的权限根目录有效
response.addCookie(cookie); //利用response将cookie保存到客户端中.
return SysResult.success();
}
3.3.3 编辑UserServiceImpl
/**
* 1.根据用户名和密码查询数据库
* 2.校验用户数据的有效性.
* 3.如果用户的数据是正确的 则开始进行单点登录操作.
* 4.如果用户数据不正确 则ticket数据为null即可.
* @param user
* @return
*/
@Override
public String doLogin(User user) {
//1.将密码进行加密处理
String password = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
user.setPassword(password);
//如果传递的是对象,则根据对象中不为null的属性充当where条件
QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);
User userDB = userMapper.selectOne(queryWrapper);
//2.校验数据是否有效
if(userDB == null){
return null;
}
//userDB数据不为null,用户的输入信息正确.开启单点登录操作.
//3.1动态生成uuid
String ticket = UUID.randomUUID().toString().replace("-", "");
//3.2脱敏处理
userDB.setPassword("123456你信不??");
String userJSON = ObjectMapperUtil.toJSON(userDB);
//3.3 将数据保存到redis中
jedisCluster.setex(ticket, 7*24*60*60, userJSON);
return ticket;
}
3.3.4 数据校验
3.4 用户登录回显
3.4.1 用户信息回显说明
当用户登录成功之后会生成COOKIE信息.根据cookie获取TICKET信息,之后根据ticket获取user信息,.之后在首页展现用户名称即可.
3.4.2 页面分析
1).页面url分析
2).页面JS分析
3.4.3 编辑JT-SSO UserController
/**
* 根据ticket信息查询用户的json信息 jsonp请求 返回值使用特定的对象封装.
* url地址:http://sso.jt.com/user/query/ca620491866a42e596b29ee52fc27aff?callback=jsonp1600333068471&_=1600333068521
*/
@RequestMapping("/query/{ticket}")
public JSONPObject findUserByTicket(@PathVariable String ticket, HttpServletResponse response,
String callback){
if(jedisCluster.exists(ticket)){
//可以正确返回
String userJSON = jedisCluster.get(ticket);
return new JSONPObject(callback, SysResult.success(userJSON));
}else{
//如果根据ticket查询有误,则应该删除Cookie信息.
Cookie cookie = new Cookie("JT_TICKET","");
cookie.setDomain("jt.com");
cookie.setPath("/");
cookie.setMaxAge(0);
response.addCookie(cookie);
return new JSONPObject(callback, SysResult.fail());
}
}
作业
1: 完成退出操作
1.要求当用户点击退出按钮时 应该重定向到系统的首页
2.删除Redis中的数据
3.删除Cookie中的数据.
2.将用户模块的代码重新构建一遍
3.预习SpringMVC中的拦截器机制