78--JT项目16(CORS跨域/HttpCLient/jt-sso单点登录)

1 关于JSONP知识说明

1.1 JSONP工具API说明

1.1.1 JSONP页面说明

$.ajax({
    url:"http://manager.jt.com/web/testJSONP",
    type:"get",				//jsonp只能支持get请求   src只能进行get请求.
    dataType:"jsonp",       //dataType表示返回值类型 必须标识
    //jsonp: "callback",    //指定参数名称
    jsonpCallback: "hello",  //指定回调函数名称
    success:function (data){   //data经过jQuery封装返回就是json串
        alert(data.itemId);
        alert(data.itemDesc);
    }
});	

1.1.2 Ajax请求方式

在这里插入图片描述

1.1.3 服务器处理跨域请求

package com.jt.web.controller;

import com.fasterxml.jackson.databind.util.JSONPObject;
import com.jt.pojo.ItemDesc;
import com.jt.unit.ObjectMapperUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController     //json字符串
public class JSONPController {
    /**
     * 完成JSONP的调用
     * url:http://manager.jt.com/web/testJSONP?callback=jQuery111101021758391465013_1597656788213&_=1597656788214
     * 规定:返回值结果,必须经过特殊的格式封装.callback(json)
     */
    @RequestMapping("/web/testJSONP")
    public JSONPObject jsonp(String callback){
        ItemDesc itemDesc = new ItemDesc();
        itemDesc.setItemId(101L).setItemDesc("我是商品详情信息");
        return new JSONPObject(callback, itemDesc);
    }
   /* public String  jsonp(String callback){
        ItemDesc itemDesc = new ItemDesc();
        itemDesc.setItemId(101L).setItemDesc("我是商品详情信息");
        String json = ObjectMapperUtil.toJSON(itemDesc);
        //return callback+"({'id':'100','name':'tomcat猫'})";
        return callback +"("+json+")";
    }*/
}

2. CORS跨域访问说明

2.1CORS说明

CORS,全称Cross-Origin Resource Sharing [1] ,是一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制,通常由于同域安全策略(the same-origin security policy)浏览器会禁止这种跨域请求。
知识回顾:
JSONP: 用户利用jsonp向服务器端动态获取数据的过程. 主体用户.
CORS: 服务器是否允许客户端访问的技术. 主体服务器.

2.2 CORS原理说明

​ 用户可以像普通的ajax请求一样发起跨域请求. get/post/put/delete,由于当下的跨域的业务比较常见,所有的主流的浏览器默认支持跨域. CORS核心需要配置服务器端是否允许跨域.

2.2.1 常规ajax跨域请求

1).页面标识

<script type="text/javascript">
	/*$(){}结构必然是jQuery函数类库导入后才能正确执行*/
	$(function(){
		alert("我执行了AJAX");
		$.get("http://manager.jt.com/test.json",function(data){
			alert(data.name);
		})
	})
</script>

2).页面报错信息. 表示服务器端暂时不允许跨域.

在这里插入图片描述

2.3 服务器实现CORS跨域

说明: 服务器端如果需要实现CORS跨域请求,则需要在服务器端标识允许跨域的网址即可.

2.3.1 编辑页面实现跨域请求

编辑jt-web 中的test.html页面信息.

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

2).编辑json数据

在这里插入图片描述

2.3.2 编辑CORS跨域

说明:为了以后能够实现通用,则在jt-common中添加cors操作.

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 {

    //扩展跨域请求的方法
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 1 运行什么样的请求进行跨域
         // /* 只允许一级目录的请求 /** 表示多级的目录可以请求访问
        registry.addMapping("/**")
                .allowedOrigins("*") //允许哪些服务进行跨域
                .allowCredentials(true)//表示是否可以携带cookie进行跨域
                .allowedMethods("GET","POST","PUT","DELETE","HEAD") //可以允许访问的请求方式
                .maxAge(1800);//定义探针的检测时间 在规定的时间内不再询问是否允许跨域
    }
}

2.3.3 编辑CORS流程图

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

在这里插入图片描述

2.3.4 CORS跨域响应信息.

在这里插入图片描述

3. 构建JT-SSO后台服务器

3.1 项目说明

说明: JT-SSO主要负责用户的单点登录操作.及用户数据认证的业务.由于不需要页面的支持,所以JT-SSO 打 jar包即可.

3.2 创建项目

3.2.1 创建jt-sso项目

在这里插入图片描述

3.2.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">
    <parent>
        <artifactId>jt</artifactId>
        <groupId>com.jt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <!-- 打jar包-->
    <packaging>jar</packaging>

    <artifactId>jt-sso</artifactId>
    <!--添加依赖-->
    <dependencies>
        <dependency>
            <groupId>com.jt</groupId>
            <artifactId>jt-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>
    <!-- 插件 用来打包-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3.2.3 编辑User的POJO对象

