框架 day78 濤濤商城專案-CMS內容管理,httpclient使用,首頁ad展示
淘淘商城第六天
講師:入雲龍
1 首頁大廣告位的實現分析
首頁的內容需要動態管理,需要後臺管理功能。
抽取首頁展示內容的共性:
1、有一張圖片
2、有一個連線
3、有一個標題
4、有連結的提示
5、價格
需要把內容進行分類,分類應該是一個樹形結構。
在展示首頁時,可以根據分類取內容資訊,把內容展示到頁面。
在後臺管理內容及內容分類的系統就叫做cms系統。
2 Cms系統
先實現內容的分類管理再實現內容管理。
2.1 內容分類管理
2.1.1 內容分類初始化
2.1.1.1 需求分析
初始化樹形檢視的url:/content/category/list
引數是id,當前節點id屬性,應該根據此id查詢子節點列表。
返回值:包含id、text、state三個屬性的json資料列表
2.1.1.2 Dao層
需要一張表儲存內容資料:欄位:標題、url、子標題、image、內容分類id等等
需要一張表儲存內容的分類資訊,樹形結構的表。
表結構:
內容分類表
內容表
Sql語句:
根據parentid查詢節點列表
SELECT * FROM `tb_content_category` WHEREparent_id = 30;
單表查詢可以實現逆向工程生成的程式碼。
2.1.1.3 Service層
功能:接收parentid。根據parentid查詢節點列表,返回返回一個EasyUI非同步Tree要求的節點列表。每個節點包含三個屬性id、text、state三個屬性。可以使用EUTreeNode。
引數:id
返回值:List<EUTreeNode>
@Service public class ContentCategoryServiceImpl implements ContentCategoryService { @Autowired private TbContentCategoryMappercontentCategoryMapper; @Override public List<EUTreeNode> getCategoryList(longparentId) { //根據parentid TbContentCategoryExample example =new TbContentCategoryExample(); Criteria criteria = example.createCriteria(); criteria.andParentIdEqualTo(parentId); //執行查詢 List<TbContentCategory> list =contentCategoryMapper.selectByExample(example); List<EUTreeNode> resultList =new ArrayList<>(); for (TbContentCategorytbContentCategory : list) { //建立一個節點 EUTreeNode node =new EUTreeNode(); node.setId(tbContentCategory.getId()); node.setText(tbContentCategory.getName()); node.setState(tbContentCategory.getIsParent()?"closed":"open"); resultList.add(node); } returnresultList; } } |
2.1.1.4 Controller
接收頁面傳遞過來的parentid,根據parentid查詢節點列表。返回List<EUTreeNode>。需要響應json資料。
@Controller @RequestMapping("/content/category") public class ContentCategoryController { @Autowired private ContentCategoryServicecontentCategoryService; @RequestMapping("/list") @ResponseBody public List<EUTreeNode> getContentCatList(@RequestParam(value="id", defaultValue="0")LongparentId) { List<EUTreeNode> list =contentCategoryService.getCategoryList(parentId); returnlist; } } |
2.1.2 內容分類新增
2.1.2.1 需求分析
請求的url:/content/category/create
引數:
1、parentId父節點id
2、name:當前節點的名稱
返回值:TaotaoResult。其中包含節點pojo物件。
2.1.2.2 Dao層
可以使用逆向工程生成的程式碼
2.1.2.3 Service層
功能:接收兩個引數parentId父節點id、name:當前節點的名稱。向tb_content_category表中新增一條記錄。返回TaoTaoResult包含記錄的pojo物件。
需要返回主鍵資訊:
需要修改mapper檔案,返回主鍵資訊。
方式一:
方式二:
<insert id="insert" parameterType="com.taotao.pojo.TbContentCategory" useGeneratedKeys="true"keyProperty="id"> insert into tb_content_category (id, parent_id, name, status, sort_order, is_parent, created, updated) values (#{id,jdbcType=BIGINT}, #{parentId,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, #{status,jdbcType=INTEGER}, #{sortOrder,jdbcType=INTEGER}, #{isParent,jdbcType=BIT}, #{created,jdbcType=TIMESTAMP}, #{updated,jdbcType=TIMESTAMP}) </insert> |
@Override public TaotaoResult insertContentCategory(longparentId, String name) { //建立一個pojo TbContentCategory contentCategory =new TbContentCategory(); contentCategory.setName(name); contentCategory.setIsParent(false); //'狀態。可選值:1(正常),2(刪除)', contentCategory.setStatus(1); contentCategory.setParentId(parentId); contentCategory.setSortOrder(1); contentCategory.setCreated(new Date()); contentCategory.setUpdated(new Date()); //新增記錄 contentCategoryMapper.insert(contentCategory); //檢視父節點的isParent列是否為true,如果不是true改成true TbContentCategory parentCat =contentCategoryMapper.selectByPrimaryKey(parentId); //判斷是否為true if(!parentCat.getIsParent()) { parentCat.setIsParent(true); //更新父節點 contentCategoryMapper.updateByPrimaryKey(parentCat); } //返回結果 return TaotaoResult.ok(contentCategory); } |
2.1.2.4 Controller層
接收兩個引數parentid、name。呼叫Service新增記錄。返回TaotaoResult。應該返回json資料。
@RequestMapping("/create") @ResponseBody public TaotaoResult createContentCategory(LongparentId, String name) { TaotaoResult result =contentCategoryService.insertContentCategory(parentId,name); returnresult; } |
2.1.3 內容分類刪除
需求分析:
請求的url:
/content/category/delete/
引數:
1、parentId
2、Id
返回值:TaotaoResult
業務邏輯:
接收parentid、id兩個引數。刪除id對應的記錄。需要判斷parentid對應的記錄下是否有子節點。如果沒有子節點。需要把parentid對應的記錄的isparent改成false。
注意:刪除直接是物理刪除。
2.1.4 重新命名節點
1、
2、當編輯完成後會觸發onAfterEdit事件。
請求的url:/content/category/update
引數:id、name
返回值:返回TaotaoResult。Json格式
業務邏輯:根據id更新記錄的name列即可。
2.2 內容管理
內容管理表:
2.2.1 內容列表
需求分析
請求url:/content/query/list
引數:page、rows、categoryId
返回值:EUDataGridResult
Total、rows:內容pojo列表。
業務邏輯:
根據內容分類id查詢內容列表。需要實現分頁。返回EUDataGridResult
2.2.2 內容新增
需求分析:
圖片上傳初始化:
內容表單提交:
請求的url:/content/save
請求的方法:post
請求內容:表單中的內容。
返回的結果:TaotaoResult。
2.2.3 Dao層
向tb_content表中插入資料。可以使用逆向工程生成的程式碼。
2.2.4 Service層
接收表tb_content對應的pojo物件。把pojo物件插入到tb_content表中。
返回TaotaoResult。
@Service public class ContentServiceImpl implements ContentService { @Autowired private TbContentMapper contentMapper; @Override public TaotaoResult insertContent(TbContentcontent) { //補全pojo內容 content.setCreated(new Date()); content.setUpdated(new Date()); contentMapper.insert(content); return TaotaoResult.ok(); } } |
2.2.5 Controller層
接收表單中的內容,使用pojo接收。要求pojo的屬性要和表單中的name一致。呼叫Service插入內容資訊。返回TaotaoResult。Json格式的資料。
@Controller @RequestMapping("/content") public class ContentController { @Autowired private ContentServicecontentService; @RequestMapping("/save") @ResponseBody public TaotaoResult insertContent(TbContent content) { TaotaoResult result =contentService.insertContent(content); returnresult; } } |
3 展示商城首頁大廣告位
3.1 首頁大廣告方案
前端系統獲取後端系統提供的介面,如何獲取?
3.1.1 方案1
jsonp跨域請求
需要當首頁載入完畢後,大廣告位就應該顯示。沒有觸發事件。不是太合適。
優點:不需要二次請求,頁面直接載入內容資料。減少門戶系統的壓力。
缺點:需要延遲載入。不利於seo優化。
3.1.2 第二種方案:
優點:有利於seo優化。可以在taotao-portal中對資料進行加工。
缺點:系統直接需要呼叫服務查詢內容資訊。多了一次http請求。
系統直接服務的呼叫,需要使用httpclient來實現。Taotao-portal和taotao-rest是在同一個區域網內部。速度非常快,呼叫時間可以忽略不計。
展示首頁內容功能,使用方案二實現。
3.2 展示流程
3.3 內容服務釋出
3.3.1 需求分析
根據內容的分類id查詢內容列表,從tb_content表中查詢。服務是一個restFul形式的服務。使用http協議傳遞json格式的資料。
3.3.2 Dao層
從tb_content表中查詢,根據內容分類id查詢。是單表查詢。可以使用逆向工程生成的程式碼。
3.3.3 Service層
接收內容分類id,根據分類id查詢分類列表。返回一個內容pojo列表。
引數:分類id
返回值:pojo列表
@Service public class ContentServiceImpl implements ContentService { @Autowired private TbContentMappercontentMapper; @Override public List<TbContent> getContentList(longcontentCid) { //根據內容分類id查詢內容列表 TbContentExample example =new TbContentExample(); Criteria criteria = example.createCriteria(); criteria.andCategoryIdEqualTo(contentCid); //執行查詢 List<TbContent> list =contentMapper.selectByExample(example); returnlist; } } |
3.3.4 Controller層
釋出服務。接收查詢引數。Restful風格內容分類id應該從url中取。
/rest/content/list/{contentCategoryId}
從url中取內容分類id,呼叫Service查詢內容列表。返回內容列表。返回一個json格式的資料。可以使用TaotaoResult包裝此列表。
@Controller @RequestMapping("/content") public class ContentController { @Autowired private ContentServicecontentService; @RequestMapping("/list/{contentCategoryId}") @ResponseBody public TaotaoResult getContentList(@PathVariable LongcontentCategoryId) { try { List<TbContent> list =contentService.getContentList(contentCategoryId); return TaotaoResult.ok(list); } catch (Exceptione) { e.printStackTrace(); return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e)); } } } |
3.4 Httpclient的使用
3.4.1 什麼是httpclient
HttpClient 是 Apache Jakarta Common 下的子專案,用來提供高效的、最新的、功能豐富的支援 HTTP 協議的客戶端程式設計工具包,並且它支援 HTTP 協議最新的版本和建議。
HTTP 協議可能是現在 Internet 上使用得最多、最重要的協議了,越來越多的 Java 應用程式需要直接通過 HTTP 協議來訪問網路資源。雖然在 JDK 的 java net包中已經提供了訪問 HTTP 協議的基本功能,但是對於大部分應用程式來說,JDK 庫本身提供的功能還不夠豐富和靈活。HttpClient 是 Apache Jakarta Common 下的子專案,用來提供高效的、最新的、功能豐富的支援 HTTP 協議的客戶端程式設計工具包,並且它支援 HTTP 協議最新的版本和建議。
下載地址:
以下列出的是 HttpClient 提供的主要的功能,要知道更多詳細的功能可以參見 HttpClient 的主頁。
(1)實現了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)
(2)支援自動轉向
(3)支援 HTTPS 協議
(4)支援代理伺服器等
3.4.2 新增依賴
需要把httpclient的jar包新增到工程中。只需要在工程中新增httpclient的依賴。
3.4.3 使用方法
3.4.3.1 使用httpclient執行get請求
@Test public void doGet() throws Exception { //建立一個httpclient物件 CloseableHttpClient httpClient = HttpClients.createDefault(); //建立一個GET物件 HttpGet get = new HttpGet("http://www.sogou.com"); //執行請求 CloseableHttpResponse response =httpClient.execute(get); //取響應的結果 intstatusCode = response.getStatusLine().getStatusCode(); System.out.println(statusCode); HttpEntity entity = response.getEntity(); String string = EntityUtils.toString(entity,"utf-8"); System.out.println(string); //關閉httpclient response.close(); httpClient.close(); } |
3.4.3.2 執行get請求帶引數
@Test public void doGetWithParam() throws Exception{ //建立一個httpclient物件 CloseableHttpClient httpClient = HttpClients.createDefault(); //建立一個uri物件 URIBuilder uriBuilder = new URIBuilder("http://www.sogou.com/web"); uriBuilder.addParameter("query", "花千骨"); HttpGet get = new HttpGet(uriBuilder.build()); //執行請求 CloseableHttpResponse response =httpClient.execute(get); //取響應的結果 intstatusCode = response.getStatusLine().getStatusCode(); System.out.println(statusCode); HttpEntity entity = response.getEntity(); String string = EntityUtils.toString(entity,"utf-8"); System.out.println(string); //關閉httpclient response.close(); httpClient.close(); } |
3.4.3.3 使用httpclient執行post請求
@Test public void doPost() throws Exception { CloseableHttpClient httpClient = HttpClients.createDefault(); //建立一個post物件 HttpPost post = new HttpPost("http://localhost:8082/httpclient/post.html"); //執行post請求 CloseableHttpResponse response =httpClient.execute(post); String string = EntityUtils.toString(response.getEntity()); System.out.println(string); response.close(); httpClient.close(); } |
3.4.3.4 帶引數post請求
@Test public void doPostWithParam() throws Exception{ CloseableHttpClient httpClient = HttpClients.createDefault(); //建立一個post物件 HttpPost post = new HttpPost("http://localhost:8082/httpclient/post.html"); //建立一個Entity。模擬一個表單 List<NameValuePair>kvList = new ArrayList<>(); kvList.add(new BasicNameValuePair("username","zhangsan")); kvList.add(new BasicNameValuePair("password","123")); //包裝成一個Entity物件 StringEntity entity = new UrlEncodedFormEntity(kvList,"utf-8"); //設定請求的內容 post.setEntity(entity); //執行post請求 CloseableHttpResponse response =httpClient.execute(post); String string = EntityUtils.toString(response.getEntity()); System.out.println(string); response.close(); httpClient.close(); } |
3.4.4 Httpclient封裝成工具類
其他專案也可能會用到httpclient,所以把工具類放到taotao-common中。
public class HttpClientUtil { public static String doGet(String url, Map<String, String> param) { // 建立Httpclient物件 CloseableHttpClient httpclient = HttpClients.createDefault(); String resultString = ""; CloseableHttpResponse response = null; try { // 建立uri URIBuilder builder = new URIBuilder(url); if (param != null) { for (String key : param.keySet()) { builder.addParameter(key, param.get(key)); } } URI uri = builder.build(); // 建立http GET請求 HttpGet httpGet = new HttpGet(uri); // 執行請求 response = httpclient.execute(httpGet); // 判斷返回狀態是否為200 if (response.getStatusLine().getStatusCode() == 200) { resultString = EntityUtils.toString(response.getEntity(), "UTF-8"); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (response != null) { response.close(); } httpclient.close(); } catch (IOException e) { e.printStackTrace(); } } return resultString; } public static String doGet(String url) { return doGet(url, null); } public static String doPost(String url, Map<String, String> param) { // 建立Httpclient物件 CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = null; String resultString = ""; try { // 建立Http Post請求 HttpPost httpPost = new HttpPost(url); // 建立引數列表 if (param != null) { List<NameValuePair> paramList = new ArrayList<>(); for (String key : param.keySet()) { paramList.add(new BasicNameValuePair(key, param.get(key))); } // 模擬表單 UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList); httpPost.setEntity(entity); } // 執行http請求 response = httpClient.execute(httpPost); resultString = EntityUtils.toString(response.getEntity(), "utf-8"); } catch (Exception e) { e.printStackTrace(); } finally { try { response.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return resultString; } public static String doPost(String url) { return doPost(url, null); } public static String doPostJson(String url, String json) { // 建立Httpclient物件 CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = null; String resultString = ""; try { // 建立Http Post請求 HttpPost httpPost = new HttpPost(url); // 建立請求內容 StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON); httpPost.setEntity(entity); // 執行http請求 response = httpClient.execute(httpPost); resultString = EntityUtils.toString(response.getEntity(), "utf-8"); } catch (Exception e) { e.printStackTrace(); } finally { try { response.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return resultString; } } |
4 大廣告位展示
4.1 需求分析
需要建立一個json字串傳遞給jsp:使用EL表示式${ad1} 接收
Json字串如何傳遞給jsp:使用modelAndView物件把json字串傳遞給jsp。
如何獲得json字串:獲得一個廣告位對應的內容列表,需要呼叫taotao-rest的服務。把列表轉換成json資料格式要求的pojo物件列表。
需要使用httpclient呼叫taotao-rest的服務。
4.2 Dao層
沒有
4.3 Service層
根據內容分類id查詢分類的內容列表,需要使用httpclient呼叫taotao-rest的服務。得到一個json字串。需要把字串轉換成java物件taotaoResult物件。從taotaoResult物件中取data屬性,得到內容列表。把內容列表轉換成jsp頁面要求的json格式。返回一個json字串。
引數:沒有引數
返回值:json字串。
@Service public class ContentServiceImpl implements ContentService { @Value("${REST_BASE_URL}") private StringREST_BASE_URL; @Value("${REST_INDEX_AD_URL}") private StringREST_INDEX_AD_URL; @Override public String getContentList() { //呼叫服務層的服務 String result = HttpClientUtil.doGet(REST_BASE_URL +REST_INDEX_AD_URL); //把字串轉換成TaotaoResult try { TaotaoResult taotaoResult = TaotaoResult.formatToList(result, TbContent.class); //取內容列表 List<TbContent> list =(List<TbContent>) taotaoResult.getData(); List<Map> resultList =new ArrayList<>(); //建立一個jsp頁碼要求的pojo列表 for (TbContenttbContent : list) { Map map =new HashMap<>(); map.put("src",tbContent.getPic()); map.put("height", 240); map.put("width", 670); map.put("srcB",tbContent.getPic2()); map.put("widthB", 550); map.put("heightB", 240); map.put("href",tbContent.getUrl()); map.put("alt",tbContent.getSubTitle()); resultList.add(map); } return JsonUtils.objectToJson(resultList); } catch (Exceptione) { e.printStackTrace(); } returnnull; } } |
4.4 Controller
展示首頁返回一個邏輯檢視,需要把首頁大廣告位的json資料傳遞給jsp。
@RequestMapping("/index") public String showIndex(Modelmodel) { String adJson = contentService.getContentList(); model.addAttribute("ad1", adJson); return"index"; } |
效果