1. Dubbo框架优势
1.1 问题说明
问题1: 当服务生产者有一个宕机,问程序是否正常运行???
说明: 由于dubbo框架的机制,依然可以保证正常运行…
问题2: 如果整合zk集群宕机,问程序是否运行正常??
说明: 如果只是主机宕机,则zk有高可用的效果,程序不受影响.
说明2: 如果整合zk集群宕机,则用户依然可以正常访问,但是现在的程序处于危险状态.
说明3: 如果在上述的情况下,再次宕机一台生产者 程序依然可以正常运行. 因为维护了本地的服务列表信息.
2. Dubbo 负载均衡机制
2.1 负载均衡种类
说明: dubbo框架中负载均衡机制是客户端负载均衡. 该配置需要在客户端(消费者)中配置即可.
2.1.1 负载均衡-随机策略
1).类名称
2).配置负载均衡机制
2.1.2 负载均衡-轮询机制
1).设置轮询策略
1).轮询类名
2.1.3 负载均衡-一致性hash
1).Controller配置
2).具体类名
2.1.3 负载均衡-“最少访问”
1).编辑Controller
2).具体类名
2.2 数据在zk中存储结构说明
3.重构京淘项目
3.1 改造京淘项目
3.1.1 导入jar包
<!--引入dubbo配置 如果下载失败 则去本地仓库中删除重新下载-->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
3.1.2 定义Dubbo接口
3.2 定义服务生产者
3.2.1 编辑UserController
3.2.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
#链接的是数据库代理
#url: jdbc:mysql://192.168.126.129:8066/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
password: root
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-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 #每一个服务都有自己特定的端口 不能重复.
3.3 定义服务消费者
3.3.1 编辑UserController
3.3.2 编辑YML配置文件
server:
port: 8092
spring: #定义springmvc视图解析器
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
dubbo:
scan:
basePackages: com.jt
application:
name: consumer-user #定义消费者名称
registry: #注册中心地址
address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
4 完成京淘单点登录业务实现
4.1 用户注册实现
4.1.1 业务需求说明
说明: 当用户点击新增按钮时,应该将数据由jt-web服务器,传递给jt-sso项目完成入库操作.同时返回有效信息进行校验.
4.1.2 页面分析
1).url分析
2).参数说明
3). 检查页面JS
4.1.3 编辑JT-WEB UserController
/**
* 完成用户注册操作
* 1.url地址:http://www.jt.com/user/doRegister
* 2.参数: password: admin123
* username: admin12332412341234
* phone: 13111112227
* 3.返回值: SysResult对象
*/
@RequestMapping("/doRegister")
@ResponseBody //将返回值结果转化为JSON
public SysResult saveUser(User user){
userService.saveUser(user);
return SysResult.success();
}
4.1.4 编辑JT-SSO UserService
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.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import sun.security.provider.MD5;
@Service
public class DubboUserServiceImpl implements DubboUserService{
@Autowired
private UserMapper userMapper;
/**
* 业务:
* 1.将密码进行加密处理
* 2. 邮箱暂时用电话代替
* @param user
*/
@Override
public void saveUser(User user) {
byte[] bytes = user.getPassword().getBytes();
//利用Spring工具API进行加密操作
String md5Pass = DigestUtils.md5DigestAsHex(bytes);
user.setPassword(md5Pass).setEmail(user.getPhone());
userMapper.insert(user);
}
}
4.2 用户实现单点登录
4.2.1 业务需求
要求: 用户只需要登录一次,则可以在任意的服务器享受免密登录.有效期为30天.
sso介绍:
单点登录(SingleSignOn,SSO),就是通过用户的一次性鉴别登录。当用户在身份认证服务器上登录一次以后,即可获得访问单点登录系统中其他关联系统和应用软件的权限,同时这种实现是不需要管理员对用户的登录状态或其他信息进行修改的,这意味着在多个应用系统中,用户只需一次登录就可以访问所有相互信任的应用系统。这种方式减少了由登录产生的时间消耗,辅助了用户管理,是目前比较流行的 [1]
4.2.2 单点登录实现原理
单点登录实现步骤:
1.用户通过用户名和密码访问jt-web服务器.
2.JT-WEB服务器通过JT-SSO校验用户名和密码是否正确.
3.如果用户名和密码正确,则将数据保存到redis中. TICKET密钥:USERJSON,之后将密钥返回给用户即可.
4.JT-WEB服务器将密钥信息保存到用户的Cookie中 并且设定Cookie的共享/有效时间.
4.2.3 登录页面分析
1).url分析
2).参数分析
3).页面JS
4.2.4 编辑UserController
/**
* 业务需求:
* 实现用户单点登录操作
* 1.url地址:http://www.jt.com/user/doLogin?r=0.43530970885614617
* 2.请求参数: username: asdasdfas
* password: asdfasdfa
* 3.返回值结果: SysResult对象
*
* 实现Cookie数据存储
* 1.获取用户名和密码进行数据校验
* 2.获取后端的密钥信息 非空????
* 3.如果一切正常,则将数据存储到Cookie中. 路径/有效期/共享问题
*
* 关于Cookie说明:
* 1.cookie只能看到自己域名下的cookie 私有的.
* 2.setPath说明
* setPath("/") 一般都是/ 读取cookie权限的设定,根目录中的请求 读取cookie
* setPath("/user") url地址路径/user下时才能获取cookie信息.
* url1: http://www.jt.com/findUser;
* url2: http://www.jt.com/user/findUser;
*
*/
@RequestMapping("/doLogin")
@ResponseBody
public SysResult userLogin(User user, HttpServletResponse response){
String ticket = userService.findUserByUP(user);
if(!StringUtils.hasLength(ticket)){
//如果数据为null则表示用户名和密码错误...
return SysResult.fail();
}
//需要将数据保存到cookie中
Cookie cookie = new Cookie("JT_TICKET", ticket);
cookie.setPath("/");
cookie.setMaxAge(7*24*60*60); //设定有效期 7天有效 单位秒
cookie.setDomain("jt.com"); //主要域名中由jt.com则可以共享数据
response.addCookie(cookie); //将数据写入客户端
return SysResult.success();
}
4.2.5 编辑UserService
/**
* 1.校验用户名和密码是否正确 不存在直接返回null
* 2.动态生成密钥 将用户信息转化为JSON
* 3.将数据保存到redis中 7天有效.
* 4.返回密钥ticket信息.
* @param user
* @return
*/
@Override
public String findUserByUP(User user) {
String md5Pass =
DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
user.setPassword(md5Pass);
//1.根据对象中不为null的属性当做where条件
QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);
User userDB = userMapper.selectOne(queryWrapper);
//2.判断对象是否有值
if(userDB==null){
return null;
}
//3.表示用户名和密码正确 开启单点登录操作
String ticket = UUID.randomUUID()
.toString().replace("-", "");
//转化之前应该将数据进行脱敏处理
userDB.setPassword("123456");
String userJSON = ObjectMapperUtil.toJSON(userDB);
//4.将数据保存到redis中
jedisCluster.setex(ticket, 7*24*60*60, userJSON);
return ticket;
}
4.2.6 效果测试
4.3 用户数据回显
4.3.1 业务分析
如果用户登录成功之后,则通过cookie数据利用JSONP跨域方式,实现数据的动态获取.
4.3.2 页面URL分析
1).页面URL分析
2).检查页面JS
4.3.3 编辑JT_SSO UserController
/**
* 跨域请求:完成用户信息获取
* URL网址: http://sso.jt.com/user/query/dca70b16a1c54aea9ebb0b27621250de?callback=jsonp1608021961735&_=1608021961777
* 参数: 参数1: ticket信息 参数2:callback
* 返回值: SysResult对象(用户数据......)
*/
@RequestMapping("/query/{ticket}")
public JSONPObject findUserByTicket(@PathVariable String ticket,
String callback){
//如何获取用户信息? 从redis中获取数据
if(jedisCluster.exists(ticket)){
String userJSON = jedisCluster.get(ticket);
SysResult sysResult = SysResult.success(userJSON);
return new JSONPObject(callback, sysResult);
}else{
return new JSONPObject(callback, SysResult.fail());
}
}
5 作业
1.完成用户退出操作
重定向到系统首页
删除cookie记录 有效期设置0
删除redis 根据key来删除 key从哪来??? 提示 request对象
重定向和跨域有啥区别?????
重定向:自己访问自己的系统,出于业务的需要.
跨域: 不同的系统之间的数据的交互. 为我自己的业务提供帮助.