说明:构建POJO对象在jt-common项目中

package com.jt.pojo;


import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@TableName("tb_user")
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class User  extends  BasePojo{
    @TableId(type = IdType.AUTO)
    private Long id;
    private String username;
    private String password;
    private  String phone;
    private String email;

}

3.2.4 构建代码层级结构

在这里插入图片描述

3.2.5 编辑UserController 编辑测试方法

在jt-sso项目中进行项目测试

package com.jt.controller;

import com.fasterxml.jackson.databind.util.JSONPObject;
import com.jt.pojo.User;
import com.jt.service.UserService;
import com.jt.vo.SysResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
//服务端要求返回的数据都是json
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    @RequestMapping("/getMsg")
    public String getMsg(){
        return  "单点登录测试";
    }
}

3.2.6编辑Hosts文件

在host文件中,添加 127.0.0.1 sso.jt.com

3.2.7 编辑nginx配置文件

,在nginx文件中添加sso.jt.com的反向代理设置修改nginx之后重启服务器.

# 配置前台服务器
	server {
		listen 80;
		server_name  sso.jt.com;

		location / {
			proxy_pass http://localhost:8093;
		}
	}

3.2.8.访问测试效果

访问路径:http://sso.jt.com/getMsg

测试结果: 单点登录测试

3.3 完成用户信息校验

3.3.1 检查URL请求路径

在这里插入图片描述

3.3.2 检查JS

1).检索项目中的代码.

image-20200818205154642

2).检查用户JSONP跨域请求

在这里插入图片描述

3.3.3 接口文档说明

在这里插入图片描述

3.3.4 编辑jt-sso UserController

package com.jt.controller;

import com.fasterxml.jackson.databind.util.JSONPObject;
import com.jt.pojo.User;
import com.jt.service.UserService;
import com.jt.vo.SysResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
//服务端要求返回的数据都是json
@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.请求参数 {需要校验的数据}/{校验类型}
     *  3. 返回结果 SysResult返回 需要包含true/false
     *  4. JSONP请求方式,返回值类型必须经过特殊格式的封装 callback(json)
     */
    @RequestMapping("/check/{param}/{type}")
    public JSONPObject checkUser(@PathVariable("param") String param , @PathVariable("type") Integer type, String callback) {
        boolean flag = userService.checkUser(param,type);//存在true  不存在false
       // int a =1/0;
        return  new JSONPObject(callback, SysResult.success(flag));
    }
}

3.3.5 编辑jt-sso UserService

package com.jt.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class UserServiceImpl implements  UserService{
    private String column = null;
    //采用工具API形式动态获取
    private static Map<Integer,String> typeMap = new HashMap<>();
    static {//类加载的时候就开始执行,只执行一次
        typeMap.put(1,"username");
        typeMap.put(2,"phone");
        typeMap.put(3,"email");
    }
    @Autowired
    private UserMapper userMapper;
    //数据校验
    @Override
    public boolean checkUser(String param, Integer type) {
         //1.根据参数类型获取校验的类型 column
        column = typeMap.get(type);
//        String column = type==1?"username":(type==2?"phone":"email");
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
        queryWrapper.eq(column,param);
        int count = userMapper.selectCount(queryWrapper);
        return  count>0? true:false; //如果返回true,表示已经存在,如果返回false,表示可以使用

    }
}

3.3.6 页面效果展现

在这里插入图片描述

3.3.7 全局异常处理机制

因为使用JSONP后,需要对异常信息进行特殊格式的封装,所以需要重构全局异常处理机制

package com.jt.aop;

import com.fasterxml.jackson.databind.util.JSONPObject;
import com.jt.vo.SysResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;

@Slf4j
@RestControllerAdvice //定义异常处理的通知 只拦截controller层抛出的异常
public class SysExceptionAOP {
    /**
     *  如果跨域访问发生了异常,返回结果必须要进行特殊格式的处理
     *  如果是跨域的访问形式,全局的异常处理可以正确的返回结果
     *  callback(json)
     *
     *  思路: 判断用户提交的参数中是否有callback参数
     * @param exception
     * @return
     */
    @ExceptionHandler(RuntimeException.class)
    public Object systemResultException(Exception exception, HttpServletRequest request){

        //获取用户请求的参数
        String callback = request.getParameter("callback");
        //判断是否为跨域
        if (StringUtils.isEmpty(callback)){
            //用户请求不是jsonp跨域访问形式
            exception.printStackTrace();
            log.error("{~~~~~"+exception.getMessage()+"}",exception);
            return  SysResult.fail();

        }else {
            //jsonp的报错信息.
            exception.printStackTrace();
            return  new JSONPObject(callback,  SysResult.fail());
        }


    }
}

