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