上文我们实现了展示后台页面的功能,而本文我们要实现的主要功能是展示商品列表,大家要是实现了该功能,点击查询商品
超链接,就能看到如下图所示的效果了。
下面我就来教大家如何实现展示商品列表这个功能。
如何分析商品列表展示页面呢?
我们知道,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,设置了它之后便默认把表格渲染成我们在最上方那张图所看到的表格样式。虽然不太好看,但是对于后台来说能用即可,美观并不是多么的重要。
1
2
3<table class="easyui-datagrid" id="itemList" title="商品列表" data-options="singleSelect:false,collapsible:true,pagination:true,url:'/item/list',method:'get',pageSize:30,toolbar:toolbar">
下面我对该<table>
标签作如下简要说明:
-
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代码中,如下所示:复制代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141var 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等等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<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>
我们再来看看商品表中的各个字段,发现与我们的表头里面定义的字段完全一致,这样才能自动将从数据库中查出来的数据赋值给相应的列进行显示。
现在我们来试着思考这样一个问题,当我们在浏览器地址栏中输入http://localhost:8081/
这样的url地址进行访问时,回车就能看到首页(即index.jsp)了,这时我们再点击查询商品
超链接,势必会发送一个请求,我们应该让请求转向item-list.jsp页面并且从数据库中查询出数据,转换成json返回给客户端,让datagrid进行局部刷新。由于要分页,因此还得传递page和rows这两个参数,它们分别表示当前页码(从1开始)和每页显示多少条记录。
说了这么多,那么我们服务端响应的数据格式应该是什么样子的呢?EasyUI中datagrid控件要求的数据格式应该是这样的:
1
2{total:"2",rows:[{"id":"1","name":"张三"},{"id":"2","name":"李四"}]}
返回过滤数据显示,该函数带一个参数data用来指向源数据(即获取的数据源,比如json对象)。您可以改变源数据的标准数据格式,但是这个函数必须返回包含total和rows属性的标准数据对象。
总觉得上面这段话,出现在这里有些突兀。反正这儿我们要知道rows当中的字段名称必须要和<table>
表格里面定义的字段名称一致。我们一般会采用用一个pojo类来返回前台所需要的数据的方式,而我们rows当中的json对象则一般是由Java对象转换而来,若是多个对象则就把一个集合转换为json串。
下面我们来新建一个这样的pojo类,例如EasyUIDataGridResult.java,由于这个pojo类有可能被多个服务所调用,因此我们把它放到taotao-common工程下,我们在该工程下新建一个com.taotao.common.pojo包,并在该包下新建一个EasyUIDataGridResult类,该类的代码如下图右侧所示,必须要引起我们注意的是,该类属性的名称必须叫toal和rows,另外由于rows集合中可能存放各种不同的对象,因此我们便不再使用泛型,直接用List表示rows属性的类型,表示它可以存放任意类型的对象。由于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-3.4.2-fix.jar这个jar包,如下图所示。
接下来我们开始在MyBatis的配置文件中配置该分页插件,如下图所示,这段配置的作用是根据不同的数据库采用不同的分页方法。
为方便大家复制,现把MyBatis的配置文件的内容贴出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14<?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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44package com.taotao.test.pagehelper; import java.util.List; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.taotao.mapper.TbItemMapper; import com.taotao.pojo.TbItem; import com.taotao.pojo.TbItemExample; public class TestPageHelper { @Test public void testHelper() { //2. 初始化Spring容器 ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-dao.xml"); //3. 获取Mapper的代理对象 TbItemMapper itemMapper = context.getBean(TbItemMapper.class); //1. 设置分页信息 PageHelper.startPage(1, 3);//3行,紧跟着的第一个查询才会被分页 //4. 调用Mapper的方法查询数据 TbItemExample example = new TbItemExample();//设置查询条件使用 List<TbItem> list = itemMapper.selectByExample(example);//这样写,表示没有设置任何条件,即select * from tb_item List<TbItem> list2 = itemMapper.selectByExample(example);//这样写,表示没有设置任何条件,即select * from tb_item //取分页信息 PageInfo<TbItem> info = new PageInfo<TbItem>(list); System.out.println("第一个分页的list的集合长度:" + list.size()); System.out.println("第一个分页的list2的集合长度:" + list2.size());//这里说明了第二个查询不会被分页 //5. 遍历结果集并打印 System.out.println("查询的总记录数:" + info.getTotal()); for (TbItem tbItem : list) { System.out.println(tbItem.getId() + ">>>名称>>>" + tbItem.getTitle()); } } }
这里,我还没资格为大家讲解PageHelper分页插件的源码,如果同学有兴趣,可以自己尝试着去查阅源码,这就很考大家的能力了。下面我们来正式编码实现商品列表查询这个功能。
没讲完,这里我还有一点需要说明一下,如果你此时安装taotao-manager-service工程,那么便会发现该工程下的测试类运行了,Eclipse控制台打印出了如下内容,虽然乱码显示。
你会不会觉得很烦呢?安装工程就安装工程嘛!为什么还要运行其中的测试类呢?如果你想在安装工程时跳过测试,那么可以使用一个打包时跳过测试的插件,即maven-surefire-plugin。因此,我们需要在taotao-manager-service工程的pom文件中添加该插件的配置,如下图所示。
这时,再次安装该工程,便不会运行该工程下的测试类了。
实现商品列表查询功能
首先我们需要在taotao-manager-interface工程的ItemService接口中添加一个方法,如下图所示。
然后我们需要在taotao-manager-service工程的ItemServiceImpl实现类中实现该接口,如下图所示。
接着我们来编写Controller类中的代码,如下图所示,我们在ItemController类中添加一个获取商品列表的方法,并且返回值要是EasyUIDataGridResult类型。
写完了代码之后,由于我们在taotao-common工程当中添加了一个pojo,在taotao-manager-interface工程中添加了一个接口,因此这两个工程都需要打包到本地仓库。
最后,我们要启动工程了,记住一个原则,即要先启动服务端,再启动客户端。这是为什么呢?因为你服务端没启动,客户端去注册中心查找服务,是不能找到的,找不到服务就会抛异常。所以,我们通常应该先启动taotao-manager工程,然后再启动taotao-manager-web工程,接着访问http://localhost:8081
并点击查询商品
超链接,如若你可以看到如下图所示界面,则说明我们成功进行分页查询了。
不过,这时我们会发现Eclipse控制台打印出了如下警告。
这个警告我们不用管它,商品列表能分页查询就行。至于出现这个警告的原因就是我们客户端这边没有服务端的类,即com.github.pagehelper.Page。
最后
以上就是犹豫香菇最近收集整理的关于淘淘商城第21讲——MyBatis分页插件(PageHelper)的使用以及商品列表的展示如何分析商品列表展示页面呢?MyBatis分页插件(PageHelper)实现商品列表查询功能的全部内容,更多相关淘淘商城第21讲——MyBatis分页插件(PageHelper)内容请搜索靠谱客的其他文章。
发表评论 取消回复