3.3.8 重构页面JS

src\main\webapp\js\register\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";
                    //判断jsonp校验是否正确
                    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;
                    }
                }
            });

image-20200818210011675

4. HttpClient

4.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)
SpringCloud框架中实现远程数据访问底层实现就是httpClient.
httpClient作用: 在java代码内部发起http请求.

4.2 HttpClient入门案例

4.2.1 引入httpClient工具包

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

4.2.2 HttpClient入门案例

package com.jt;

import org.apache.http.HttpEntity;
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;

import java.io.IOException;

public class TestHttpClient {

        /**
     * 业务需求:在java代码中访问百度的页面
     * url: http://news.sohu.com    html代码片段
     * 实现步骤:
     *      1. 获取httpClient对象
     *      2. 自定义url地址
     *      3. 定义请求类型
     *      4. 发起请求 获取响应结果.
     *      5. 校验返回值状态,是否正确
     *      6. 获取返回值信息,之后完成后续业务处理.
     *      SDK......
     * */
 
    @Test
    public void test01()  {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        String url = "http://news.sohu.com";
        HttpGet get = new HttpGet(url);
        try {
            CloseableHttpResponse response = httpClient.execute(get);
            //获取返回值状态
            int status = response.getStatusLine().getStatusCode();
            if (status==200){
                //获取响应结果
                HttpEntity entity = response.getEntity();//获取响应对象的实体信息
                //将实体对象转化为用户可以识别的字符串
                String result = EntityUtils.toString(entity,"UTF-8");
                System.out.println(result);

            }else {
                System.out.println("httpClient调用异常");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4.3 HttpClient高级案例

4.3.1 业务说明

用户通过 http://www.jt.com/user/httpClient/saveUser/{username}/{password} 访问服务器.要求利用httpClient技术将用户信息保存到jt-sso中.
发送url请求路径: http://sso.jt.com/user/httpClient/saveUser?username=xxxx&password=xxxx
实现数据传递.
在jt-sso中完成数据入库操作.

image-20200818210916446

4.3.2 编辑jt-web Controller

package com.jt.controller;

import com.jt.pojo.User;
import com.jt.service.HttpClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HttpClientController {
    @Autowired
    private HttpClientService httpClientService;

    /**
     * 用户测试路径:
     * http://www.jt.com/user/httpClient/saveUser/admin123456/123456789
     * 将数据传递给sso.jt.com
     * return "用户请求成功"
     */
    @RequestMapping("/user/httpClient/saveUser/{username}/{password}")
    public String saveUser(User user){//参数接收与对象的属性必须保持一致.可以自动赋值springmvc
        httpClientService.saveUser(user);
        return  "httpClient测试成功";
    }
}

4.3.2 编辑jt-web Service

package com.jt.service;

import com.jt.pojo.User;
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.springframework.stereotype.Service;

import java.io.IOException;

@Service
public class HttpClientServiceImpl implements  HttpClientService{
    /**
     * http://sso.jt.com/user/httpClient/saveUser?
     * @param user
     */
    //位置jt-web 不能直接链接数据库 需要将数据传递给sso.jt.com
    @Override
    public void saveUser(User user) {
		//定义url
        String url ="http://sso.jt.com/user/httpClient/saveUser?username="
                +user.getUsername()+"&password="+user.getPassword();
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //请求方式
        HttpGet get = new HttpGet(url);
        //发起请求
        try {
            //获取响应对象
            CloseableHttpResponse httpResponse = httpClient.execute(get);
            if (httpResponse.getStatusLine().getStatusCode()!=200){
                throw  new RuntimeException("请求错误");
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("请求错误");
        }
    }
}

4.3.3 编辑jt-sso Controller

   /**
     * 完成httpClient测试
     * url:http://sso.jt.com/user/httpClient/saveUser?username=111&password="2222"
     */
    @RequestMapping("/httpClient/saveUser")
    public SysResult saveUser(User user){
        userService.saveUser(user);
        return  SysResult.success();

    }

4.3.4 编辑jt-sso Service

@Autowired
    private UserMapper userMapper;
    //保存用户操作
    @Override
    public void saveUser(User user) {
        user.setPhone("13582x37xx5").setEmail("1x35430x61@qq.com");
        userMapper.insert(user);
    }

4.3.5 页面效果展现

在这里插入图片描述

posted on 2020-08-18 21:25  liqiangbk  阅读(422)  评论(0编辑  收藏  举报

导航