分布式(十五)

1 CORS跨域

1.1 CORS跨域实现原理

说明:当下的主流的浏览器天生都支持跨域,通过添加请求头信息,将源地址进行标识,之后发往后端服务器.
在这里插入图片描述

关键点: 跨域请求由浏览器和服务器共同完成,.要求双方都必须同意跨域才行. 但是默认的条件下服务器端是不允许跨域的.所以必须经过配置才行.
在这里插入图片描述

1.2 CORS实现跨域

说明:在jt-common中添加跨域配置

//类似于web项目中使用的web.xml配置文件
@Configuration
public class CorsConfig implements WebMvcConfigurer{
	
	/**
	 * 配置后端服务器可以跨域的清单
	 * 参数说明:  addMapping:什么样的请求可以进行跨域   /web/**    /aaa/b/c/e/d/d/d
	 *          /*   匹配一级目录
	 *          /**  匹配多级目录   使用最多
	 */
	@Override
	public void addCorsMappings(CorsRegistry registry) {
		
		registry.addMapping("/**")
				.allowedOrigins("*")   //配置源 通配
				.allowedMethods("GET","POST","PUT","DELETE","HEAD") //允许的请求方式
				.allowCredentials(true)		//是否允许携带cookie
				.maxAge(1800);				//允许跨域的持续时间
	}
}

1.3 编辑ajax请求页面

	<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>测试JSON跨域问题</title>
<script type="text/javascript" src="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript">
	/*$(){}结构必然是jQuery函数类库导入后才能正确执行*/
	$(function(){			   //正常
		alert("我要进行cors的跨域了!!!!");   //正常
		//利用jQuery发起AJAX请求
		$.get("http://manage.jt.com/web/testCors",function(data){
			alert(data.id);
			alert(data.password);
		})
	})
</script>
</head>
<body>
	<h1>JSON跨域请求测试</h1>
</body>
</html>

1.4 编辑CorsController

@RestController
public class CorsController {
	
	
	@RequestMapping("/web/testCors")
	public User testUser() {
		System.out.println("我执行了业务操作!!!");
		return new User().setId(100L).setPassword("我是cors的返回值!!!!");
	}
	
}

1.5 查看响应信息

在这里插入图片描述

2 用户信息校验

2.1 业务需求

在这里插入图片描述

说明:当用户添加注册信息时,需要向JT-SSO单点登录系统进行数据的校验.如果数据库中存在/不存在都应该返回相关信息,之后页面提示信息给用户.

2.1 页面JS分析

在这里插入图片描述

注意事项: 明确url中的哪些部分一定写死在js中.之后根据检索的功能快速定位JS位置.
在这里插入图片描述

说明:配置ajax实现JSONP的请求.
在这里插入图片描述

2.2 业务接口文档

在这里插入图片描述

2.3 编辑UserController

/**
	 * 1.url:http://sso.jt.com/user/check/{param}/{type}
	 * 2.参数:param  需要校验的数据   
	 *       type   校验的类型
	 * 3.返回值结果:   SysResult对象     data:true/false
	 * 4.jsonp跨域访问
	 * 终极目标:  1.快  省  安全
	 */
	@RequestMapping("/check/{param}/{type}")
	public JSONPObject checkUser(@PathVariable String param,@PathVariable Integer type,
			String callback) {
		
		boolean flag = userService.checkUser(param,type);//要求返回true/false
		SysResult sysResult = SysResult.success(flag);
		return new JSONPObject(callback, sysResult);
	}

2.4 编辑UserService

@Service
public class UserServiceImpl implements UserService {
	
	@Autowired
	private UserMapper userMapper;
	private static Map<Integer,String> paramMap; //如果项目中固定写死的可以通过static方式维护
	
	static {
		//1.将type类型转化为具体的字段信息.
		Map<Integer,String> map = new HashMap<>();
		map.put(1, "username");
		map.put(2, "phone");
		map.put(3, "email");
		paramMap = map;
	}

	//校验数据库中是否有数据!!!  有true   没有false
	//type 1 username,  2 phone ,3 eamil 
	@Override
	public boolean checkUser(String param, Integer type) {
		//String column = type==1?"username":((type==2)?"phone":"email");
		String column = paramMap.get(type);
		//1.通过获取数据库中的记录总数,判断是否存在数据.
		QueryWrapper<User> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq(column, param);
		int count = userMapper.selectCount(queryWrapper);
		return count>0?true:false;
	}
}

2.5 页面效果

在这里插入图片描述

2.6 优化页面结构

