1 回調
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; }
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; }
2 商品詳細頁面展現
2.1 HttpClent
2.1.1 介紹
總結:在業務層代碼中,通過httpClient的方式可以模擬瀏覽器發出的Http請求.
2.1.2 HttpClient和JSONP的差別
區別:
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);
}
}
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);
}
}
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" />
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; }
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; }
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中的更新數據直接刪除.