京淘项目实战开发-16

1.Dubbo入门案例

1.1 定义接口

在这里插入图片描述

1.2 接口项目与其他项目之间的关系

在这里插入图片描述

1.3 编辑服务生产者

1.3.1 生产者层级关系

由于内部由TCP-IP协议进行调用,所以不需要Controller层
在这里插入图片描述

1.3.2 编辑生产者的YML配置

server:
  port: 9000   #定义端口

spring:
  datasource:
    #引入druid数据源
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.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

#关于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  #每一个服务都有自己特定的端口 不能重复.

      
mybatis-plus:
  type-aliases-package: com.jt.dubbo.pojo       #配置别名包路径
  mapper-locations: classpath:/mybatis/mappers/*.xml  #添加mapper映射文件
  configuration:
    map-underscore-to-camel-case: true                #开启驼峰映射规则

1.3.3 关于服务生产者配置

在这里插入图片描述

1.4 编辑服务消费者

1.4.1 代码结构

在这里插入图片描述

1.4.2 消费者配置文件

server:
  port: 9001
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

1.4.3 编辑消费者Controller

在这里插入图片描述

1.5 关于Dubbo负载均衡说明

1.5.1 关于客户端负载均衡说明

由于所有的消费者在服务器内部完成了负载均衡,所以称之为客户端负载均衡.(区别于nginx的集中式负载均衡)

1.5.2 随机策略(默认策略)

在这里插入图片描述

1.5.3 轮询策略

在这里插入图片描述

1.5.3 一致性hash算法

将消费者与服务生产者绑定. 注意名称全部小写
在这里插入图片描述

1.5.4 最小访问量

挑选当前负载压力小的生产者 进行访问
在这里插入图片描述

1.6 关于微服务框架优势

1.6.1 zk服务器宕机是否影响用户使用

答案: 用户访问不受影响, 集群主要的目的为了容灾

1.6.2 zk集群宕机是否受影响

用户第一次链接zk集群之后,将服务列表信息.保存到本地. 暂时影响不大.
如果这时其中的一个提供者宕机,用户访问依然不受影响. 因为消费者会动态的维护自己的服务列表
此时Dubbo框架陷入危险中,需要尽快启动zk.

2.京淘项目改造

2.1 代码结构

说明:基于SOA思想 将项目进行改造
在这里插入图片描述

2.2 定义中立的接口

2.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 定义接口

在这里插入图片描述

2.3 构建服务生产者

2.3.1 代码改造

在这里插入图片描述

package com.jt.service.Impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.jt.mapper.UserMapper;
import com.jt.service.DubboUserService;
import org.springframework.beans.factory.annotation.Autowired;

@Service(timeout = 3000)
public class DubboUserServiceImpl implements DubboUserService {

    @Autowired
    private UserMapper userMapper;

}

2.3.2 YML配置改造

server:
  port: 8093
  servlet:
    context-path: /
spring:
  datasource:
    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:
    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  #每一个服务都有自己特定的端口 不能重复.

2.4 构建服务消费者

2.4.1 编辑UserController

说明:修改jt-web中的UserController

在这里插入图片描述

@Controller
@RequestMapping("/user")
public class UserController {

    @Reference
    private DubboUserService userService;
    /**
     * 实现通用的页面跳转
     * 1). 当用户网址 http://www.jt.com/user/login.html   要求跳转到登录页面中  login.jsp
     * 2). 注册页面  http://www.jt.com/user/register.html  要求跳转到登录页面中  register.jsp
     */
    //modleName模块名
    @RequestMapping("/{modleName}")
    public String module(@PathVariable String modleName){

        return modleName;
    }
}

2.4.1 编辑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 页面分析

1).页面URL分析
在这里插入图片描述

在这里插入图片描述

2).携带参数
在这里插入图片描述

3).页面JS分析
在这里插入图片描述

3.1.2 编辑UserController(jt-web)


    /**
     * 完成用户注册
     * 1.url地址:http://www.jt.com/user/doRegister
     * 2.参数:  password: admin123
     *          username: admin1234
     *          phone: 13111111112
     * 3.返回值:  SysResult对象  json
     */
    @RequestMapping("/doRegister")
    @ResponseBody
    public SysResult doRegister(User user){

        userService.saveUser(user);
        return SysResult.success();
    }

3.1.3 编辑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;

@Service(timeout = 3000)
public class DubboUserServiceImpl implements DubboUserService{

    @Autowired
    private UserMapper userMapper;
    
    /**
     * 1.对密码进行加密处理
     * 2.邮箱用电话代替
     * @param user
     */
    @Transactional
    @Override
    public void saveUser(User user) {
        //字符串转字节
        byte[] bytes = user.getPassword().getBytes();
        //MD5加密
        String md5Pass = DigestUtils.md5DigestAsHex(bytes);
        user.setEmail(user.getPhone())
                .setPassword(md5Pass);//把加密的密码存入数据库
        userMapper.insert(user);
    }
}

运行测试:
在这里插入图片描述

在这里插入图片描述

这个BUG,是因为热部署照成的,因为热部署启动过快,zookeeper反应不过来,所以生成了2条记录。
解决办法:要么重启(先启动服务提供者,在启动服务消费者),要么关闭热部署!
在这里插入图片描述
在这里插入图片描述

3.2 用户登录

