一、商品列表功能
商品列表功能是后端维护购物网站的商品的功能,提供了显示、新增、编辑、删除、下架和上架功能,显示如下:
二、显示功能的实现
打开查询商品后,后端首先按照分页刷新出商品的信息,因此显示功能是第一步。
2.1 前端代码实现
前端代码的实现上主要包括界面显示和访问动作两项。界面显示采用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"> <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> </table>
控件附带的动作为“GET”,url为“/item/list”,且附带参数为“page=1&rows=30”
页数随着数据网格下方的页码变化,前端发生翻页动作时,向后端重新发送请求,这需要后端进行处理。
2.2 后端代码实现
与前端代码对应,后端需要对“/item/list?page=1&rows=30”的url做出相应,分为如下步骤:
1. 在priv.ality.common中创建pojo对象,用于定义EasyUIDataGrid的数据对象,数据获取和更新时都会用到。
package priv.ality.utils; import java.util.List; public class EasyUIDataGridResult { private long total; private List rows; public long getTotal() { return total; } public void setTotal(long total) { this.total = total; } public List getRows() { return rows; } public void setRows(List rows) { this.rows = rows; } }
该类中包含了EasyUIDataGrid中需要用到的数据和数据长度。
2. 在priv.ality.service.ItemService中声明数据更新方法getItemList
package priv.ality.service; import priv.ality.pojo.TbItem; import priv.ality.utils.EasyUIDataGridResult; import java.util.List; public interface ItemService { TbItem getItemById(Long itemId); EasyUIDataGridResult getItemList(int page, int rows); }
3. 在priv.ality.service.impl.ItemServiceImpl类中添加方法的实现:
@Override public EasyUIDataGridResult getItemList(int page, int rows) { //分页处理 PageHelper.startPage(page, rows); //执行查询 TbItemExample example = new TbItemExample(); Listlist = itemMapper.selectByExample(example); //取分页信息 PageInfo pageInfo = new PageInfo<>(list); //返回处理结果 EasyUIDataGridResult result = new EasyUIDataGridResult(); result.setTotal(pageInfo.getTotal()); result.setRows(list); return result; }
该方法使用了PageHelper库提供Mybatis的分页功能,并使用EasyUIDataGrid对象作为返回值返回给DataGrid控件,由控件进行抽取和
4. 在priv.ality.controller中添加对URL“/item/list”的处理
@RequestMapping("/item/list") @ResponseBody private EasyUIDataGridResult getItemList(Integer page, Integer rows) { return itemService.getItemList(page, rows); }
controller中通过调用itemService中的getItemList方法提供数据完成功能。
三、新增功能
商品列表除了基本的显示功能之外,还提供数据的增删查改,有一个工具栏“商品列表”用以提供快捷操作:
商品列表的源码如下:
var toolbar = [{ text:'新增', iconCls:'icon-add', handler:function(){ ; } },{ text:'编辑', iconCls:'icon-edit', handler:function(){ ; } },{ text:'删除', iconCls:'icon-cancel', handler:function(){ ; } },'-',{ text:'下架', iconCls:'icon-remove', handler:function(){ ; } },{ text:'上架', iconCls:'icon-remove', handler:function(){ ; } }];
当前代码只包含了显示样式,本篇文章只涉及“新增功能"
新增功能与Menu-Tree中的功能保持一致,当点击“新增”按钮时,页面跳转到“新增商品”页面:
跳转过程的代码(即“商品列表”中“新增”工具的代码)如下:
{ text:'新增', iconCls:'icon-add', handler:function(){ $(".tree-title:contains('新增商品')").parent().click(); } }
$(".tree-title:contains('新增商品')").parent().click();
如上提供了跳转到“新增商品”的操作,下面分析该操作。
“新增商品”页见上,页面主要实现的内容有:
1. 商品类目的选择2. 商品标题、价格和数量的必选项设置3. 商品图片的上传4. 富文本商品描述
首先给出新增商品页的布局代码:
<p style="padding:10px 10px 10px 10px"> <form id="itemAddForm" class="itemForm" method="post"> <table cellpadding="5"> <tr> <td>商品类目:</td> <td> <a href="javascript:void(0)" class="easyui-linkbutton selectItemCat">选择类目</a> <input type="hidden" name="cid" style="width: 280px;"></input> </td> </tr> <tr> <td>商品标题:</td> <td><input class="easyui-textbox" type="text" name="title" data-options="required:true" style="width: 280px;"></input></td> </tr> <tr> <td>商品卖点:</td> <td><input class="easyui-textbox" name="sellPoint" data-options="multiline:true,validType:'length[0,150]'" style="height:60px;width: 280px;"></input></td> </tr> <tr> <td>商品价格:</td> <td><input class="easyui-numberbox" type="text" name="priceView" data-options="min:1,max:99999999,precision:2,required:true" /> <input type="hidden" name="price"/> </td> </tr> <tr> <td>库存数量:</td> <td><input class="easyui-numberbox" type="text" name="num" data-options="min:1,max:99999999,precision:0,required:true" /></td> </tr> <tr> <td>条形码:</td> <td> <input class="easyui-textbox" type="text" name="barcode" data-options="validType:'length[1,30]'" /> </td> </tr> <tr> <td>商品图片:</td> <td> <a href="javascript:void(0)" class="easyui-linkbutton picFileUpload">上传图片</a> <input type="hidden" name="image"/> </td> </tr> <tr> <td>商品描述:</td> <td> <textarea style="width:800px;height:300px;visibility:hidden;" name="desc"></textarea> </td> </tr> <tr class="params hide"> <td>商品规格:</td> <td> </td> </tr> </table> <input type="hidden" name="itemParams"/> </form> <p style="padding:5px"> <a href="javascript:void(0)" class="easyui-linkbutton" onclick="submitForm()">提交</a> <a href="javascript:void(0)" class="easyui-linkbutton" onclick="clearForm()">重置</a> </p> </p>
下面依次对四个方面进行实现。
四、新增功能的实现
4.1 商品类目
前端代码
商品类目的前端布局代码如下:
<tr> <td>商品类目:</td> <td> <a href="javascript:void(0)" class="easyui-linkbutton selectItemCat">选择类目</a> <input type="hidden" name="cid" style="width: 280px;"></input> </td> </tr>
该布局中“选择商品”的属性为“easyui-linkbutton”,该按钮并没有注册OnClick事件,而是注册一个为“selectItemCat”的样式,该样式由/js/common.js中,定义如下:
// 初始化选择类目组件 initItemCat : function(data){ $(".selectItemCat").each(function(i,e){ var _ele = $(e); if(data && data.cid){ _ele.after("<span style='margin-left:10px;'>"+data.cid+"</span>"); }else{ _ele.after("<span style='margin-left:10px;'></span>"); } _ele.unbind('click').click(function(){ $("<p>").css({padding:"5px"}).html("<ul>") .window({ width:'500', height:"450", modal:true, closed:true, iconCls:'icon-save', title:'选择类目', onOpen : function(){ var _win = this; $("ul",_win).tree({ url:'/item/cat/list', animate:true, onClick : function(node){ if($(this).tree("isLeaf",node.target)){ // 填写到cid中 _ele.parent().find("[name=cid]").val(node.id); _ele.next().text(node.text).attr("cid",node.id); $(_win).window('close'); if(data && data.fun){ data.fun.call(this,node); } } } }); }, onClose : function(){ $(this).window("destroy"); } }).window('open'); }); }); },
该样式类selectItemCat使用each对所有绑定该事件的样式循环初始化,在该类首先对click事件进行解绑,然后绑定方法function:
$("<p>").css({padding:"5px"}).html("<ul>") window({ width:'500', height:"450", modal:true, closed:true, iconCls:'icon-save', title:'选择类目', onOpen : function(){ var _win = this; $("ul",_win).tree({ url:'/item/cat/list', animate:true, onClick : function(node){ if($(this).tree("isLeaf",node.target)){ // 填写到cid中 _ele.parent().find("[name=cid]").val(node.id); _ele.next().text(node.text).attr("cid",node.id); $(_win).window('close'); if(data && data.fun){ data.fun.call(this,node); } } } }); }, onClose : function(){ $(this).window("destroy"); } ).window('open');
该动作创建并打开一个模态窗口,该窗口的打开动作中进行AJAX请求向服务器请求数据,并将数据填充到easy-ui的异步树形控件中,设定url为'/item/cat/list',这也需要服务器端对该URL进行相应。
easy-ui中的异步tree控件初始化时首先读取当前树的节点,当展开一个封闭的节点时如果节点未曾加载,则在url中添加请求参数:节点ID,然后向服务器发起请求,服务器端进行相应时为JSON数据,且具备结构要求:
[{ "id": 1, "text": "Node 1", "state": "closed" } { "id": 2, "text": "Node 2", "state": "closed" } ]
state的值要求如下:如果当前节点为父节点,state应为“closed”、如果是叶子节点则应该为“open”。
前端代码分析完毕,对于JQuery的API熟练度不够,还没发自己写出来一个=_=!
后端代码
1. 创建EasyUITreeNode这个pojo对象
EasyUITreeNode用于定义树形节点的各个节点数据,由于类比较基础,放置在ality-common工程中:
public class EasyUITreeNode { private long id; private String text; private String state; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getText() { return text; } public void setText(String text) { this.text = text; } public String getState() { return state; } public void setState(String state) { this.state = state; } }
2. 创建ItemCatService接口,代表商品添加相关的服务
package priv.ality.service; import priv.ality.utils.EasyUITreeNode; import java.util.List; public interface ItemCatService { public ListgetItemCatList(long parentId); }
该服务的方法getItemCatList使用参数parentId对应前端分析的url中带来的参数,返回值为EasyUITreeNode的List对象。
3. 创建该接口的实现ItemCatServiceImpl:
package priv.ality.service.impl; import org.springframework.beans.factory.annotation.Autowired; import priv.ality.mapper.TbItemCatMapper; import priv.ality.pojo.TbItemCat; import priv.ality.pojo.TbItemCatExample; import priv.ality.service.ItemCatService; import priv.ality.utils.EasyUITreeNode; import java.util.ArrayList; import java.util.List; public class ItemCatServiceImpl implements ItemCatService { @Autowired private TbItemCatMapper itemCatMapper; @Override public ListgetItemCatList(long parentId) { // 根据parentId查询分类列表 TbItemCatExample example = new TbItemCatExample(); //设置查询条件 TbItemCatExample.Criteria criteria = example.createCriteria(); criteria.andParentIdEqualTo(parentId); //执行查询 List list = itemCatMapper.selectByExample(example); //转换成EasyUITreeNode列表 List resultList = new ArrayList<>(); for (TbItemCat tbItemCat : list) { //创建一个节点对象 EasyUITreeNode node = new EasyUITreeNode(); node.setId(tbItemCat.getId()); node.setText(tbItemCat.getName()); node.setState(tbItemCat.getIsParent()?"closed":"open"); //添加到列表中 resultList.add(node); } return resultList; } }
该实现中使用Example对象和Criteria对象设置查询条件,获取了ParentId等于入参的所有结果,并按照异步Tree要求的格式进行封装后返回结果。
4. 在Controller中添加方法接受参数并返回结果(JSON数据)。
package priv.ality.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import priv.ality.service.ItemCatService; import priv.ality.utils.EasyUITreeNode; import java.util.List; @Controller @RequestMapping("/item/cat") public class ItemCatController { @Autowired private ItemCatService itemCatService; @RequestMapping("/list") @ResponseBody public ListgetItemCatList(@RequestParam(value="id",defaultValue = "0")Long parentId){ return itemCatService.getItemCatList(parentId); } }
功能完成结果如下:
如上可见,商品类目选择功能已经得到实现。
ps:入职新公司,技术栈发生变更,由JavaWeb转大数据方向,语言转向Ruby和Node.js,所以下面就暂时暂停更新这个系列的文章啦,有的闲工夫再来~