1 CORS跨域
1.1原理
说明:当下的主流的浏览器天生都支持跨域,通过添加请求头信息,将源地址进行标识,之后发往后端服务器.
关键点: 跨域请求由浏览器和服务器共同完成,.要求双方都必须同意跨域才行. 但是默认的条件下服务器端是不允许跨域的.所以必须经过配置才行.
1.2 CORS实现跨域
1.2.1在jt-common中添加跨域配置
package com.jt.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer{//类似于web项目中的web.xml配置文件
/**
* 配置后端服务器可以跨域的清单
* 参数说明: addMapping:什么样的请求可以进行跨域 /web/** /aaa/*
* /* 匹配一级目录
* /** 匹配多级目录 使用最多
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*") //http://www.jt.com配置源
.allowedMethods("GET","POST","PUT","DELETE","HEAD") //运行请求方式
.allowCredentials(true) //是否允许携带Cookie
.maxAge(1800); //允许跨域持续时间
}
}
1.2.2 编辑jt-web中的test.html页面
<!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("我执行了AJAX");
alert("我要进行cors的跨域了!!!!"); //正常
//利用jQuery发起AJAX请求
//$.get("http://manage.jt.com/test.json",function(data){
$.get("http://manage.jt.com/web/testCors",function(data){
alert(data.id);
alert(data.password);
//alert(data.name);
})
})
</script>
</head>
<body>
<h1>JSON跨域请求测试</h1>
</body>
</html>
1.2.3在jt-manage
package com.jt.web.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.jt.pojo.User;
@RestController
public class corsController {
@RequestMapping("/web/testCors")
public User testCors(String callback) {
//准备返回数据
//User user =new User();
//user.setId(100L).setPassword("我是cors");
return new User().setId(100L).setPassword("我是cors");
}
}
1.2.4查看响应信息
1.3用户注册信息校验
1.3.1业务需求
说明:当用户添加注册信息时,需要向JT-SSO单点登录系统进行数据的校验.如果数据库中存在/不存在都应该返回相关信息,之后页面提示信息给用户.
注意事项: 明确url中的哪些部分一定写死在js中.之后根据检索的功能快速定位JS位置.
说明:配置ajax实现JSONP的请求.
1.3.2业务接口文档
1.3.3编辑UserController
package com.jt.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.util.JSONPObject;
import com.jt.service.UserService;
import com.jt.vo.SysResult;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/getMsg")
public String getMsg() {
return "单点登录";
}
/**
* 1.url:http://sso.jt.com/user/check/{param}/{type}
* 2.参数: param 需要校验的数据
* type 校验的类型
* 3.返回值结果 SysResult date:true/false
* 4.jsomp跨域访问
* 终极目标: 快 省 安全
*/
@RequestMapping("check/{param}/{type}")
public JSONPObject check(@PathVariable String param,@PathVariable Integer type,String callback) {
Boolean flag =userService.checkUser(param,type);
SysResult sysResult=SysResult.success(flag);
return new JSONPObject(callback,sysResult); //经过视图解析器
}
}
1.3.4编辑UserService
package com.jt.service;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
private static Map<Integer,String> paramMap;
static {
//2.将type类型转化为具体字段信息
Map<Integer,String> map =new HashMap<>();
map.put(1, "username");
map.put(2, "phone");
map.put(3, "eamil");
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 colum=paramMap.get(type);
//1.通过获取数据库中记录的总数,判断是否存在数据.
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(colum, param);
int count =userMapper.selectCount(queryWrapper);
return count>0?true:false;
}
}
效果
1.4优化页面结构
/jt-web/src/main/webapp/js/register/jdValidate.js
599行
$.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;
}
}
});
1.5全局异常处理机制优化
package com.jt.aop;
import javax.servlet.http.HttpServletRequest;
import org.springframework.util.StringUtils;
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-->通知 Rest-->返回的数据都是json串
@Slf4j //添加日志
public class SystemExceptionAOP {
/*
* 添加通用的异常返回的方法
* 底层原理:AOP的异常通知
*/
@ExceptionHandler(RuntimeException.class) //拦截运行时异常
public Object systemResultException(HttpServletRequest request,Exception e) {
String callback =request.getParameter("callback");
if(StringUtils.isEmpty(callback)) { //不是跨域访问
log.error("{~~~业务调用异常~~~}"+e.getMessage(),e); //输出日志
return SysResult.fail(); //返回统一的失败数据
}
//说明:有可能跨域 jsonp只能提交get请求
String method =request.getMethod();
if(!method.equalsIgnoreCase("GET")) {
log.error("{~~~业务调用异常~~~}"+e.getMessage(),e); //输出日志
return SysResult.fail(); //返回统一的失败数据
}
//3.如果程序执行到这里,标识进行了jsonp的请求,按照jsonp方法处理
log.error("{~~~业务调用异常~~~}"+e.getMessage(),e); //输出日志
return new JSONPObject(callback, SysResult.fail());
// e.printStackTrace(); //如果有问题,则直接在控制台打印
// log.error("{~~~业务调用异常~~~}"+e.getMessage(),e); //输出日志
// return SysResult.fail(); //返回统一的失败数据
}
}
2.HttpClient入门
2.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)
2.2 场景介绍
说明:跨域的形式只能发生在有页面的web端,由浏览器解析页面JS.发起ajax请求.实现跨域.但是由于分布式的思想,后端服务器的数量众多.有时可能由A业务服务器向B业务服务器获取业务数据,但是没有页面的支持,所以不能通过跨域的形式实现.只能通过远程过程调用的方式实现数据的通信.
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.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 TsetHttpClient {
/**
* 1.利用HttpClient机制 访问百度服务器.. http://www.baidu.com
* 2.实现步骤:
* a.定义请求网址
* b.定义HttpClient工具API对象
* c.定义请求的类型
* d.发起请求,获取返回值结果
* e.校验返回值
* f.获取返回值结果
* @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就是正确
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);
}
}
}
访问http://manage.jt.com/web/testCors
@Test
public void testGet() throws ClientProtocolException, IOException {
// String url="http://www.baidu.com"; //任意网络资源
String url="http://manage.jt.com/web/testCors";
CloseableHttpClient httpClient=HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url); //说明请求用说明接收方法
CloseableHttpResponse response=httpClient.execute(httpGet);
//发起请求之后要判断返回值结果知否正确 一般条件下状态码信息为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);//字符串
//将字符串转化Object
User user =ObjectMapperUtil.toObject(result, User.class);
System.out.println(user);
}
}
2.4入门
sso-controller
/**
* "http://sso.jt.com/user/findUserById/"+userId
*/
@RequestMapping("findUserById/{userId}")
public User findUserById(@PathVariable Long userId){
return userService.findUserById(userId);
}
sso-service
@Override
public User findUserById(Long userId) {
return userMapper.selectById(userId);
}
web-controller
/**
* 为了实现业务功能用户信息查询
*
*/
@RequestMapping("findUserById/{userId}")
@ResponseBody
public User findUserById(@PathVariable Long userId){
return userService.findUserById(userId);
}
web-service
package com.jt.service;
import com.jt.pojo.User;
import com.jt.util.ObjectMapperUtil;
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.springframework.stereotype.Service;
import java.io.IOException;
@Service
public class UserServiceImpl implements UserService{
@Override
public User findUserById(Long userId) {
String url="http://sso.jt.com/user/findUserById/"+userId;
HttpClient httpClient= HttpClients.createDefault();
HttpGet httpGet= new HttpGet(url);
try {
HttpResponse httpResponse = httpClient.execute(httpGet);
if (httpResponse.getStatusLine().getStatusCode()==200){
HttpEntity httpEntity = httpResponse.getEntity();
String result = EntityUtils.toString(httpEntity, "UTF-8");
return ObjectMapperUtil.toObject(result,User.class);
}else {
throw new RuntimeException("请求失败,看看你的地址有木有问题");
}
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
3.Dubbo
3.1 SOA思想
面向服务的架构(SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)进行拆分,并通过这些服务之间定义良好的接口和协议联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构件在各种各样的系统中的服务可以以一种统一和通用的方式进行交互。
3.2 RPC
RPC是远程过程调用(Remote Procedure Call)的缩写形式。SAP系统RPC调用的原理其实很简单,有一些类似于三层构架的C/S系统,第三方的客户程序通过接口调用SAP内部的标准或自定义函数,获得函数返回的数据进行处理后显示或打印。
总结: 需要调用第三方完成本地的服务.
RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务
本地过程调用:如果需要将本地student对象的age+1,可以实现一个addAge()方法,将student对象传入,对年龄进行更新之后返回即可,本地方法调用的函数体通过函数指针来指定。
远程过程调用:上述操作的过程中,如果addAge()这个方法在服务端,执行函数的函数体在远程机器上,如何告诉机器需要调用这个方法呢?
3.3 Dubbo框架介绍
Apache Dubbo |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:
1.面向接口的远程方法调用,
2.智能容错和负载均衡
3.服务自动注册和发现。
3.4 Dubbo框架工作原理
组件说明:
1.消费者 负责接收用户的请求信息的. 页面
2.提供者 主要负责实现业务接口.
3.注册中心 注册中心基于心跳检测机制.可以非常灵活的检查服务是否可用.及服务自动的注册和发现功能.
4.监控 监控整合dubbo框架内部的状态信息
3.5 注册中心工作原理(重点)
步骤:
1.当服务提供者启动时,将自己的IP地址/端口号/服务数据一起注册到注册中心中.
2.当注册中心接收提供者的数据信息之后,会维护服务列表数据.
3.当消费者启动时,会连接注册中心.
4.获取服务列表数据.之后在本地保存记录.
5.当用户需要业务操作时,消费者会根据服务列表数据,之后找到正确的IP:PORT直接利用RPC机制进行远程访问.
6.注册中心都有心跳检测机制.当发现服务器宕机/或者新增服务时.则会在第一时间更新自己的服务列表数据,并且全网广播通知所有的消费者.
4 ZK介绍
安装教程
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
ZooKeeper包含一个简单的原语集,提供Java和C的接口。
ZooKeeper代码版本中,提供了分布式独享锁、选举、队列的接口,代码在$zookeeper_home\src\recipes。其中分布锁和队列有Java和C两个版本,选举只有Java版本。(概述图片来源: [1] )
总结: ZooKeeper是分布式 应用程序服务的调度器