3.2.1 SSO介绍

      单点登录(SingleSignOn,SSO),就是通过用户的一次性鉴别登录。当用户在身份认证服务器上登录一次以后,即可获得访问单点登录系统中其他关联系统和应用软件的权限,同时这种实现是不需要管理员对用户的登录状态或其他信息进行修改的,这意味着在多个应用系统中,用户只需一次登录就可以访问所有相互信任的应用系统。这种方式减少了由登录产生的时间消耗,辅助了用户管理,是目前比较流行的 [1]

3.2.2 SSO登录策略

在这里插入图片描述

1).用户输入用户名和密码点击登录时传递用户信息到web服务器中。
    JT-WEB将信息RPC调用到JT-SSO单点登录系统中进行数据的校验

2).如果用户名和密码正确,则将用户名信息保存到redis中,注意超时时间(7天有效),如果用户名和密码错误则直接提示用户即可。

3).如果用户名和密码正确,则将TICKET信息保存到用户的Cookie中(7天有效)

4).当用户重复访问时,则动态获取TICKET信息,之后去Redis缓存中校验数据是否有效. 有效则放行 无效则拦截.

3.2.3 用户登录页面分析

1).url分析
在这里插入图片描述
2).参数提交
在这里插入图片描述
3).页面JS
在这里插入图片描述

3.2.4 编辑UserController

 /**
     * 完成用户单点登录流程
     * 1.URL地址:http://www.jt.com/user/doLogin?r=0.8136555319489749
     * 2.参数分析: username: admin123
     *            password: admin123456
     * 3.系统返回值: SysResult对象
     * Cookie作用: 浏览器用来保存服务器数据的一种方式
     * setPath():    代表cookie中一种权限的设定.
     * 例子:
     *      url地址: http://www.jt.com/addUser/xxxx
     *      url2地址 http://www.jt.com/xxxx
     *
     *      cookie.setPath(/)           url/url2可以获取cookie中的值
     *      cookie2.setPath(/addUser)    url可以获取cookie2中的值
     *
     * setDomain("jt.com");  表示cookie在jt.com结尾的域名下进行共享.
     *
     *
     */
    @RequestMapping("/doLogin")
    @ResponseBody
    public SysResult doLogin(User user, HttpServletResponse response){
        //假设ticket正确返回
        String ticket = userService.doLogin(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);
        cookie.setDomain("jt.com");
        response.addCookie(cookie);*/
        //通过工具包,封装cookie
        CookieUtil.addCookie("JT_TICKET", ticket,
                "jt.com",7*24*60*60, response);
        return SysResult.success();
    }

编写工具包

package com.jt.util;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

public class CookieUtil {
    public static void addCookie(String cookieName, String cookieValue, String domain, Integer maxAge, HttpServletResponse response){
        Cookie cookie = new Cookie(cookieName, cookieValue);
        cookie.setPath("/");
        cookie.setDomain(domain);
        cookie.setMaxAge(maxAge);
        response.addCookie(cookie);//上传给cookie
    }
}

3.2.5 编辑UserService

/**
     * 1.校验用户信息是否有效
     * 2.进行单点登录流程
     * @param user
     * @return
     */
      @Override
    public String doLogin(User user) {
        字符串转字节
        byte[] bytes = user.getPassword().getBytes();
        //MD5加密
        String md5Pass= DigestUtils.md5DigestAsHex(bytes);
        user.setPassword(md5Pass);
        //user用户名和密码不为空,把它传给userDB数据库中
        User userDB = userMapper.selectOne(new QueryWrapper<>(user));
        if (userDB == null){
            //根据用户名和密码没有查询到
            return null;
        }
        //不为空,用户名和密码正确 开始启动单点登录的流程
        String ticket = UUID.randomUUID().toString();
        //生成用户JSON
        //为了防止泄密 进行脱敏处理
        userDB.setPassword("123456");//不影响数据库中的数据
        String userJSON = ObjectMapperUtil.toJSON(userDB);
        //setex设置7天有效
        jedisCluster.setex(ticket, 7*24*60*60,userJSON);
        //如果程序执行正确,则返回密钥
        return ticket;
    }

3.2.6 页面效果展现

在这里插入图片描述

报错:Connection refused: no further information (连接被拒绝:无进一步信息)
在这里插入图片描述解决方法:Linux是否启动了redis,检查是否开启了防火墙!!!

3.3 用户数据回显

3.3.1 页面URL分析

1).页面分析
在这里插入图片描述
2).页面JS分析

//当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);
					console.log(data.data);
					console.log(_data);
					var html =_data.username+",欢迎来到京淘!<a href=\"http://www.jt.com/user/logout.html\" class=\"link-logout\">[退出]</a>";
					$("#loginbar").html(html);
				}
			}
		});

3.3.2 编辑JT-SSO UserController

   /**
     * 实现用户跨域数据的回显   JSONP
     * URL地址: http://sso.jt.com/user/query/edf7eb6a-3cb1-472e-9d27-b21d727b60c3?callback=jsonp1616574179860&_=1616574179904
     * 参数:  ticket信息拼接到url中   restFul风格
     * 返回值: StsResult对象
     */
    @RequestMapping("/query/{ticket}")
    public JSONPObject findUserByTicket(@PathVariable String ticket,String callback){

        String userJSON = jedisCluster.get(ticket);
        if(!StringUtils.hasLength(userJSON)){ //如果为null

            return new JSONPObject(callback, SysResult.fail());
        }
        //服务器需要向客户端传递数据.
       // User user = ObjectMapperUtil.toObject(userJSON, User.class)

       return new JSONPObject(callback, SysResult.success(userJSON));
    }

3.3.3 页面效果展现

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值