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中的更新数据直接删除.