1.用户数据校验
1.1 构建JT_SSO
1.1.1 创建项目
1.1.2 编辑POM.xml文件
<?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">
<!--1.添加继承-->
<parent>
<artifactId>jt</artifactId>
<groupId>com.jt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jt_sso</artifactId>
<!--默认不写 就是jar包-->
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<!--2.添加依赖-->
<dependencies>
<dependency>
<groupId>com.jt</groupId>
<artifactId>jt_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<!--3.添加插件-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
1.1.3 编辑User pojo文件
1).表设计
2).编辑User POJO
在jt-common中添加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;
@Data
@Accessors(chain = true)
@TableName("tb_user")
//8091 8092 8093 查询所有用户的列表信息JSON返回
//http://sso.jt.com/findAll
public class User extends BasePojo{
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String password; //采用MD5方式加密
private String phone;
private String email; //暂时使用电话号码代替
}
1.1.4 编辑JT_SSO项目
通过http://sso.jt.com/findAll的方式访问
1).代码结构
2)创建主启动类
package com.jt;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.jt.mapper")
public class SpringBootRun {
public static void main(String[] args) {
SpringApplication.run(SpringBootRun.class, args);
}
}
3)创建mapper层
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
4)创建service层
public interface UserService {
List<User> findAll();
}
实现类
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public List<User> findAll() {
return userMapper.selectList(null);
}
}
5)controller控制层
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/findAll")
public List<User> findAll(){
return userService.findAll();
}
}
6)创建yaml配置端口
server:
port: 8093
servlet:
context-path: /
spring:
datasource:
#引入druid数据源,type切换数据源
# 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:
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
7)配置启动类
1.1.5 编辑nginx配置文件
# 京淘前台管理系统
server {
listen 80;
server_name sso.jt.com;
location / {
proxy_pass http://localhost:8093;
}
}
运行测试:
1.2 用户数据校验实现
1.2.1 页面分析
说明: 当用户输入用户名时,校验用户是否存在,发起跨域请求。
1.2.2 页面JS
1).检索JS
2).页面JS
$.ajax({
url : "http://sso.jt.com/user/check/"+escape(pin)+"/1?r=" + Math.random(),
dataType : "jsonp",
success : function(data) {
checkpin = data.data?"1":"0";
if (!data.data) {
validateSettings.succeed.run(option);
namestate = true;
}else {
validateSettings.error.run(option, "该用户名已占用!");
namestate = false;
}
}
});
1.2.3 接口文档分析
1.2.4 编辑JT-SSO UserController
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/findAll")
public List<User> findAll(){
return userService.findAll();
}
/***
* 实现用户数据校验
* 1.URL地址: http://sso.jt.com/user/check/admin123/1?r=0.1845737292036227&callback=jsonp1616466201812&_=1616466206686
* 2. 参数: /admin123/1
* 3.返回值结果 SysResult对象
* data: false //返回数据true用户已存在,false用户不存在,可以
* 4.JSONP方式说明: 返回值有特殊要求 callback(json)
*/
@RequestMapping("/check/{param}/{type}")
public JSONPObject checkUser(@PathVariable String param, @PathVariable Integer type, String callback){
//只讨论数据是否存在.
int count = userService.checkUser(param,type);//查询记录总数
boolean flag = count > 0; //存在大于0为true,否则为flase
//返回值有特殊要求 callback(json)
return new JSONPObject(callback, SysResult.success(flag));
}
}
1.2.5 编辑JT-SSO UserService
@Service
public class UserServiceImpl implements UserService {
//该类数据只取不改
private static Map<Integer,String> paramMap = new HashMap<>();
static {
paramMap.put(1, "username");
paramMap.put(2, "phone");
paramMap.put(3, "email");
}
@Autowired
private UserMapper userMapper;
@Override
public List<User> findAll() {
return userMapper.selectList(null);
}
//1 username、2 phone、3 email
@Override
public int checkUser(String param, Integer type) {
QueryWrapper queryWrapper = new QueryWrapper();
//动态获取校验的数据类型
queryWrapper.eq(paramMap.get(type), param);
//查询数据总数
return userMapper.selectCount(queryWrapper);
}
}
运行测试:
1.3 全局异常处理
1.3.1 编辑页面JS
$.ajax({
url : "http://sso.jt.com/user/check/"+escape(pin)+"/1?r=" + Math.random(),
dataType : "jsonp",
success : function(data) {
if (data.status == 200) {
if (!data.data) {
validateSettings.succeed.run(option);
namestate = true;
} else {
validateSettings.error.run(option, "该用户名已占用!");
namestate = false;
}
}else {
validateSettings.error.run(option, "请稍后重试!");
namestate = false;
}
}
});
1.3.2 编辑全局异常处理
package com.jt.aop;
import com.fasterxml.jackson.databind.util.JSONPObject;
import com.jt.vo.SysResult;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import java.sql.SQLException;
//spring中的通知 核心原理:Spring AOP机制
@RestControllerAdvice //只对Controller代码层级有效.
public class SysResultException {
//当程序发生异常时, 如果没有try-catch则直接向上抛出异常.
//该注解只拦截运行时异常.
//经过测试发现jsonp的请求会携带callback参数 如果有callback参数则认为是JSONP请求
//如何获取callback参数
@ExceptionHandler({RuntimeException.class})
public Object exception(Exception e, HttpServletRequest request){
//错误日志
e.printStackTrace();
//callback接收获取的参数
String callback = request.getParameter("callback");
//StringUtils,是spring包底下控制字符串的APi
if(StringUtils.hasLength(callback)){//判断是否有值
//JSONPObject同一类型返回
return new JSONPObject(callback, SysResult.fail());
}
return SysResult.fail();
}
}
2 HttpClient方式
2.1 关于跨域说明
一般的情况下 采用跨域一般处理一些简单的数据.对于安全性要求不是特别的高. 并且业务相对简单.如果有需求对安全性及业务要求严格,则使用跨域的方式则不能满足用户的需求.则应该采用HttpClient(微服务底层实现)方式实现远程数据访问.
2.2 HttpClient介绍
HttpClient 是Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。
HTTP 协议是 Internet 上使用得最多、最重要的协议之一,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。虽然在 JDK 的 java net包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。HttpClient 已经应用在很多的项目中,比如 Apache Jakarta 上很著名的另外两个开源项目 Cactus 和 HTMLUnit 都使用了 HttpClient。Commons HttpClient项目现已终止,不再开发。 它已被Apache HttpComponents项目里的HttpClient和HttpCore模块取代,它们提供了更好的性能和更大的灵活性。
2.3 HttpClient入门
2.3.1 导入jar包
<!--添加httpClient jar包 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
2.3.2 编辑入门案例
package com.jt.httpClient;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.jupiter.api.Test;
import java.io.IOException;
public class TestHttpClient {
@Test
public void testGet() throws IOException {
//1.实例化对象
HttpClient httpClient = HttpClients.createDefault();
//2.定义请求网址
String url = "http://www.baidu.com"; //html代码
//3.定义请求方式
HttpGet get = new HttpGet(url);//get请求
//4.发送请求
HttpResponse httpResponse = httpClient.execute(get);//无法保证请求一定正确
//5.判断状态码
int status = httpResponse.getStatusLine().getStatusCode();//getStatusLine状态量,getStatusCode状态码
if(status == 200) {
//6.获取数据
HttpEntity httpEntity = httpResponse.getEntity();//getEntity 实体对象
//转换实体对象
String html = EntityUtils.toString(httpEntity, "UTF-8");
//输出html
System.out.println(html);
}
}
}
2.4 SOA
2.4.1 SOA介绍
面向服务的架构(SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)进行拆分,并通过这些服务之间定义良好的接口和协议联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构建在各种各样的系统中的服务可以以一种统一和通用的方式进行交互。
个人理解:它就是一种开发的编码规范,一种架构的设计模型,翻译过来就是面向服务的架构
2.4.2 RPC(思想)
RPC是远程过程调用(Remote Procedure Call)的缩写形式。
参考:如何给老婆解释什么是RPC:https://www.jianshu.com/p/2accc2840a1b
-
问题1: 什么是本地过程调用?
不需要经过第三方,自己调用方法实行功能。 -
问题2: 什么是远程过程调用?
自己需要完成一项业务,但是由于诸多原因 自己不能直接调用,则通过第三方访问的业务调用称之为RPC。(代理)
总结:
1.解决分布式系统中,服务之间的调用问题。
2.远程调用时,要能够像本地调用一样方便,让调用者感知不到远程调用的逻辑(代理)。
3 Dubbo框架
3.1 官网介绍
Apache Dubbo |ˈdʌbəʊ| 提供了六大核心能力:面向接口代理的高性能RPC调用,智能容错和负载均衡,服务自动注册和发现,高度可扩展能力,运行期流量调度,可视化的服务治理与运维。
官网:https://dubbo.apache.org/zh/
3.2 微服务调用核心机制
3.2.1 现阶段架构设计问题
3.2.2 服务自动注册/发现
步骤:
1.当生产者启动时,会将服务信息(服务名称/服务IP:PORT) 写入到注册中心。
2.注册中心会动态维护服务列表,定期刷新。
3.消费者启动时链接注册中心,获取最新的服务列表数据,之后缓存到本地方便下次调用。
4.当用户开始访问消费者时,消费者查询本地的服务列表进行负载均衡,访问其中一个生产者获取数据。
5.注册中心通过心跳检测机制,访问生产者,当生产者宕机,则第一时间更新自己的服务列表,并且全网广播,通知所有的消费者更新列表数据。
3.3 Zookeeper注册中心安装
具体安装步骤,参考文章:https://blog.csdn.net/QQ1043051018/article/details/115511389
3.4 关于集群知识点说明
3.4.1 为什么集群最小单位3台
集群正常工作的公式: 存活的节点数量 > N/2
讨论:
1个节点 1-1 > 1/2 :不满足 1个节点不能搭建集群
2个节点 2-1 > 2/2 :不满足 2个节点不能搭建集群
3个节点 3-1 > 3/2 : 满足 3个节点是搭建集群最小单位
3.4.2 为什么集群一般都是奇数台?
从容灾性的角度考虑问题:
3台服务器 3-1 > 3/2 :宕机1台集群可以工作
4台服务器 4-1 > 4/2 :宕机1台集群可以工作
说明: 由于奇数和偶数容灾性一样的,所以搭建奇数台更加合理。
3.5 ZK选举规则
说明:
- 1.myid的最大值优先.
- 2.超半数同意 当选主机.
案例1: 依次启动zk1,zk2,zk3 3台服务器。
1).谁当主机? 2
案例2: 依次启动zk1-zk7
1).谁当主机? 4
2).谁永远当选不了主机 1 2 3
3.6 导入Dubbo入门案例
3.6.1 修改版本号
3.6.2 修改依赖项
3.6.3 导入项目
等待依赖下载完成