添加状态码的判断编辑jdValidate.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.status == 200){
                    	 //返回值data.data=true 已存在/false 不存在
                        if (!data.data) {
                            validateSettings.succeed.run(option);
                            namestate = true;
                        }else {
                            validateSettings.error.run(option, "该用户名已占用!");
                            namestate = false;
                        }
                    }else{
                    	 validateSettings.error.run(option, "服务器正忙,请重试!!!");
                         namestate = false;
                    }
                   
                }
            });

2.7全局异常处理机制优化

package com.jt.aop;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import com.fasterxml.jackson.databind.util.JSONPObject;
import com.jt.vo.SysResult;

import lombok.extern.slf4j.Slf4j;

//标识改类是全局异常处理机制的配置类
@RestControllerAdvice //advice通知   返回的数据都是json串
@Slf4j	//添加日志
public class SystemExceptionAOP {
	
	/*
	 * 添加通用异常返回的方法.
	 * 底层原理:AOP的异常通知.
	 * 
	 * 常规手段:  SysResult.fail();
	 * 跨域访问:  JSONP   必须满足JSONP跨域访问要求  callback(SysResult.fail())
	 * 问题: 如何断定用户使用的是跨域方式还是普通业务调用??? 
	 * 分析: jsonp请求   get请求的方式携带?callback   
	 * 判断依据:  用户参数是否携带callback  特定参数,一般条件下不会使用
	 * */
	@ExceptionHandler({RuntimeException.class}) //拦截运行时异常
	public Object systemResultException(HttpServletRequest request,Exception exception) {
		
		String callback = request.getParameter("callback");
		if(StringUtils.isEmpty(callback)) {	//不是跨域访问
			log.error("{~~~~~~"+exception.getMessage()+"}", exception); //输出日志
			return SysResult.fail();	 //返回统一的失败数据
		}
		
		//说明:有可能跨域  jsonp只能提交GET请求
		String method = request.getMethod();
		if(!method.equalsIgnoreCase("GET")) {
			//如果不是get请求,不是jsonp请求方式
			log.error("{~~~~~~"+exception.getMessage()+"}", exception); //输出日志
			return SysResult.fail();	 //返回统一的失败数据
		}
		
		//3.如果程序执行到这里,标识进行了JSONP的请求. 按照JSONP的方式返回数据
		log.error("{~~~~~~"+exception.getMessage()+"}", exception); //输出日志
		return new JSONPObject(callback, SysResult.fail());
		
	}
}

3.HttpClient入门

3.1 HttpClient介绍

HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。虽然在 JDK 的 java net包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。HttpClient 已经应用在很多的项目中,比如 Apache Jakarta 上很著名的另外两个开源项目 Cactus 和 HTMLUnit 都使用了 HttpClient。现在HttpClient最新版本为 HttpClient 4.5 .6(2015-09-11)

3.2 场景介绍

说明:跨域的形式只能发生在有页面的web端,由浏览器解析页面JS.发起ajax请求.实现跨域.但是由于分布式的思想,后端服务器的数量众多.有时可能由A业务服务器向B业务服务器获取业务数据,但是没有页面的支持,所以不能通过跨域的形式实现.只能通过远程过程调用的方式实现数据的通信.
在这里插入图片描述

3.3 HttpClient入门案例

3.3.1 导入jar包

<!--添加httpClient jar包 -->
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpclient</artifactId>
		</dependency>

3.3.2 测试案例

package com.jt.test;

import java.io.IOException;

import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.jupiter.api.Test;

public class TestHttpClient {
	
	/**
	 * 案例说明:                           万能用法
	 * 	1.利用httpClient机制 访问百度服务器.   http://www.baidu.com
	 * 	2.实现步骤: (了解即可)
	 * 		1.定义请求网址
	 * 		2.定义httpClient工具API对象
	 * 		3.定义请求的类型
	 * 		4.发起请求,获取返回值结果
	 * 		5.校验返回值
	 * 		6.获取返回值结果数据.
	 * @throws IOException 
	 * @throws ClientProtocolException 
	 */
	@Test
	public void testGet() throws ClientProtocolException, IOException {
		String url = "http://www.baidu.com";//任意网络资源  包裹业务服务器.
		CloseableHttpClient httpClient = HttpClients.createDefault();
		HttpGet httpGet = new HttpGet(url);
		CloseableHttpResponse response = httpClient.execute(httpGet);//不能保证网络请求一定正确.
		//发起请求之后 需要判断返回值结果是否正确  一般条件下判断响应状态码信息是否为200.
		//404 400 提交参数异常  406 接收参数异常 500 服务器异常  504  超时   200正常 
		int status = response.getStatusLine().getStatusCode();
		if(status == 200) {
			//说明请求正确  获取返回值的实体对象
			HttpEntity httpEntity = response.getEntity();
			//将远程服务器返回的信息,转化为字符串. 方便调用   1.json   2.html代码片段
			String result = EntityUtils.toString(httpEntity,"utf-8");
			System.out.println(result);
		}
	}
	
}

