• java学习day78--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

    srcmainwebappjs egisterjdValidate.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 页面效果展现

    在这里插入图片描述

  • 相关阅读:
    Android_NDK问题:APP_BUILD_SCRIPT points to an unknown file: <project_path>/jni/Android.mk
    Android开发问题集锦-Button初始为disable状态时自定义的selector不生效问题
    一步步学习Python-django开发-添加后台管理
    一步步学习Python-django开发-建立django数据库
    一步步学习Python-django开发-Mac下搭建Python-Django环境
    JAVA小知识点-Finally和Return的执行关系
    Android自定义组合控件内子控件无法显示问题
    《将博客搬至CSDN》
    idea自动生成try/catch代码块的快捷键
    转:Apache common包 CollectionUtils 使用详解
  • 原文地址:https://www.cnblogs.com/liqbk/p/13526140.html
Copyright © 2020-2023  润新知