http://blog.csdn.net/yerenyuan_pku/article/details/72774381
上文我們實現了展示后台頁面的功能,而本文我們實現的主要功能是展示商品列表,大家要是實現了該功能,點擊查詢商品
超鏈接,就能看到如下所示結果:
下面我就來教大家如何實現展示商品列表這個功能。
我們知道,EasyUI的最大特點便是局部刷新,所有展示都是分模塊展示的,不像我們一般頁面采用全部刷新。查詢商品是index.jsp中的一個模塊展示而已,我們下面來看下index.jsp頁面代碼,如下圖所示。可以看到,當我們點擊查詢商品這個鏈接的時候實際上是去訪問item-list這么一個邏輯視圖。
然后我們再來看下item-list.jsp頁面代碼,如下圖所示,我們可以看到這個頁面代碼只是有個table和一個div,並沒有文件頭和尾,因此這不是一個完整的頁面,而只是一個片段而已(它是index.jsp的一個代碼片段而已,而EasyUI的特點便是對這樣的代碼塊進行刷新,而不會刷新其它模塊)。
從上面可看出item_list.jsp頁面並不是一個完整的html,如果是一個完整的html,它應該是以<html>
開頭,以</html>
結尾,除了index.jsp是一個完整的html之外,你會發現其他的jsp頁面都是一個html的片段,因為EasyUI其實就是一個單頁面功能,EasyUI這里面所有的動作都是在一個html中完成的,它加載的這些jsp頁面,都只是加載一個片段,然后把這個片段再添加到當前頁面中。這就是我們通常所說的頁面優化,大家是不是又學到一個技能點?
下面我們再具體看下item-list.jsp這個頁面的代碼,首先看下<table>
頭信息,如下所示,可以看到,table的class設置成了”easyui-datagrid”,設置了它之后便默認把表格渲染成我們在最上方那張圖所看到的表格樣式。雖然不太好看,但是對於后台來說能用即可,美觀並不是多么重要。
<table class="easyui-datagrid" id="itemList" title="商品列表" data-options="singleSelect:false,collapsible:true,pagination:true,url:'/item/list',method:'get',pageSize:30,toolbar:toolbar">
- data-options中
singleSelect:false
表示可以多選,如果想要實現只能選擇一條記錄的效果,可以把singleSelect的值設置為true。 collapsible:true
所代表的意思是是否顯示折疊按鈕,如下圖最右邊紅色框圈住的按鈕。
如果把collapsible的值設置為false,那么這個按鈕將不再顯示。pagination:true
代表的意思是要顯示分頁,如果不想分頁就把該值設置為false。url:'/item/list'
的意思是我們初始化商品列表請求的url。method:'get'
表示請求方式是GET。pageSize:30
表示每頁顯示30條記錄,我們從有分頁信息的圖中可以看到”30”的信息,就是這里設置的值。-
toolbar:toolbar
指定工具欄,如上圖的”新增”、”編輯”、”刪除”、”下架”、”上架”這些菜單。toolbar是由js定義的,代碼就在item-list.jsp頁面下方的js部分,如下所示:var toolbar = [{ text:'新增', iconCls:'icon-add', handler:function(){ $(".tree-title:contains('新增商品')").parent().click(); } },{ text:'編輯', iconCls:'icon-edit', handler:function(){ var ids = getSelectionsIds(); if(ids.length == 0){ $.messager.alert('提示','必須選擇一個商品才能編輯!'); return ; } if(ids.indexOf(',') > 0){ $.messager.alert('提示','只能選擇一個商品!'); return ; } $("#itemEditWindow").window({ onLoad :function(){ //回顯數據 var data = $("#itemList").datagrid("getSelections")[0]; data.priceView = TAOTAO.formatPrice(data.price); $("#itemeEditForm").form("load",data); // 加載商品描述 $.getJSON('/rest/item/query/item/desc/'+data.id,function(_data){ if(_data.status == 200){ //UM.getEditor('itemeEditDescEditor').setContent(_data.data.itemDesc, false); itemEditEditor.html(_data.data.itemDesc); } }); //加載商品規格 $.getJSON('/rest/item/param/item/query/'+data.id,function(_data){ if(_data && _data.status == 200 && _data.data && _data.data.paramData){ $("#itemeEditForm .params").show(); $("#itemeEditForm [name=itemParams]").val(_data.data.paramData); $("#itemeEditForm [name=itemParamId]").val(_data.data.id); //回顯商品規格 var paramData = JSON.parse(_data.data.paramData); var html = "<ul>"; for(var i in paramData){ var pd = paramData[i]; html+="<li><table>"; html+="<tr><td colspan=\"2\" class=\"group\">"+pd.group+"</td></tr>"; for(var j in pd.params){ var ps = pd.params[j]; html+="<tr><td class=\"param\"><span>"+ps.k+"</span>: </td><td><input autocomplete=\"off\" type=\"text\" value='"+ps.v+"'/></td></tr>"; } html+="</li></table>"; } html+= "</ul>"; $("#itemeEditForm .params td").eq(1).html(html); } }); TAOTAO.init({ "pics" : data.image, "cid" : data.cid, fun:function(node){ TAOTAO.changeItemParam(node, "itemeEditForm"); } }); } }).window("open"); } },{ text:'刪除', iconCls:'icon-cancel', handler:function(){ var ids = getSelectionsIds(); if(ids.length == 0){ $.messager.alert('提示','未選中商品!'); return ; } $.messager.confirm('確認','確定刪除ID為 '+ids+' 的商品嗎?',function(r){ if (r){ var params = {"ids":ids}; $.post("/rest/item/delete",params, function(data){ if(data.status == 200){ $.messager.alert('提示','刪除商品成功!',undefined,function(){ $("#itemList").datagrid("reload"); }); } }); } }); } },'-',{ text:'下架', iconCls:'icon-remove', handler:function(){ var ids = getSelectionsIds(); if(ids.length == 0){ $.messager.alert('提示','未選中商品!'); return ; } $.messager.confirm('確認','確定下架ID為 '+ids+' 的商品嗎?',function(r){ if (r){ var params = {"ids":ids}; $.post("/rest/item/instock",params, function(data){ if(data.status == 200){ $.messager.alert('提示','下架商品成功!',undefined,function(){ $("#itemList").datagrid("reload"); }); } }); } }); } },{ text:'上架', iconCls:'icon-remove', handler:function(){ var ids = getSelectionsIds(); if(ids.length == 0){ $.messager.alert('提示','未選中商品!'); return ; } $.messager.confirm('確認','確定上架ID為 '+ids+' 的商品嗎?',function(r){ if (r){ var params = {"ids":ids}; $.post("/rest/item/reshelf",params, function(data){ if(data.status == 200){ $.messager.alert('提示','上架商品成功!',undefined,function(){ $("#itemList").datagrid("reload"); }); } }); } }); } }];
看完了<table>
里面的屬性,下面我們來看下表頭的代碼,其中<thead>
表示表頭,<tr>
表示一行,<th>
表示一列。我們可以看到第一列是復選框,字段名稱為”ck”,商品ID的字段名稱是”id”,商品標題的字段名稱為’title”等等。
<thead> <tr> <th data-options="field:'ck',checkbox:true"></th> <th data-options="field:'id',width:60">商品ID</th> <th data-options="field:'title',width:200">商品標題</th> <th data-options="field:'cid',width:100">葉子類目</th> <th data-options="field:'sellPoint',width:100">賣點</th> <th data-options="field:'price',width:70,align:'right',formatter:TAOTAO.formatPrice">價格</th> <th data-options="field:'num',width:70,align:'right'">庫存數量</th> <th data-options="field:'barcode',width:100">條形碼</th> <th data-options="field:'status',width:60,align:'center',formatter:TAOTAO.formatItemStatus">狀態</th> <th data-options="field:'created',width:130,align:'center',formatter:TAOTAO.formatDateTime">創建日期</th> <th data-options="field:'updated',width:130,align:'center',formatter:TAOTAO.formatDateTime">更新日期</th> </tr> </thead>
- 1
我們再看看商品表各個字段,發現與我們的表頭里面定義的字段完全一致,這樣才能自動將從數據庫查出來的數據賦值給相應的列進行顯示。
現在我們試着思考這樣一個問題,當我們在瀏覽器地址欄中輸入http://localhost:8080/
url地址,回車就能看到首頁——index.jsp,這時我們點擊查詢商品
超鏈接,勢必會發送一個請求,我們應該讓請求轉向item-list.jsp頁面並且從數據庫查詢出數據,轉換成json返回給客戶端,讓datagrid進行局部刷新。由於要分頁,因此還要傳遞page和rows,它們分別表示當前頁碼(從1開始)和每頁顯示多少條記錄。那么,我們服務端響應的數據格式應該是什么樣子的呢?EasyUI中datagrid控件要求的數據格式為:
{total:"2",rows:[{"id":"1","name":"張三"},{"id":"2","name":"李四"}]}
返回過濾數據顯示,該函數帶一個參數”data”用來指向源數據(即:獲取的數據源,比如json對象)。您可以改變源數據的標准數據格式,但是這個函數必須返回包含total和rows屬性的標准數據對象。
總覺得上面這段話,出現在這里有些突兀。這兒我們要知道rows當中的字段名稱必須要和<table>
表格里面定義的字段名稱一致。我們一般采用用一個pojo類來返回前台所需要的數據的方式,而我們rows當中的json數據則一般是由Java對象轉換而來,多個對象的話就把一個集合轉換為json串。
下面我們來新建一個pojo類——EasyUIDataGridResult,由於這個pojo類有可能被多個服務所調用,因此我們把它放到taotao-common工程下,我們在該工程下新建一個com.taotao.common.pojo包,並在該包下新建一個EasyUIDataGridResult類,該類的代碼如下圖右側所示,必須注意的是,屬性的名稱必須叫toal和rows,另外由於rows集合可能是各種不同的對象,因此我們便不再使用泛型,直接用List表示類型,它可以存放任意類型的對象。由於pojo要在服務端和客戶端之間進行傳輸,因此一定要實現序列化接口。
上面分析完了之后,下面我來講講MyBatis分頁插件——PageHelper。
MyBatis分頁插件——PageHelper
在實現商品列表展示這個功能的過程中,我們肯定是需要進行商品分頁查詢的。很不幸的是,我們使用逆向工程生成的mapper文件(比如TbItemMapper.xml)中是是不支持分頁處理的,那么我們怎么實現分頁功能呢?
- 大家可以自己手工修改mapper文件,使其可以分頁,這種方式比較麻煩,因為當生成的mapper文件很多時,一個一個的改又是一個耗時的工程,而且還容易出錯。
- 就是不修改mapper文件,使用MyBatis提供的一個分頁插件——PageHelper來實現分頁,這種方法當然是我們的首選了。
如果你也在用MyBatis,建議嘗試該分頁插件,這個一定是最方便使用的分頁插件。PageHelper分頁插件目前支持:Oracle、MySQL、MariaDB(其實只是MySQL的一個分支而已)、SQLite、Hsqldb、PostgreSQL六種數據庫。
我們使用的PageHelper分頁插件版本是3.4.2-fix,這個版本從中央倉庫是下載不到的,這是經過好事者修改過的版本,MyBatis官方提供的分頁插件在無條件分頁查詢的時候沒問題,但是當有條件進行分頁查詢的時候會拋異常(即官方提供的分頁插件對逆向工程支持得並不好),因此好事者做了修改,命名為了3.4.2-fix版本,我們目前只需要會使用就可以了,等我們學會熟練使用了,能夠很好的閱讀源碼了,便可以看看哪些做了修改。
我們怎么使用這個修改后的分頁插件呢?導入如下修改過后的maven工程——pagehelper到Eclipse中。
由於我們使用的jdk版本是1.7,所以我們並不需要修改pom.xml文件中build定義的jdk版本。當然了,要是你使用得jdk版本更高,比如是jdk1.8,那你就要修改了。
接下來我們就要對該工程進行maven打包了,要打包到本地maven倉庫中,如下:
接下來我們開始在mybatis的配置文件中配置分頁插件,如下圖所示,這段配置的作用是根據不同的數據庫采用不同的分頁方法。
為方便大家復制,把mybatis的配置文件的內容貼出如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <plugins> <!-- com.github.pagehelper為PageHelper類所在包名 --> <plugin interceptor="com.github.pagehelper.PageHelper"> <!-- 設置數據庫類型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六種數據庫--> <property name="dialect" value="mysql"/> </plugin> </plugins> </configuration>
- 1
下面新建一個測試類來測試一下分頁是否好使,如下圖所示。發現是可以正常進行分頁查詢的。
為方便大家復制代碼,這里把測試類的代碼粘貼出來,如下所示。
public class TestPageHelper { @Test public void testPageHelper() { // 初始化Spring容器 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-dao.xml"); // 從容器中獲得mapper代理對象 TbItemMapper itemMapper = applicationContext.getBean(TbItemMapper.class); // 執行查詢 TbItemExample example = new TbItemExample(); // 查詢之前進行分頁處理 PageHelper.startPage(1, 30); // 注意,分頁插件僅對最近的這一次查詢有效,下一次查詢就無效了。怎么實現的呢?使用了LocalThread。 List<TbItem> list = itemMapper.selectByExample(example); // 取分頁信息 System.out.println("結果集中的記錄數:" + list.size()); PageInfo<TbItem> pageInfo = new PageInfo<>(list); System.out.println("總記錄數:" + pageInfo.getTotal()); System.out.println("總頁數:" + pageInfo.getPages()); } }
- 1
這里,我還沒資格為大家講解PageHelper的源碼,如果同學有興趣,可以自己嘗試着去查閱源碼,這就很考大家的能力了。下面我們來實現商品列表查詢功能。
商品列表查詢
首先我們需要在taotao-manager-interface的接口中添加一個方法,如下圖所示。
接下來我們需要在taotao-manager-service的實現類中實現該接口,如下圖所示。
下面我們來寫Controller類的代碼,如下圖所示,我們在ItemController當中添加一個獲取商品列表的方法,返回值是EasyUIDataGridResult類。
寫完了代碼,由於我們在taotao-common當中添加了一個pojo,在taotao-manager-interface添加一個接口,因此這兩個工程都需要打包到本地倉庫。
最后,我們要啟動工程了,記住一個原則,即要先啟動服務端,再啟動客戶端。這是為什么呢?因為你服務端沒啟動,客戶端去注冊中心查找服務,是不能找到的,找不到服務就會拋異常。所以,我們應該先啟動taotao-manager工程,再啟動taotao-manager-web工程,然后訪問http://localhost:8081
並點擊查詢商品
,可以看到如下圖所示界面,說明我們成功進行分頁查詢了。
這時我們會發現Eclipse控制台有如下警告:
這個警告我們不用管它,商品列表能分頁查詢就行。至於出現這個警告的原因就是我們客戶端這邊沒有服務端的類——com.github.pagehelper.Page。