80--JT项目18(Dubbo负载均衡/单点登录/注册业务)
1.Dubbo负载均衡说明
1.1 zookeeper数据存储结构
1.2 Dubbo通讯原理
通讯协议: dubbo协议(tcp-ip)
说明: dubbo协议将TCP-IP协议进行封装.
Dubbo框架中使用dubbo协议建立了链接,之后通过IP:20880等端口进行通讯,与LinuxIP地址无关.
图中的ip就是动态生成的,与其他的无关
1.3 Dubbo负载均衡策略
1.3.1 hash一致性原则
根据IP:port进行hash运算,之后绑定固定的提供者进行访问.
效果: 以后消费者与服务提供者进行了绑定.
在dubbo-jt项目中入门案例里面,对消费者的controller进行负载均衡配置
1.3.2 挑选访问压力最小的
说明:挑选当前服务器压力较小的进行访问.
1.3.3 随机访问
说明:如果什么都不配置,则采用随机算法.
1.3.4 轮询策略
说明:按照顺序进行访问,循环往复
1.4 简述什么是客户端负载均衡/集中式负载均衡
1).什么是集中式的负载均衡 (nginx)
特点:
1).用户访问服务器时,自己不清楚访问的真实的服务器到底是谁,由nginx服务器动态的反向代理实现.
2).统一由负载均衡服务器进行负载. 问题 负载均衡服务器访问压力高.
客户端负载均衡
1).消费者在访问服务提供者时清楚的了解 到底应该访问哪台服务器.
2).由于每个客户端都进行负载均衡.相当于将压力均匀的分配给客户端.访问压力低.
核心: 1).nginx一般只负责反向代理
2).在微服务框架中 几乎都是客户端负载均衡服务器.
2.京淘项目改造--Dubbo框架的应用
2.1导入jar包
<!--引入dubbo配置 -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
2.2 添加接口
说明:提供接口,也就是提供了规范
2.3 构建服务提供者(JT-SSO)
2.3.1 编辑提供者Service实现类
2.3.2 编辑jt-sso中YML配置文件
说明:在jt-sso中的yml配置文件中实现dubbo的配置
server:
port: 8093
servlet:
context-path: /
spring:
datasource:
#引入druid数据源
#type: com.alibaba.druid.pool.DruidDataSource
#driver-class-name: com.mysql.jdbc.Driver
#url: jdbc:mysql://192.168.126.129:8066/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
password: 1234
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的包路径 扫描dubbo的注解
application: #应用名称
name: provider-user #一个接口对应一个服务名称 相同的接口服务名称必定一 致. 不同的接口服务名称- 一定不一致.
registry: #配置注册中心
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.4 构建服务消费者(JT-WEB)
2.4.1 编辑UserController
2.4.2 编辑jt-web中YML配置文件
server:
port: 8092
spring: #定义springmvc视图解析器
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
#配置dubbo
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 业务分析
1).url地址分析
2).页面JS
$.ajax({
type : "POST",
url : "/user/doRegister",
contentType : "application/x-www-form-urlencoded; charset=utf-8",
data : {password:_password,username:_username,phone:_phone},
dataType : 'json',
success : function(result) {
if(result.status == "200"){
// 注册成功,去登录页
showMessage('注册成功,请登录!');
verc();
$("#registsubmit").removeAttr("disabled").removeClass()
.addClass("btn-img btn-regist");
isSubmit = false;
return;
}else{
showMessage('注册失败,请联系管理员!');
//alert('注册失败,请重新注册! ' + result.data );
}
});
3).分析返回值:返回SysResult对象(result.status == "200")
3.1.2 编辑jt-web中UserController
/**
* 业务说明:完成用户数据入库操作
* 1.url地址: http://www.jt.com/user/doRegister
* 2.参数问题: {password:_password,username:_username,phone:_phone},
* 3.返回值结果: SysResult对象
*/
@RequestMapping("/doRegister")
@ResponseBody
public SysResult doRegister(User user){
//service 第三方接口. 直接rpc调用访问jt-sso中的实现类
userService.saveUser(user);
return SysResult.success();
}
3.1.3 编辑jt-sso中DubboUserServiceImpl
package com.jt.service;
import com.alibaba.dubbo.config.annotation.Service;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
@Service //注意使用Dubbo的注解
public class DubboUserServiceImpl implements DubboUserService{ //alt+shift+p
@Autowired
private UserMapper userMapper;
/**
* 1.密码加密
* 2.邮箱使用手机代替
* @param user
*/
@Override
public void saveUser(User user) {
String md5Password = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
user.setPassword(md5Password).setEmail(user.getPhone());
userMapper.insert(user);
}
}
3.2 用户登录实现
3.2.1 用户登录要求
如果用户在www.jt.com中完成完成了登录操作.则用户在其他的京淘项目的子系统中都可以实现免密登录.
3.2.2 SSO介绍
单点登录(SingleSignOn,SSO),就是通过用户的一次性鉴别登录。当用户在身份认证服务器上登录一次以后,即可获得访问单点登录系统中其他关联系统和应用软件的权限,同时这种实现是不需要管理员对用户的登录状态或其他信息进行修改的,这意味着在多个应用系统中,用户只需一次登录就可以访问所有相互信任的应用系统。这种方式减少了由登录产生的时间消耗,辅助了用户管理,是目前比较流行的 [1]
架构分析
实现步骤:
1.当用户输入用户名和密码之后点击提交按钮.将数据传给JT-WEB服务器.
2.JT-WEB利用RPC方式访问JT-SSO 校验数据是否有效.
3.如果校验的数据准备无误,之后将用户信息保存到Redis中. key 使用uuid, value使用userJSON. 并且设定7天超时.
4.JT-SSO 将服务器数据返回给JT-WEB服务器.(如果用户名和密码错误的则返回为null即可).
5.JT-WEB服务器将数据保存到Cookie中.(要求实现Cookie共享/doMain方法).
3.2.3 用户登录页面分析
1).页面URL分析
2).页面参数分析
3).页面JS分析
3.2.4 编辑jt-web中UserController
/**
* 請求地址: http://www.jt.com/user/doLogin?r=0.4026067653434138
* 參數 username password
* 返回值結果 SysResult
* 需求: 將cookie名称为JT_TICKET数据输出到浏览器中,要求7天超时,并且实现"jt.com"数据共享
*/
@RequestMapping("/doLogin")
@ResponseBody
public SysResult doLogin(User user, HttpServletResponse response){
//完成用户登录操作,然后需要获取ticket密钥
String ticket = dubboUserService.doLogin(user);
if (StringUtils.isEmpty(ticket)){
//说明用户名或者密码有问题
return SysResult.fail();
}
//创建cookie对象
Cookie cookie = new Cookie("JT_TICKET",ticket);
//设置cookie的存活时间 -1 表示关闭当前会话,cookie删除
//设置cookie的存活时间 0 表示立即cookie删除
//设置cookie的存活时间 >0 表示设置cookie的超时时间
cookie.setMaxAge(7*24*60*60);
cookie.setPath("/");
//在jt.com中实现数据的共享
cookie.setDomain("jt.com");
//添加cookie,将数据保存到浏览器
response.addCookie(cookie);
return SysResult.success();
}
3.2.5 编辑jt-sso中 DubboUserServiceImpl
/**
* 目的 : 校验用户信息是否有效并且实现单点登录操作
* 步骤
* 1. 校验用户名和密码是否正确(密码明文转化为密文)
* 2. 查询数据库是否有结果
* 3.如果有结果则生成ticket信息(UUID) ,将user转化为userJson
* 4.将数据保存到redis中,并且设定超时时间
* 5.返回当前用户登录的密钥
* @param user
* @return
*/
@Override
public String doLogin(User user) {
//将明文转化为密文
String password = user.getPassword();
String digestAsHex = DigestUtils.md5DigestAsHex(password.getBytes());
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username",user.getUsername()).eq("password",digestAsHex);
//获取的是用户的全部记录 (包含涉密信息)
User user1 =userMapper.selectOne(queryWrapper);
//检验数据是否有效
if (user1==null){
//如果数据无效,怎返回null
return null;
}
//如果程序执行到这里,说明用户名和密码正确的. 开启单点登录流程
String ticket = UUID.randomUUID().toString().replace("-","");
//脱敏处理 余额/密码/手机号/家庭地址
user1.setPassword("123456?你信吗");
String json = ObjectMapperUtils.toJSON(user);
jedisCluster.setex(ticket,7*24*60*60,json);
return ticket;
}
3.2.6 页面效果测试
说明:cookie的value值成为一个随机的数字
3.3 实现用户信息回显
3.3.1 业务需求
说明:当用户登录成功之后,需要在顶部实现数据的回显. 根据ticket获取用户用户的JSON信息.
3.3.2 编辑页面jt.js
var TT = JT = {
checkLogin : function(){
//获取指定名称的cookie
var _ticket = $.cookie("JT_TICKET");
if(!_ticket){//对象为空.则执行下面内容
return ;
}
//当dataType类型为jsonp时,jQuery就会自动在请求链接上增加一个callback的参数
$.ajax({
url : "http://sso.jt.com/user/query/" + _ticket,
dataType : "jsonp",
type : "GET",
success : function(data){
if(data.status == 200){
//把json串转化为js对象
var _data = JSON.parse(data.data);
var html =_data.username+",欢迎来到京淘!<a href=\"http://www.jt.com/user/logout.html\" class=\"link-logout\">[退出]</a>";
$("#loginbar").html(html);
}
}
});
}
}
$(function(){
// 查看是否已经登录,如果已经登录查询登录信息
TT.checkLogin();
});
3.3.3 编辑JT-SSO中的UserController
说明:通过跨域的方式进行数据回显,所以需要在jt-sso中的控制层进行代码编写
/**
* 登录成功以后进行数据回显
* url地址:http://sso.jt.com/user/query/b11facd89dec4789907e638dfbbd8bf7?callback=jsonp1598089308095&_=1598
* 参数 ticket
* 返回值 SysResult 用jsonp封装
*/
@RequestMapping("/query/{ticket}")
public JSONPObject doTicket(@PathVariable("ticket") String ticket,String callback){
String userJson = jedisCluster.get(ticket);
if (userJson==null){
return new JSONPObject(callback,SysResult.fail());
}
else {
return new JSONPObject(callback,SysResult.success(userJson));
}
}