日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

大数据互联网架构阶段 前台系统架构 跨域请求

發(fā)布時間:2024/4/30 windows 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 大数据互联网架构阶段 前台系统架构 跨域请求 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

電商項目 前臺系統(tǒng)的架構(gòu)

零、目錄

  • 前臺架構(gòu)設(shè)計
  • 前臺分類樹
  • 跨域請求技術(shù)
    • jsonp
    • httpClient

一 、前臺架構(gòu)設(shè)計

  • 不能直接訪問數(shù)據(jù)庫 , 需要通過后臺訪問數(shù)據(jù)
  • 架構(gòu): 單通道連接資源 , 數(shù)據(jù)資源不能交叉訪問
  • 安全: 前臺 對外網(wǎng)掛接 , 不適合訪問數(shù)據(jù)庫 , 有安全隱患 , 前臺需要跨系統(tǒng)訪問數(shù)據(jù)
  • 跨系統(tǒng)訪問數(shù)據(jù)用到的的技術(shù):
  • jsonp
  • httpClient
  • RabbitMQ
  • 二、 前臺分類樹

  • 商品分類:
  • 在后臺系統(tǒng)中的商品分類請求的設(shè)計是分級請求的 , 先展示一級分類 ,然后點(diǎn)擊時獲取被點(diǎn)擊的id , 獲取他的子分類
  • 但是在前臺系統(tǒng)商品分類的設(shè)計中 , 只發(fā)起一次ajax異步請求 , 請求到所有的封裝好的三層結(jié)構(gòu)的商品分類數(shù)據(jù)(使用map+ list+ 三層循環(huán)嵌套實現(xiàn))
  • 商品分類數(shù)據(jù)的結(jié)構(gòu)
  • 數(shù)據(jù)的要求

  • 前臺需要一個json串 , ,需要構(gòu)建一個對象ItemCatResult,內(nèi)部只有一個data屬性的集合
  • 整體的返回結(jié)構(gòu)都在data中完成
  • 每個data中的list對象進(jìn)行封裝嵌套完成3層結(jié)構(gòu)

    u, n, i; 其中u和n都是字符串 i是list集合,集合的元素類型又是itemCatData
  • 按照以上要求完成pojo設(shè)計

    public class ItemCatResult {@JsonProperty("data")private List<ItemCatData> itemCats ;public List<ItemCatData> getItemCats() {return itemCats;}public void setItemCats(List<ItemCatData> itemCats) {this.itemCats = itemCats;}} public class ItemCatData {@JsonProperty("u")//傳遞時以u傳遞 , 減少跨域傳遞數(shù)據(jù)的字節(jié)數(shù) , 加快傳遞速度private String url;@JsonProperty("n")private String name;@JsonProperty("i")private List<?> items;public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getName() {return name;}public void setName(String name) {this.name = name;}public List<?> getItems() {return items;}public void setItems(List<?> items) {this.items = items;}} 完成三成結(jié)構(gòu)數(shù)據(jù)的封裝 處理前臺分類樹 請求,返回具有三層結(jié)構(gòu)偶的數(shù)據(jù)@RequestMapping("web/itemcat/all")@ResponseBodypublic ItemCatResult queryItemCat() {//整理三層結(jié)構(gòu)的數(shù)據(jù)//先獲取所有的數(shù)據(jù)List<ItemCat> itemCats = itemCatService.queryAll();//創(chuàng)建一個返回對象ItemCatResult result = new ItemCatResult();//引入一個map + list + 三層for循環(huán)嵌套//map維護(hù)當(dāng)前分類中的父子關(guān)系, key保存一個id , value保存該id的所有子類(list形式)Map<Long , List<ItemCat>> map = new HashMap<Long , List<ItemCat>>();//對map進(jìn)行處理for(ItemCat itemCat : itemCats) {//從當(dāng)前的所有l(wèi)ist中獲取一個parentIdif(!map.containsKey(itemCat.getParentId())) {//創(chuàng)建一個map的元素 ,key為整個parentId , value為該id的所有子類(list形式)map.put(itemCat.getParentId(), new ArrayList<ItemCat>());}//把當(dāng)前對象放入map維護(hù)的父子關(guān)系中 。 map.get(itemCat.getParentId()).add(itemCat);}//開始構(gòu)建result對象//一級菜單內(nèi)容 , 從map獲取一級分類的listList<ItemCat> itemCatList01 = map.get(new Long(0));//從一級菜單入手完成result的dataList<ItemCatData> itemCatDataList1 = new ArrayList<ItemCatData>();//完成data里的數(shù)據(jù)for(ItemCat itemCat : itemCatList01) {ItemCatData itemCatData1 = new ItemCatData();itemCatData1.setUrl("/products/"+itemCat.getId()+".html");itemCatData1.setName("<a href='"+itemCatData1.getUrl()+"'>"+itemCat.getName()+"</a>");//進(jìn)行當(dāng)前對象的二層菜單的數(shù)據(jù)封裝個 , 使用第二層forList<ItemCatData> itemCatDataList2 = new ArrayList<ItemCatData>();List<ItemCat> itemCatList02 = map.get(itemCat.getId());for(ItemCat itemCats2 : itemCatList02) {ItemCatData itemCatData2 = new ItemCatData();itemCatData2.setUrl("/products/"+itemCats2.getId()+".html");itemCatData2.setName("<a href='"+itemCatData2.getUrl()+"'>"+itemCats2.getName()+"</a>");List<String> itemCatDataList3 = new ArrayList<String>();List<ItemCat> itemCatList03 = map.get(itemCats2.getId());for(ItemCat itemCat3 : itemCatList03) {itemCatDataList3.add("/products/"+itemCat3.getId()+".html"+itemCat3.getName());}itemCatData2.setItems(itemCatDataList3);itemCatDataList2.add(itemCatData2);}itemCatData1.setItems(itemCatDataList2);itemCatDataList1.add(itemCatData1);}result.setItemCats(itemCatDataList1);return result;}
  • 三 、 跨域請求問題

  • 在電商項目中 , 為了提高數(shù)據(jù)庫的可用性 , 引入了緩存技術(shù) , 而像電商項目這樣的大型項目一般都需需要進(jìn)行橫向拆分成多個特定功能的系統(tǒng)來同時開發(fā) , 但是由于多個系統(tǒng)去訪問數(shù)據(jù)庫執(zhí)行魂村邏輯時, 可能引起數(shù)據(jù)混亂 , 這就限制了數(shù)據(jù)只能單通道訪問 , 前臺系統(tǒng)在緩存中沒有數(shù)據(jù)時不能直接訪問數(shù)據(jù)庫 , 而是通過后臺系統(tǒng)去請求數(shù)據(jù) 。 , 這就引出了跨域訪問的種種問題 。
  • 四、 Jsonp跨域請求數(shù)據(jù)

  • 前臺系統(tǒng)的頁面發(fā)出ajax請求 , 到后臺系統(tǒng)請求商品分類數(shù)據(jù)
  • 但是前臺和后臺是兩個系統(tǒng) , 從后臺訪問數(shù)據(jù)屬于跨域訪問 , 無法使用json格式數(shù)據(jù) , 需要jsonp
  • 前臺調(diào)用的jquery代碼

    $.getJSONP(url , 參數(shù)){}
  • json廣泛流行的原因是 , json是js原聲支持的格式, 在js中可以自動將json格式的數(shù)據(jù)轉(zhuǎn)換為對象后調(diào)用其中的屬性 。
  • 但是由于js的同源策略導(dǎo)致前臺系統(tǒng)獲取到后臺系統(tǒng)的數(shù)據(jù)后不能夠解析 , 想要解決js同源策略引起的跨域請求問題 , 需要引入jsonp技術(shù)
  • jsonp實際上就是在json字符串外包裝一個方法 , 利用script標(biāo)簽可以將跨域的數(shù)據(jù)請求到 , 然后通過一個js方法即可解析 , 但是要注意js的方法名必須要與json外層包裝的方法名一致
  • 但是后臺通過@ResponseBody返回的數(shù)據(jù)默認(rèn)就是json格式 , 需要自己構(gòu)建一個responseBody類似的對象將返回的數(shù)據(jù)轉(zhuǎn)換成jsonp需要的格式 。
  • 開發(fā)步驟:

  • 前臺發(fā)出請求 url?callback=xxxx
  • 后臺controller處理這個請求時不接受callback參數(shù) , 正常返回數(shù)據(jù)即可
  • 自定義responseBody轉(zhuǎn)換器

    public class CallbackMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {// 做jsonp的支持的標(biāo)識,在請求參數(shù)中加該參數(shù)private String callbackName;@Overrideprotected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException,HttpMessageNotWritableException {// 從threadLocal中獲取當(dāng)前的Request對象HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();String callbackParam = request.getParameter(callbackName);if (StringUtils.isEmpty(callbackParam)) {// 沒有找到callback參數(shù),直接返回json數(shù)據(jù)super.writeInternal(object, outputMessage);} else {JsonEncoding encoding = getJsonEncoding(outputMessage.getHeaders().getContentType());try {//將對象轉(zhuǎn)換為json串,然后用回調(diào)方法包括起來String result = callbackParam + "(" + super.getObjectMapper().writeValueAsString(object)+ ");";IOUtils.write(result, outputMessage.getBody(), encoding.getJavaName());} catch (JsonProcessingException ex) {throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);}}}public String getCallbackName() {return callbackName;}public void setCallbackName(String callbackName) {this.callbackName = callbackName;}}
  • 將自定義的轉(zhuǎn)換器配置在spring-mvc配置文件中

    <!-- MVC注解驅(qū)動 --><mvc:annotation-driven><!-- 采用自定義方案 --><mvc:message-converters><!-- 定義原有的文本轉(zhuǎn)化器 , 如果不定義 則會被后定義的文本轉(zhuǎn)換器覆蓋--><bean class="org.springframework.http.converter.StringHttpMessageConverter"><constructor-arg index="0" value="UTF-8" /></bean><!-- 添加自定義json轉(zhuǎn)化器,完成jsonp格式數(shù)據(jù)的峰裝 , 支持json跨域 --><beanclass="com.jt.common.spring.exetend.jackson.CallbackMappingJackson2HttpMessageConverter"><!-- 跨域請求中的請求參數(shù)名 --><!-- 當(dāng)參數(shù)中有callback屬性時 , 調(diào)用這個轉(zhuǎn)換器 --><!-- 從參數(shù)中尋找callback , 在代碼中處理 --><property name="callbackName" value="callback"></property></bean></mvc:message-converters></mvc:annotation-driven>
  • 這樣在返回就過時 , 就會在結(jié)果外層包裝一個callback參數(shù)對應(yīng)的方法 , 形成jsonp格式的數(shù)據(jù) 。
  • 四、 httpClient跨域請求

  • 自定義httpClientService

    @Service public class HttpClientService {private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientService.class);@Autowired(required=false)private CloseableHttpClient httpClient;@Autowired(required=false)private RequestConfig requestConfig;/*** 執(zhí)行g(shù)et請求* * @param url* @return* @throws Exception*/public String doGet(String url,Map<String, String> params,String encode) throws Exception {LOGGER.info("執(zhí)行GET請求,URL = {}", url);if(null != params){URIBuilder builder = new URIBuilder(url);for (Map.Entry<String, String> entry : params.entrySet()) {builder.setParameter(entry.getKey(), entry.getValue());}url = builder.build().toString();}// 創(chuàng)建http GET請求HttpGet httpGet = new HttpGet(url);httpGet.setConfig(requestConfig);CloseableHttpResponse response = null;try {// 執(zhí)行請求response = httpClient.execute(httpGet);// 判斷返回狀態(tài)是否為200if (response.getStatusLine().getStatusCode() == 200) {if(encode == null){encode = "UTF-8";}return EntityUtils.toString(response.getEntity(), encode);}} finally {if (response != null) {response.close();}// 此處不能關(guān)閉httpClient,如果關(guān)閉httpClient,連接池也會銷毀}return null;}public String doGet(String url, String encode) throws Exception{return this.doGet(url, null, encode);}public String doGet(String url) throws Exception{return this.doGet(url, null, null);}/*** 帶參數(shù)的get請求* * @param url* @param params* @return* @throws Exception*/public String doGet(String url, Map<String, String> params) throws Exception {return this.doGet(url, params, null);}/*** 執(zhí)行POST請求* * @param url* @param params* @return* @throws Exception*/public String doPost(String url, Map<String, String> params,String encode) throws Exception {// 創(chuàng)建http POST請求HttpPost httpPost = new HttpPost(url);httpPost.setConfig(requestConfig);if (null != params) {// 設(shè)置2個post參數(shù),一個是scope、一個是qList<NameValuePair> parameters = new ArrayList<NameValuePair>(0);for (Map.Entry<String, String> entry : params.entrySet()) {parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));}// 構(gòu)造一個form表單式的實體UrlEncodedFormEntity formEntity = null;if(encode!=null){formEntity = new UrlEncodedFormEntity(parameters,encode);}else{formEntity = new UrlEncodedFormEntity(parameters);}// 將請求實體設(shè)置到httpPost對象中httpPost.setEntity(formEntity);}CloseableHttpResponse response = null;try {// 執(zhí)行請求response = httpClient.execute(httpPost);// 判斷返回狀態(tài)是否為200if (response.getStatusLine().getStatusCode() == 200) {return EntityUtils.toString(response.getEntity(), "UTF-8");}} finally {if (response != null) {response.close();}}return null;}/*** 執(zhí)行POST請求* * @param url* @param params* @return* @throws Exception*/public String doPost(String url, Map<String, String> params) throws Exception {// 創(chuàng)建http POST請求HttpPost httpPost = new HttpPost(url);httpPost.setConfig(requestConfig);if (null != params) {// 設(shè)置2個post參數(shù),一個是scope、一個是qList<NameValuePair> parameters = new ArrayList<NameValuePair>(0);for (Map.Entry<String, String> entry : params.entrySet()) {parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));}// 構(gòu)造一個form表單式的實體UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);// 將請求實體設(shè)置到httpPost對象中httpPost.setEntity(formEntity);}CloseableHttpResponse response = null;try {// 執(zhí)行請求response = httpClient.execute(httpPost);// 判斷返回狀態(tài)是否為200if (response.getStatusLine().getStatusCode() == 200) {return EntityUtils.toString(response.getEntity(), "UTF-8");}} finally {if (response != null) {response.close();}}return null;}public String doPostJson(String url, String json) throws Exception {// 創(chuàng)建http POST請求HttpPost httpPost = new HttpPost(url);httpPost.setConfig(requestConfig);if(null != json){//設(shè)置請求體為 字符串StringEntity stringEntity = new StringEntity(json,"UTF-8");httpPost.setEntity(stringEntity);}CloseableHttpResponse response = null;try {// 執(zhí)行請求response = httpClient.execute(httpPost);// 判斷返回狀態(tài)是否為200if (response.getStatusLine().getStatusCode() == 200) {return EntityUtils.toString(response.getEntity(), "UTF-8");}} finally {if (response != null) {response.close();}}return null;}}
  • 在spring配置文件中配置

    <!-- 定義httpclient連接池 --> <bean id="httpClientConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager" destroy-method="close"><!-- 設(shè)置連接總數(shù) --><property name="maxTotal" value="${http.pool.maxTotal}"></property><!-- 設(shè)置每個地址的并發(fā)數(shù) --><property name="defaultMaxPerRoute" value="${http.pool.defaultMaxPerRoute}"></property> </bean><!-- 定義 HttpClient工廠,這里使用HttpClientBuilder構(gòu)建--> <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}"/><!-- 創(chuàng)建連接的最長時間 --><property name="connectTimeout" value="${http.request.connectTimeout}"/><!-- 數(shù)據(jù)傳輸?shù)淖铋L時間 --><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" />
  • 配置文件所需要的參數(shù)信息 httpclient.properties

    #從連接池中獲取到連接的最長時間http.request.connectionRequestTimeout=500#5000http.request.connectTimeout=5000#數(shù)據(jù)傳輸?shù)淖铋L時間http.request.socketTimeout=30000#提交請求前測試連接是否可用http.request.staleConnectionCheckEnabled=true#設(shè)置連接總數(shù)http.pool.maxTotal=200#設(shè)置每個地址的并發(fā)數(shù)http.pool.defaultMaxPerRoute=100
  • 總結(jié)

    以上是生活随笔為你收集整理的大数据互联网架构阶段 前台系统架构 跨域请求的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。