3.3.3 HttpClient与跨域的区别

在这里插入图片描述

4.Dubbo

4.1 SOA思想(架构设计思想)

面向服务的架构(SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)进行拆分,并通过这些服务之间定义良好的接口和协议联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构件在各种各样的系统中的服务可以以一种统一和通用的方式进行交互。

在这里插入图片描述

4.2 RPC思想

4.2.1 漫话RPC

一个阳光明媚的早晨,老婆又在翻看我订阅的技术杂志。
“老公,什么是RPC呀,为什么你们程序员那么多黑话!”,老婆还是一如既往的好奇。
“RPC,就是Remote Procedure Call的简称呀,翻译成中文就是远程过程调用嘛”,我一边看着书,一边漫不经心的回答着。
“啥?你在说啥?谁不知道翻译成中文是什么意思?你个废柴,快给我滚去洗碗!”
“我去。。。”,我如梦初醒,我对面坐着的可不是一个程序员,为了不去洗碗,我瞬间调动起全部脑细胞,星辰大海在我脑中汇聚,灵感涌现…
“是这样,远程过程调用,自然是相对于本地过程调用来说的嘛。”
“嗯哼,那先给老娘讲讲,本地过程调用是啥子?”
“本地过程调用,就好比你现在在家里,你要想洗碗,那你直接把碗放进洗碗机,打开洗碗机开关就可以洗了。这就叫本地过程调用。”
“哎呦,我可不干,那啥是远程过程调用?”
“远程嘛,那就是你现在不在家,跟姐妹们浪去了,突然发现碗还没洗,打了个电话过来,叫我去洗碗,这就是远程过程调用啦”,多么通俗易懂的解释,我真是天才!

“哦!我明白了”,说着,老婆开始收拾包包。
“你这是干啥去哦”
“我?我要出门浪去呀,待会记得接收我的远程调用哦,哦不,咱们要专业点,应该说,待会记得接收我的RPC哦!”

4.2.2 什么是RPC

RPC是远程过程调用(Remote Procedure Call)的缩写形式。SAP系统RPC调用的原理其实很简单,有一些类似于三层构架的C/S系统,第三方的客户程序通过接口调用SAP内部的标准或自定义函数,获得函数返回的数据进行处理后显示或打印。
总结: 需要调用第三方完成本地的服务.

4.3 Dubbo框架介绍

Apache Dubbo |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:
1.面向接口的远程方法调用,
2.智能容错和负载均衡
3.服务自动注册和发现。

4.4 Dubbo框架工作原理

在这里插入图片描述

组件说明:
1.消费者 负责接收用户的请求信息的. 页面
2.提供者 主要负责实现业务接口.
3.注册中心 注册中心基于心跳检测机制.可以非常灵活的检查服务是否可用.及服务自动的注册和发现功能.
4.监控 监控整合dubbo框架内部的状态信息.

4.5 注册中心工作原理(重点)

在这里插入图片描述

步骤:
1.当服务提供者启动时,将自己的IP地址/端口号/服务数据一起注册到注册中心中.
2.当注册中心接收提供者的数据信息之后,会维护服务列表数据.
3.当消费者启动时,会连接注册中心.
4.获取服务列表数据.之后在本地保存记录.
5.当用户需要业务操作时,消费者会根据服务列表数据,之后找到正确的IP:PORT直接利用RPC机制进行远程访问.
6.注册中心都有心跳检测机制.当发现服务器宕机/或者新增服务时.则会在第一时间更新自己的服务列表数据,并且全网广播通知所有的消费者.

4.6 安装注册中心-zookeeper

4.6.1 ZK下载

在这里插入图片描述

4.6.2 ZK介绍

ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
ZooKeeper包含一个简单的原语集,提供Java和C的接口。
ZooKeeper代码版本中,提供了分布式独享锁、选举、队列的接口,代码在$zookeeper_home\src\recipes。其中分布锁和队列有Java和C两个版本,选举只有Java版本。(概述图片来源: [1] )
总结: ZooKeeper是分布式 应用程序服务的调度器.

作业
1.完成zk集群搭建
2.预习dubbo入门案例
修改代码: 将dubbo-jt中的pom.xml文件进行修改
在这里插入图片描述

在这里插入图片描述

导入效果:
在这里插入图片描述

©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页