1. Dubbo
1.1 创建接口
1.2 创建服务生产者
1.2.1 定义生产者的实现类
package com.jt.dubbo.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import com.alibaba.dubbo.config.annotation.Service;
import com.jt.dubbo.mapper.UserMapper;
import com.jt.dubbo.pojo.User;
@Service(timeout=3000) //3秒超时 内部实现了rpc
//@org.springframework.stereotype.Service//将对象交给spring容器管理
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public List<User> findAll() {
System.out.println("我是第一个服务的提供者");
return userMapper.selectList(null);
}
@Override
public void saveUser(User user) {
userMapper.insert(user);
}
}
1.2.2 提供者配置文件
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 服务消费者
1.3.1 编辑Controller
package com.jt.dubbo.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.dubbo.pojo.User;
import com.jt.dubbo.service.UserService;
@RestController
public class UserController {
//利用dubbo的方式为接口创建代理对象 利用rpc调用
//调用远程服务就像调用自己的服务一样的简单!!!
@Reference
private UserService userService;
/**
* Dubbo框架调用特点:远程RPC调用就像调用自己本地服务一样简单
* @return
*/
@RequestMapping("/findAll")
public List<User> findAll(){
//远程调用时传递的对象数据必须序列化.
return userService.findAll();
}
@RequestMapping("/saveUser/{name}/{age}/{sex}")
public String saveUser(User user) {
userService.saveUser(user);
return "用户入库成功!!!";
}
}
1.3.2 编辑YML配置文件
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.3.3 消费者测试
1.4 Dubbo高可用测试
1.4.1 测试需求
1).测试当服务器宕机,用户访问是否受影响. 用户访问不受影响. zk心跳检测机制
2).测试当zk集群宕机,用户访问是否受影响. 不受影响 消费者在本地有服务列表数据,自己维护.
3).测试是否有负载均衡的效果 用户访问有负载均衡的效果
1.5 Dubbo负载均衡
1.5.1 负载均衡方式
1.服务端负载均衡(集中式负载均衡)
说明: 用户访问服务器时不清楚真实的服务器到底是谁,由负载均衡服务器动态动态管理.
典型代表: NGINX
一般nginx服务器做反向代理使用,负载均衡只是提供的功能.
2.客户端负载均衡
说明:采用微服务架构时,当消费者访问服务提供者时,由于框架内部已经实现了负载均衡的策略,所以消费者访问提供者时已经完成了负载均衡的机制.所以将所有的压力平衡到了各个消费者中.
1.5.2 负载均衡-随机算法
1.5.2 负载均衡-轮询算法
1.5.3 负载均衡-一致性hash
1.5.3 负载均衡-最少访问
2. 重构京淘项目
2.0 导入jar包
<!--引入dubbo配置 -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
2.1 重构接口项目
2.2 重构JT-SSO(生产者)
2.2.1编辑Service实现类
2.2.2 编辑YML配置文件
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://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.3 重构服务消费者
2.3.1 编辑UserController
2.3.2 编辑YML配置文件
server:
port: 8092
spring: #定义springmvc视图解析器
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
#配置dubbo消费者
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
3. 用户模块实现
3.1 用户注册实现
3.1.1 页面分析
3.1.2 编辑UserController
/**
* 完成用户的注册操作
* url地址: http://www.jt.com/user/doRegister
* Request Method: POST
* 请求参数:
* password: admin123
* username: admin123123123
* phone: 13111112225
* 返回值类型:
* SysResult对象
*/
@RequestMapping("/doRegister")
@ResponseBody
public SysResult saveUser(User user){
//利用dubbo进行RPC调用
dubboUserService.saveUser(user);
return SysResult.success();
}
3.1.2 编辑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.util.DigestUtils;
@Service(timeout = 3000)
public class DubboUserServiceImpl implements DubboUserService{
@Autowired
private UserMapper userMapper;
@Override
public void saveUser(User user) {
//密码采用md5方式进行加密处理
String password = user.getPassword();
String md5Pass = DigestUtils.md5DigestAsHex(password.getBytes());
user.setEmail(user.getPhone()).setPassword(md5Pass);
userMapper.insert(user);
}
}
3.1.3 页面效果展现
3.2 用户登录
3.2.1 单点登录业务实现
单点登录(SingleSignOn,SSO),就是通过用户的一次性鉴别登录。当用户在身份认证服务器上登录一次以后,即可获得访问单点登录系统中其他关联系统和应用软件的权限,同时这种实现是不需要管理员对用户的登录状态或其他信息进行修改的,这意味着在多个应用系统中,用户只需一次登录就可以访问所有相互信任的应用系统。这种方式减少了由登录产生的时间消耗,辅助了用户管理,是目前比较流行的.
实现步骤:
1.用户输入用户名和密码之后点击登录按钮开始进行登录操作.
2.JT-WEB向JT-SSO发送请求,完成数据校验
3.当JT-SSO获取数据信息之后,完成用户的校验,如果校验通过则将用户信息转化为json.并且动态生成UUID.将数据保存到redis中. 并且返回值uuid.
如果校验不存在时,直接返回”不存在”即可.
4.JT-SSO将数据返回给JT-WEB服务器.
5.如果登录成功,则将用户UUID保存到客户端的cookie中.
3.2.2 页面URL分析
3.2.3 编辑UserController
/**
* 业务:完成用户登录操作
* url地址: http://www.jt.com/user/doLogin?r=0.35842191622936337
* 参数:
* username: admin123
* password: admin123456
* 返回值: SysResult对象
*
* 业务具体实现:
* 1.校验用户名和密码是否正确
* 2.判断返回值结果是否为null 用户名和密码有误 返回201状态码
* 3.如果返回值结果不为null uuid保存到cookie中即可.
*
* Cookie知识介绍:
* 1.cookie.setPath("/") 根目录有效
* url1: www.jt.com/addUser
* url2: www.jt.com/user/addUser
*
* 2. cookie.setDomain("域名地址"); cookie在哪个域名中共享
* 例子1: cookie.setDomain("www.jt.com");
* 只有在www.jt.com的域名中有效
*
* cookie.setDomain("jt.com");
* 只有在jt.com结尾的域名中有效
*
*/
@RequestMapping("/doLogin")
@ResponseBody
public SysResult doLogin(User user, HttpServletResponse response){
String uuid = dubboUserService.doLogin(user);
if(StringUtils.isEmpty(uuid)){
return SysResult.fail();
}
//将uuid保存到Cookie中
Cookie cookie = new Cookie("JT_TICKET",uuid);
cookie.setMaxAge(30*24*60*60); //让cookie 30天有效
cookie.setPath("/"); //cookie在哪个url路径生效
cookie.setDomain("jt.com"); //设定cookie共享
response.addCookie(cookie);
return SysResult.success();
}
3.2.4 编辑UserService
/**
* 1.根据用户名和密码查询后端服务器数据
* 将密码加密处理
* @param user
* @return
*/
@Override
public String doLogin(User user) {
String md5Pass = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
user.setPassword(md5Pass);
QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);//u/p不能
//根据对象中不为空的属性,充当where条件.
User userDB = userMapper.selectOne(queryWrapper);
if(userDB == null){
//根据用户名和密码错误
return null;
}
//开始进行单点登录业务操作
String uuid = UUID.randomUUID()
.toString()
.replace("-", "");
userDB.setPassword("123456你信不?"); //去除有效信息.
String userJSON = ObjectMapperUtil.toJSON(userDB);
jedisCluster.setex(uuid, 30*24*60*60, userJSON);
return uuid;
}
3.2.5 页面效果展现
3.3 用户信息回显
3.3.1 用户信息回显业务需求
思路: 用户通过TICKET信息,利用JSONP的方式动态获取远程的服务器数据信息.之后将数据返回之后 回显数据.
3.3.2 用户URL请求
3.3.3 页面JS分析
3.3.4 编辑JT-SSO的UserController
/**
* 业务说明:
* 通过跨域请求方式,获取用户的JSON数据.
* 1.url地址: http://sso.jt.com/user/query/efd321aec0ca4cd6a319b49bd0bed2db?callback=jsonp1605775149414&_=1605775149460
* 2.请求参数: ticket信息
* 3.返回值: SysResult对象 (userJSON)
* 需求: 通过ticket信息获取user JSON串
*/
@RequestMapping("/query/{ticket}")
public JSONPObject findUserByTicket(@PathVariable String ticket,String callback){
String userJSON = jedisCluster.get(ticket);
if(StringUtils.isEmpty(userJSON)){
return new JSONPObject(callback, SysResult.fail());
}else{
return new JSONPObject(callback, SysResult.success(userJSON));
}
}
3.3.5 页面效果展现
3.4 用户登出操作
3.4.1 退出业务逻辑
当用户点击退出操作时,应该重定向到系统首页. 同时删除redis信息/Cookie信息.
3.4.2 编辑UserController
/**
* 完成用户退出操作
* url地址:http://www.jt.com/user/logout.html
* 参数: 没有参数
* 返回值: String 重定向到系统首页
* 业务:
* 1.删除redis K-V 获取ticket信息
* 2.删除cookie
*/
@RequestMapping("/logout")
public String logout(HttpServletRequest request,HttpServletResponse response){
//1.获取Cookie中的JT_TICKET值
Cookie[] cookies = request.getCookies();
if(cookies != null && cookies.length>0){
for (Cookie cookie : cookies){
if(cookie.getName().equals("JT_TICKET")){
String ticket = cookie.getValue();
//redis删除ticket信息
jedisCluster.del(ticket);
cookie.setMaxAge(0); //0表示立即删除
//规则cookie如果需要操作,必须严格定义
cookie.setPath("/");
cookie.setDomain("jt.com");
response.addCookie(cookie);
}
}
}
return "redirect:/";
}
4. 商品信息展现
4.1 业务需求说明
当用户点击商品时应该跳转到商品的展现页面,在页面中应该展现2部分数据.item数据/itemDesc数据. item.jsp页面
数据取值方式:
1.获取item信息 ${item.title }
2.获取ItemDesc数据 ${itemDesc.itemDesc}
4.2 重构JT-MANAGE
4.2.1 编辑ItemService
4.2.2 编辑YML配置
server:
port: 8091
servlet:
context-path: / #在根目录中发布 缺省值.
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
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
#配置manage Dubbo服务
dubbo:
scan:
basePackages: com.jt #指定dubbo的包路径
application: #应用名称
name: provider-item #一个接口对应一个服务名称
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: 20881 #每一个服务都有自己特定的端口 不能重复.
4.3 实现页面跳转
4.3.1 页面URL分析
4.3.2 编辑ItemController
package com.jt.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.pojo.Item;
import com.jt.pojo.ItemDesc;
import com.jt.service.DubboItemService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.xml.ws.RequestWrapper;
@Controller
public class ItemController {
@Reference(check = false)
private DubboItemService itemService;
/**
* 实现商品的展现
* url: http://www.jt.com/items/562379.html
* 参数: 562379商品ID号
* 返回值: item.jsp
* 页面取值: item对象/itemDesc对象
* {item.id/title}
*/
@RequestMapping("/items/{itemId}")
public String findItemById(@PathVariable Long itemId, Model model){
Item item = itemService.findItemById(itemId);
ItemDesc itemDesc = itemService.findItemDescById(itemId);
model.addAttribute("item",item);
model.addAttribute("itemDesc",itemDesc);
return "item";
}
}
4.3.3 编辑ItemService
package com.jt.web.service;
import com.alibaba.dubbo.config.annotation.Service;
import com.jt.mapper.ItemDescMapper;
import com.jt.mapper.ItemMapper;
import com.jt.pojo.Item;
import com.jt.pojo.ItemDesc;
import com.jt.service.DubboItemService;
import org.springframework.beans.factory.annotation.Autowired;
@Service(timeout = 3000)
public class DubboItemServiceImpl implements DubboItemService {
@Autowired
private ItemMapper itemMapper;
@Autowired
private ItemDescMapper itemDescMapper;
@Override
public Item findItemById(Long itemId) {
return itemMapper.selectById(itemId);
}
@Override
public ItemDesc findItemDescById(Long itemId) {
return itemDescMapper.selectById(itemId);
}
}
4.3.4 页面效果展现
5 购物车操作
5.1 业务分析
说明:当用户点击购物车按钮时,应该跳转到购物车列表页面.
页面名称: cart.jsp
页面数据: ${cartList}
5.2 创建购物Cart POJO
package com.jt.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
@TableName("tb_cart")
@Data
@Accessors(chain = true)
public class Cart extends BasePojo{
@TableId(type = IdType.AUTO) //主键自增
private Long id; //购物车Id号
private Long userId; //用户Id号
private Long itemId; //商品id号
private String itemTitle; //商品标题
private String itemImage; //商品图片信息
private Long itemPrice;
private Integer num;
}
5.3 创建JT-CART项目
5.3.1 创建项目
5.3.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">
<modelVersion>4.0.0</modelVersion>
<artifactId>jt-cart</artifactId>
<parent>
<artifactId>jt2007</artifactId>
<groupId>com.jt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<!--3.依赖工具API-->
<dependencies>
<dependency>
<groupId>com.jt</groupId>
<artifactId>jt-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<!--4.添加maven插件-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
5.3.3 购物车项目结构
6.总结
本节重点在于了解Dubbo服务在项目中的应用,熟悉器基本应用流程,重构京淘项目的业务实现架构。