zoukankan      html  css  js  c++  java
  • 13、HttpClient服务器跨域请求

    回调

    1.1 回调函数

    1.1.1 回调的原理图

    说明:在架构设计中,回调的机制经常会被使用,课下自行学习.

     

    1.2 JSON的数据结构

    1.2.1 JSON官网介绍

     

    1.2.2 Object格式

     

    例子:{“key1”:”value1”,key2:”value2”}

    User(id.name.age)

    1.2.3 数组格式

     

    例子:[“value1”,”value2”,”value3”]

    1.2.4 复杂格式

    说明:将上述2中简单JSON格式进行无限层级的嵌套.最终形成的

     

    例子 [1,{id:1,name:”tom”,age:18}]

    {id:1,name:"tom",array:[1,2,3,4,5,{array:[22,33,44,55]}]}

    1.3 JSONP调用调用

    1.3.1 流程图

     

    1.4 缓存操作

    1.4.1 编辑Controller

    /**
         * 利用工具类直接返回JSONP的对象 callback({JSON})
         * @param callback
         * @return
         */
        @RequestMapping("/web/itemcat/all")
        @ResponseBody
        public Object findItemCat(String callback){
            
            ItemCatResult itemCatresult = itemCatService.findCacheItemCatAll();
            
            //负责JSONP对象返回 构造方法中添加返回的数据
            MappingJacksonValue jacksonValue = 
                    new MappingJacksonValue(itemCatresult);
            
            //设定返回值方法
            jacksonValue.setJsonpFunction(callback);
            return jacksonValue;
        }
    View Code

    1.4.2 编辑Service

    /**
         * 1.查询时应该先查询缓存
         * 2.如果缓存中没有缓存数据则执行业务操作查询数据
         * 3.将查询结果返回,将查询的结果存入缓存中
         * 4.如果缓存中含有该数据
         * 5.将缓存数据转化对象返回.满足编程的规范
         * @return
         */
        //实现三级商品分类的缓存操作
        @Override
        public ItemCatResult findCacheItemCatAll(){
            
            String key = "ITEM_CAT_ALL";
            
            String jsonData = jedisCluster.get(key);
            
            try {
                //判断数据是否为空
                if(StringUtils.isEmpty(jsonData)){
                    ItemCatResult itemCatResult = 
                            findItemCatAll();
                    //将对象转化为JSON串
                    String restJSON = 
                            objectMapper.writeValueAsString(itemCatResult);
                    //将数据存入redis中
                    jedisCluster.set(key, restJSON);
                    return itemCatResult;
                    
                }else {
                    ItemCatResult itemCatResult =
                            objectMapper.readValue(jsonData, ItemCatResult.class);
                    return itemCatResult;    
                }
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
    View Code

    商品详细页面展现

    2.1 HttpClent

    2.1.1 介绍

    总结:在业务层代码中,通过httpClient的方式可以模拟浏览器发出的Http请求.

    2.1.2 HttpClientJSONP的差别

     

    区别:

      1.发送请求的位置不同.

        JSONP的请求是由浏览器发出的.

        httpClient请求是由业务层模拟http协议发出的

      2.浏览器监控不同

        JSONP的调用浏览器可以完全的监控.

        HttpClient的方式浏览器不能监控其调用.对于业务的操作一般都会使用httpClient

      3.返回值处理不同

         1.JSONP的处理是通过页面的JS的方式解析返回结果

         2.HttpClient是通过业务代码的方式解析返回值结果.

    2.2 入门案例

    2.2.1 Jar包引入

    <!-- httpclient -->
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>${httpclient.version}</version>
            </dependency>

     

    2.2.2 Get请求

    //模拟get请求
        @Test
        public void testGet() throws ClientProtocolException, IOException{
            
            //1.创建httpCLient对象
            CloseableHttpClient httpClient 
             = HttpClients.createDefault();
            
            //2.定义uri
            String uri = "https://item.jd.com/1607218.html";
            
            //3.定义请求方式
            HttpGet httpGet = new HttpGet(uri);
    
            //4.发出请求
            CloseableHttpResponse response
                         = httpClient.execute(httpGet);
            
            //判断请求是否正确
            if(response.getStatusLine().getStatusCode() == 200){
                //获取请求内容
                String result = 
                        EntityUtils.toString(response.getEntity())  ;
                System.out.println("打印实体信息"+result);
            }
        }
    View Code

    2.2.3 Post提交

    @Test
        public void testPost() throws ClientProtocolException, IOException{
            
            //获取httpclient对象
            CloseableHttpClient client = 
                    HttpClients.createDefault();
            
            //定义url
            String url = "http://www.tmooc.cn/web/index_new.html?tedu";
            
            //定义Post请求方式
            HttpPost httpPost = new HttpPost(url);
            
            //Entity中需要设定post中提交的参数
            //UrlEncodedFormEntity entity =  new UrlEncodedFormEntity(parameters)
            //httpPost.setEntity(entity);
            
            CloseableHttpResponse httpResponse 
             =    client.execute(httpPost);
            
            //判断数据是否正确
            if(httpResponse.getStatusLine().getStatusCode() == 200){
                
                String msg = EntityUtils.toString(httpResponse.getEntity());
                System.out.println(msg);
            }
        }
    View Code

    2.3 Spring整合HttpClient

    2.3.1 导入Spring配置文件

    <!-- 定义httpclient连接池 -->
        <bean id="httpClientConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager" destroy-method="close">
            <!-- 设置连接总数 -->
            <property name="maxTotal" value="${http.pool.maxTotal}"></property>
            <!-- 设置每个地址的并发数 -->
            <property name="defaultMaxPerRoute" value="${http.pool.defaultMaxPerRoute}"></property>
        </bean>
        
        <!-- 定义 HttpClient工厂,这里使用HttpClientBuilder构建-->
        <bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create">
            <property name="connectionManager" ref="httpClientConnectionManager"></property>
        </bean>
        
        <!-- 得到httpClient的实例 -->
        <bean id="httpClient" factory-bean="httpClientBuilder" factory-method="build"/>
        
        <!-- 定期清理无效的连接 -->
        <bean class="com.jt.common.util.IdleConnectionEvictor" destroy-method="shutdown">
            <constructor-arg index="0" ref="httpClientConnectionManager" />
            <!-- 间隔一分钟清理一次 -->
            <constructor-arg index="1" value="60000" />
        </bean>
        
        <!-- 定义requestConfig的工厂 -->
        <bean id="requestConfigBuilder" class="org.apache.http.client.config.RequestConfig.Builder">
            <!-- 从连接池中获取到连接的最长时间 -->
            <property name="connectionRequestTimeout" value="${http.request.connectionRequestTimeout}"/>
            <!-- 创建连接的最长时间 -->
            <property name="connectTimeout" value="${http.request.connectTimeout}"/>
            <!-- 数据传输的最长时间 -->
            <property name="socketTimeout" value="${http.request.socketTimeout}"/>
            <!-- 提交请求前测试连接是否可用 -->
            <property name="staleConnectionCheckEnabled" value="${http.request.staleConnectionCheckEnabled}"/>
        </bean>    
        
        <!-- 得到requestConfig实例 -->
        <bean id="requestConfig" factory-bean="requestConfigBuilder" factory-method="build" />
    View Code

    2.3.2 导入properties文件

     

    Spring引入配置文件

     

    2.3.3 编辑Get请求

    Get请求

    Get请求
    /**
         * 说明:
         *     编辑工具类时需要处理2中类型的请求 get post
         * 参数介绍:
         *  addUser?id:1&name=tom&age=18
         *     定义url  确定访问的路径
         *  定义参数集合 Map<String,String>.指定参数的类型都是String
         *  定义字符集 encode=utf-8 
         *  
         *  方法介绍
         *  根据不同的用户需求,重载多个方法
         */
        
        
        /**
         * 编辑思路:
         * Url:findItem?id=1&name=tom
         * 1.判断是否包含参数,如果包含参数应该将参数进行动态的拼接
         * 2.判断是否指定字符集编码  如果没有指定则设置默认值UTF-8
         * 3.通过httpClient对象发起http请求
         * 4.判断返回值是否有效
         * 5.将结果返回
         * @param url
         * @param params
         * @param charset
         * @return
         * @throws URISyntaxException 
         */
        public String doGet(String uri,Map<String, String> params,String charset) throws URISyntaxException{
            //1.判断是否含有参数 Url:findItem?id=1&name=tom
            URIBuilder builder = new URIBuilder(uri);
            if(params !=null){
                //整理get提交参数
                for (Map.Entry<String, String> param :params.entrySet()) {
                    builder.addParameter(param.getKey(), param.getValue());
                }
                //Uri:findItem?id=1&name=tom&age=18
                System.out.println("编辑uri结果:!!!!"+builder.toString());
                uri = builder.toString();    
            }
            
            //判断字符集编码
            if(StringUtils.isEmpty(charset)){
                
                charset = "UTF-8";
            }
            
            //定义Get请求对象
            HttpGet httpGet = new HttpGet(uri);
            httpGet.setConfig(requestConfig);
            
            //发送请求
            try {
                CloseableHttpResponse httpResponse 
                    = httpClient.execute(httpGet);
                //判断请求是否正确
                if(httpResponse.getStatusLine().getStatusCode() == 200){
                    //result是远程返回的JSON数据
                    String result = EntityUtils.toString(httpResponse.getEntity(),charset);
                    return result;    
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return null;
        }
    View Code

    2.3.4 编辑Post请求

    Post请求

    Post请求
    /*
         * 1.doPost请求方式和doget类似
         * 2.doPost中的参数传递借助form表单.
         * 
         * 编码步骤:
         *     1.定义请求的对象 httpPost()
         *  2.判断是否含有参数,如果含有参数需要表单的赋值
         *  3.将form表单的参数赋值给post请求
         * 
         */
        public String doPost(String uri,Map<String, String> params,String charset) throws UnsupportedEncodingException{
            
            //定义post提交方式
            HttpPost httpPost = new HttpPost(uri);
            if(StringUtils.isEmpty(charset)){
                 
                charset = "UTF-8";
            }
            //判断参数是否为空
            if(params !=null){
                //定义参数提交的集合
                List<NameValuePair> parameters = 
                        new ArrayList<NameValuePair>();
                
                //为参数赋值
                for (Map.Entry<String, String> param : params.entrySet()) {
                    
                    BasicNameValuePair nameValuePair =
                            new BasicNameValuePair(param.getKey(), param.getValue());
                    parameters.add(nameValuePair);
                }
                
                UrlEncodedFormEntity entity = 
                        new UrlEncodedFormEntity(parameters, charset);
                //为post请求赋值
                httpPost.setEntity(entity);
            }
            try {
                CloseableHttpResponse response = 
                        httpClient.execute(httpPost);
                
                //判断返回值是否正确
                if(response.getStatusLine().getStatusCode() == 200){
                    
                    String result = EntityUtils.toString(response.getEntity(),charset);
                    return result;
                }
                
            } catch (Exception e) {
                e.printStackTrace();
            } 
            return null;
        }
    View Code

    2.4 商品详细实现

    2.4.1  页面分析

    说明:当查询某一个商品时,会发送一个请求,并且采用resuFul风格进行数据的提交

    http://www.jt.com/items/562379.html

    2.4.2 HttpClient调用流程图

     

    说明:

    1.客户端首先接收请求 http://www.jt.com/items/1474391982.html,交给Controller处理

    2.调用客户端Service

    3.通过httpClient进行跨域访问

    4.服务端Controller接收请求并且处理

    5.业务层代码获取Item数据

    2.4.3 分析页面

    说明:根据访问地址编辑Controller

    2.4.4 编辑客户端Controller

    说明:controller拦截客户端请求

    /**

     * 将来的页面是否需要人为的指定

     * @param itemId

     * @return

     */

    @RequestMapping("/{itemId}")

    public String findItemById(@PathVariable Long itemId,Model model){

     

    Item item = itemService.findItemById(itemId);

     

    model.addAttribute("item", item);

     

    return "item";

    }

    2.4.5 调用客户端Service

    /**

     * 经过京淘前台的业务层,去访问后台的业务代码?

     * 解决策略:跨域

     * 问题:在业务层中不能采用JSONP的形式进行跨域调用

     * 解决:采用HttpClient方式进行调用

     *

     */

    @Override

    public Item findItemById(Long itemId) {

    String uri = "http://manage.jt.com/web/item/findItemById/"+itemId;

    try {

    String jsonData = httpClientService.doGet(uri);

     

    if(!StringUtils.isEmpty(jsonData)){

    //需要将JSON串转化为Item对象

    Item item =

    objectMapper.readValue(jsonData, Item.class);

    return item;

    }

    } catch (Exception e) {

    e.printStackTrace();

    }

    return null;

    }

    2.4.6 编辑后端Controller

    说明:根据客户端发出的请求,Controller接收请求

    //http://manage.jt.com/web/item/findItemById/"+itemId

    @RequestMapping("/findItemById/{itemId}")

    @ResponseBody

    public Item findItemById(@PathVariable Long itemId){

     

    //根据Id获取后台Item数据

    Item item = itemService.findItemById(itemId);

     

    return item;

    }

    2.4.7 编辑服务端Service

    说明:根据ItemId获取Item数据并且返回

    @Override

    public Item findItemById(Long itemId) {

     

    Item item = itemMapper.selectByPrimaryKey(itemId);

     

    return item;

    }

    2.5 商品信息实现缓存

    2.5.1 前台实现缓存处理

    2.6 维护redis中数据的一致性

    2.6.1 后台数据更新维护

    说明:当后台数据进行更新或者删除操作时,需要进行redis内存的数据维护,策略将redis中的更新数据直接删除.

  • 相关阅读:
    PHP抛出简单说明
    html设置强制缓存的方法
    php yield处理大数据的方法
    pixijs 粒子聚合图片
    PHP监听消息队列的方法
    C++ fstream 二进制读写文件 (一个文件备份的例子)
    Ubuntu18.04下Docker CE安装
    Python3.9安装
    如何通过SQL命令更改Postgres的max_connections
    ubuntu 配置br0网桥,亲测有效
  • 原文地址:https://www.cnblogs.com/xiangyuqi/p/8652828.html
Copyright © 2011-2022 走看看