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中的更新數據直接刪除.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM