Komponen jadual asli Bootstrap hanya boleh memenuhi paparan data ringkas, tetapi tidak dapat memenuhi keperluan operasi yang lebih banyak. Sudah tentu, anda boleh mencari komponen jadual berasaskan bootstrap yang dipanggil "DataTables-1.10.11", tetapi jika anda tidak mengetahui API dengan baik, ia akan menyakitkan untuk digunakan, tetapi jika anda memilih untuk menggunakan jqGrid, maka Tutorial ini membawakan anda penyelesaian kepada jadual operasi yang kaya ini.
1. Paparan kesan
OK, mari tunjukkan gambar ini Saya percaya anda telah jatuh cinta dengan versi bootstrap jqGrid Ia sangat serasi dengan bootstrap dan sudah tentu, ini memerlukan kita membuat beberapa perubahan pada jqGrid dan pada pada masa yang sama mengubah suai komponen tertentu.
2. Muat turun sumber
Bagaimanapun, saya suka berkongsi kod komponen jqGrid, anda boleh memuat turunnya dari laman web rasmi jqGrid, bagaimanapun, beberapa perubahan diperlukan selepas memuat turun, jadi saya terus memuat naik jqGrid yang telah diubah suai. Anda hanya perlu menambah yang disediakan Hanya import fail ke dalam projek anda yang sepadan.
Selain itu, anda juga perlu memuat turun jquery-ui-1.10.0.custom.css Saya tidak akan memberikan alamat muat turun, tetapi saya percaya anda pasti akan menemuinya, walaupun anda gunakan kekerapan Anda juga boleh mencari Du Niang yang telah mengalami kemalangan.
3. Artikel ini tentang apa? Sejak saya menubuhkan kumpulan QQ, terdapat "aliran tidak berkesudahan" rakan sekelas yang menyertai kumpulan itu, tetapi saya juga mendapati bahawa orang yang menyertai kumpulan itu datang terus kepada saya meminta demo atau kod projek yang saya tidak suka ini. Cubalah, laksanakan yang berikut, dan buat beberapa perubahan untuk menjadikannya milik anda. Jelas sekali anda tidak akan mendapat bantuan lagi dengan menyalin kod saya sepenuhnya. Saya harap pelajar di atas akan lebih proaktif.
Selepas bercakap tentang perkara karut di atas, mari kita kembali kepada perniagaan dan bercakap tentang apa yang utama untuk membenamkan jqGrid dalam bootstrap:
skim susun atur jqGrid dalam bootstrap parameter struktur jqGrid sendiri Operasi data jqGrid modular jqGrid dalam bootstrap
Penjelasan secara tentatif dibahagikan kepada bahagian di atas, tetapi perlu diingatkan bahawa disebabkan keterbatasan ruang, hanya idea dan sebahagian daripada kod disediakan dalam blog.
①, pelan susun atur jqGrid dalam bootstrap
<!DOCTYPE html> <html lang="zh-CN"> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ include file="/components/common/taglib.jsp"%> <%@ include file="/components/common/csslib.jsp"%> <head> <link type="text/css" rel="stylesheet" href="${ctx}/css/deal/my_pay_list.css" /> </head> <body> <div class="container"> <form class="form-horizontal" id="jqgridForm" role="form" action="${ctx}/deal/datablePayDealOrdersList" method="post"> <div class="form-group"> <div class="col-sm-12"> <label for="name" class="control-label pull-left">项目名称:</label> <div class="col-sm-3"> <input type="text" name="name" class="form-control" id="name" placeholder="请输入项目名称" value="" /> </div> </div> </div> <div class="form-group"> <div class="col-sm-12"> <button type="button" class="btn btn-primary pull-right" id="searchBtn">检索</button> </div> </div> <div class="form-group"> <div class="col-sm-12"> <table id="pageGrid" rel="jqgridForm" class="jqgrid"></table> <div id="pageGridPager"></div> </div> </div> </form> </div> <%@ include file="/components/common/jslib.jsp"%> <script type="text/javascript" src="${ctx}/js/deal/my_pay_list.js"></script> </body> </html>
, di sini kami menyertakan borang borang dengan lapisan syarat carian untuk jqGrid, iaitu bahagian carian yang disenaraikan pada pemaparan Apabila butang carian diklik, syarat pertanyaan medan borang diserahkan kepada pengawal dan kemudian mendapatkan data.
, mentakrifkan butang carian, yang akan digunakan kemudian apabila kita bercakap tentang modularisasi. id="jqgridForm"
Tentukan elemen jadual jqGrid dan elemen pengaki jqGrid Peraturan yang digunakan dipersetujui buat sementara waktu dalam projek saya. Anda juga boleh mempunyai peraturan anda sendiri. Dengan menyatakan id borang melalui rel, anda boleh menggunakan jadual dengan lebih mudah untuk mendapatkan semula borang. ②. Parameter struktur jqGrid sendiriid="searchBtn"
<table id="pageGrid" rel="jqgridForm" class="jqgrid"></table> <div id="pageGridPager"></div>
$(function() { var jqOption = { datatype : "xml", mtype : "POST", shrinkToFit : true, viewrecords : false, rownumbers : false, autowidth : true, height : "100%", colNames : [ 'id', 'status', '项目信息', '项目状态', '订单号', '项目名称', '下单时间', '支付金额', '支持数量', '订单状态', '操作' ], colModel : [ { name : 'id', index : 'id', hidden : true }, { name : 'status', index : 'status', hidden : true }, { name : 'image_str', index : 'image_str', width : 140, resizable : false, sortable : false, formatter : function(cellvalue, options, rowObject) { if (cellvalue == '支付总花费:') { return cellvalue; } }, align : 'left' }, { name : 'oper', index : 'oper', width : 90, resizable : false, sortable : false, align : 'center', formatter : function(cellvalue, options, rowObject) { var status = parseInt($(rowObject).find("status").text()); var id = $(rowObject).find("id").text(); if (status == 0) { return '<a class="color0088cc" width="700" target="dialog" href="' + common.ctx + '/deal/initPayg/' + id + '">去支付</a>'; } if (status == 1 || status == 3) { return '<a class="color0088cc" target="_blank" href="' + common.ctx + '/deal/showDealOr/' + id + '">查看详情</a>'; } if (status == 2) { return '<a class="color0088cc" target="ajaxTodo" href="' + common.ctx + '/deal/receivder/' + id + '">确认收货</a>'; } }, } ], xmlReader : { repeatitems : false, root : "PageGrid", row : "map", page : 'page', total : 'total', records : 'records', id : 'ID' }, rowNum : 50, rowList : [ 50, 100, 200, 300 ], pager : "#pageGridPager", footerrow : true, loadError : YUNM.ajaxError, gridComplete : function() { var $form = $("#" + $("#pageGrid").attr("rel")); $.ajax({ type : $form.method || 'POST', url : common.ctx + "/deal/getAllOrded", data : $form.serializeArray(), dataType : "json", cache : false, success : function(json) { $("#pageGrid").footerData("set", { image_str : "支付总花费:", order_price : json.message }); }, error : YUNM.ajaxError }); if ($.fn.ajaxTodo) { $("a[target=ajaxTodo]", $("#pageGrid")).ajaxTodo(); } // dialog if ($.fn.ajaxTodialog) { $("a[target=dialog]", $("#pageGrid")).ajaxTodialog(); } }, }; initEnv(jqOption); });
Terdapat banyak atribut yang disenaraikan dalam fail di atas Saya tidak akan memperkenalkan terlalu banyak tentang jqGrid perkenalkan beberapa perkara penting:
, pemformat masih digunakan dengan kerap, jadi cara untuk mendapatkan nilai sel yang sepadan adalah sangat penting jqGrid saya menggunakan format data xml (datatype: "xml"), kemudian anda boleh lulus Cari nilai yang sepadan dengan lajur deal_id. formatter: function(cellvalue, options, rowObject) {
, perhatikan nilai parameter dalam xmlReader Operasi data ④jqGrid akan diperkenalkan secara terperinci seterusnya, yang berkaitan dengan enkapsulasi data xml latar belakang. $(rowObject).find("deal_id").text()
, Mengenai kaedah footerData, ia juga sangat mudah digunakan untuk kesannya, sila rujuk pada rendering. Kaedah xmlReader : { repeatitems : false, root : "PageGrid",
, selepas halaman dimuatkan, kami menghantar parameter permulaan jqGrid kepada kaedah initEnv Kaedah initEnv akan diperkenalkan kemudian dalam pemodulatan jqGrid dalam bootstrap. ③. Modularisasi jqGrid dalam bootstrap$("#pageGrid").footerData("set", {image_str : "支付总花费:", order_price : json.message});
initEnv(jqOption);
Dalam ②, kami melihat kaedah initEnv, jadi bahagian dalam kaedah ini ialah kerja pengkapsulan modular khusus untuk jqGrid.
kaedah initEnv
该方法中,我们将会看到initLayout方法和initUI方法,具体内容稍候介绍。
initLayout
function initLayout() { $("table[rel=jqgridForm]").each(function() { var rel = $(this).attr("rel"); if (rel) { var $form = $("#" + rel); var tableWidth = $form.width(); $(this).setGridWidth(tableWidth, true); } }); }
也就是说,在窗口缩放的时候,我们为jqGrid重新绘制宽度,使其自适应于bootstrap的响应式布局。使用的方法就是jqGrid的setGridWidth方法。
initUI
function initUI(_box, jqOption) { var $p = $(_box || document); if (jqOption) { YUNM.debug("初始化jqgrid"); var $form = $("#" + $("#pageGrid").attr("rel")); YUNM.debug(YUNM.array2obj($form.serializeArray())); // 初始化 var op = $.extend({ url : $form.attr("action"), postData : YUNM.array2obj($form.serializeArray()), }, jqOption); $("#pageGrid").jqGrid(op); // 检索按钮 $("#searchBtn", $form).click(function() { $("#pageGrid").jqGrid('setGridParam', { url : $form.attr("action"), page : 1, postData : YUNM.array2obj($form.serializeArray()), }); $("#pageGrid").trigger("reloadGrid"); }); // toolbar,将button的圆角去掉 $(".btn", $form).each(function() { var $this = $(this); $this.css({ "border-radius" : "0px", "border-bottom" : "0", }); }); } } array2obj : function(array) { var params = $({}); $.each(array, function(i) { var $param = $(this)[0]; params.attr($param.name, $param.value); }); return params[0]; },
如果你曾看过我之前的系列文章,对于initUi方法就不会太陌生,熟悉dwz的朋友,自然也不会陌生,我项目中的大部分模板还是依赖于dwz,谢谢这些前辈们。
var $form = $("#" + $("#pageGrid").attr("rel"));
由于我们在jqGrid上关联了form检索条件的form表单,此处就可以将form表单对象取到,取到form表单对象,自然也就去得到了检索域的值($form.serializeArray()
)。拿到form表单的检索域值后,此时就需要做一番处理了。我们知道,jqGrid在向controller传递参数时,必然需要上送分页、排序的相关字段(page、rows、sord、sidx),使用的方法是$("#pageGrid").jqGrid({postData:xxx});
,通常情况下,我们上送form表单时,只需要使用$form.serializeArray()
就可以,但如果此时,只是将xxx替换为$form.serializeArray()
,那么controller中将不会获得分页、排序的相关字段(page、rows、sord、sidx),这是一个冲突,此时怎么处理呢?解决办法就是将form表单数据对象化(array2obj 方法),然后我们再通过var op =$.extend({url:$form.attr("action"),postData:YUNM.array2obj($form.serializeArray()),},jqOption);$("#pageGrid").jqGrid(op);
将检索域的值和分页、排序的相关字段一起上送到controller。$("#searchBtn", $form).click
通过封装click事件,将jqGrid的数据重新加载。$(".btn", $form).each(function() {
此处的方法将检索button去圆角,使其更贴合jqGrid,见效果图。④ 、jqGrid的数据操作
数据操作部分,我认为包含有 检索参数传递、分页排序参数传递、sql语句的编写。
关于参数传递,前端的参数封装在③中已有介绍,我们来看一看controller中如何处理数据的。
首先,我们来定义PageGrid,也就是jqGrid中xmlReader的数据源。
package com.honzh.common.page; import java.util.List; import com.thoughtworks.xstream.annotations.XStreamAlias; @XStreamAlias("pageGrid") @SuppressWarnings("rawtypes") public class PageGrid { private int page; private int total; private int records; private List data; public int getPage() { return this.page; } public void setPage(int page) { this.page = page; } public int getTotal() { return this.total; } public void setTotal(int total) { this.total = total; } public int getRecords() { return this.records; } public void setRecords(int records) { this.records = records; } public List getData() { return this.data; } public void setData(List data) { this.data = data; } }
项目中需要xstream.jar,自行下载。
XStreamComponent.java
package com.honzh.common.page; import org.apache.commons.lang.StringUtils; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.io.xml.DomDriver; import com.thoughtworks.xstream.mapper.DefaultMapper; import com.thoughtworks.xstream.mapper.XStream11XmlFriendlyMapper; public class XStreamComponent { private XStream xstream; public static XStreamComponent newInstance() { XStreamComponent xmlComponent = new XStreamComponent(); xmlComponent.alias(new Class[] { PageGrid.class }); return xmlComponent; } public XStreamComponent() { this.xstream = new XStream(new DomDriver()); } public String toXML(Object obj) { return this.xstream.toXML(obj); } public String toPageXML(Object obj) { registerConverter(new MapCustomConverter(new DefaultMapper(XStream11XmlFriendlyMapper.class.getClassLoader()))); return toXML(obj); } public Object fromPageXML(String xml) { registerConverter(new MapCustomConverter(new DefaultMapper(XStream11XmlFriendlyMapper.class.getClassLoader()))); return fromXML(xml); } public Object fromXML(String xml) { return this.xstream.fromXML(xml); } @SuppressWarnings("rawtypes") public void processAnnotations(Class type) { this.xstream.processAnnotations(type); } @SuppressWarnings("rawtypes") public void processAnnotations(Class[] types) { this.xstream.processAnnotations(types); } @SuppressWarnings("rawtypes") public void alias(String name, Class type) { this.xstream.alias(name, type); } @SuppressWarnings("rawtypes") public void alias(Class[] types) { for (Class type : types) { String className = type.getName(); try { String[] classNames = StringUtils.split(className, "."); this.xstream.alias(classNames[(classNames.length - 1)], type); } catch (Exception ex) { this.xstream.alias(className, type); } } } public void registerConverter(Converter converter) { this.xstream.registerConverter(converter); } @SuppressWarnings("rawtypes") public void useAttributeFor(Class definedIn, String fieldName) { this.xstream.useAttributeFor(definedIn, fieldName); } }
主要将pageGrid封装为xml对象,进而传递会前端。
MapCustomConverter.java
package com.honzh.common.page; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; public class MapCustomConverter extends AbstractCollectionConverter { public MapCustomConverter(Mapper mapper) { super(mapper); } @SuppressWarnings("rawtypes") public boolean canConvert(Class type) { return (type.equals(HashMap.class)) || (type.equals(Hashtable.class)) || (type.getName().equals("java.util.LinkedHashMap")) || (type.getName().equals("sun.font.AttributeMap")); } @SuppressWarnings({ "rawtypes" }) public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { Map map = (Map) source; for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) { Map.Entry entry = (Map.Entry) iterator.next(); writer.startNode(entry.getKey() == null ? "null" : entry.getKey().toString()); writer.setValue(entry.getValue() == null ? "" : entry.getValue().toString()); writer.endNode(); } } @SuppressWarnings("rawtypes") public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { Map map = (Map) createCollection(context.getRequiredType()); populateMap(reader, context, map); return map; } @SuppressWarnings({ "rawtypes", "unchecked" }) protected void populateMap(HierarchicalStreamReader reader, UnmarshallingContext context, Map map) { while (reader.hasMoreChildren()) { reader.moveDown(); Object key = reader.getNodeName(); Object value = reader.getValue(); map.put(key, value); reader.moveUp(); } } }
主要将数据库中获取的hashmap转换为标准的xml格式数据。
BaseConditionVO.java
package com.honzh.common.persistence; import java.util.HashMap; import java.util.Map; import org.apache.ibatis.session.RowBounds; /** * 分页查询时的参数设置类.<br> * * <P> * 1.PAGE_SHOW_COUNT──当然默认一页显示10。<br> * 2.pageNum──第几页。<br> * 3.numPerPage──一页显示多少,为空时,显示PAGE_SHOW_COUNT。<br> * 4.totalCount──总共数目。totalCount/numPerPage=多少页<br> * 5.orderField──排序的列。<br> * 6.orderDirection──排序的方向。 * </P> */ public class BaseConditionVO { public final static int PAGE_SHOW_COUNT = 50; private int pageNum = 1; private int numPerPage = 0; private long totalCount = 0; private String orderField = ""; private String orderDirection = ""; /** * @Fields ps : 对参数类型进行封装. */ private Map<String, Object> mo = new HashMap<String, Object>(); public int getPageNum() { return pageNum; } public void setPageNum(int pageNum) { this.pageNum = pageNum; } public int getNumPerPage() { return numPerPage > 0 ? numPerPage : PAGE_SHOW_COUNT; } public void setNumPerPage(int numPerPage) { this.numPerPage = numPerPage; } public String getOrderField() { return orderField; } public void setOrderField(String orderField) { this.orderField = orderField; } public String getOrderDirection() { return "desc".equals(orderDirection) ? "desc" : "asc"; } public void setOrderDirection(String orderDirection) { this.orderDirection = orderDirection; } public long getTotalCount() { return totalCount; } public void setTotalCount(long totalCount) { this.totalCount = totalCount; } public int getStartIndex() { int pageNum = this.getPageNum() > 0 ? this.getPageNum() - 1 : 0; return pageNum * this.getNumPerPage(); } public RowBounds createRowBounds() { RowBounds ro = new RowBounds(this.getStartIndex(), this.getNumPerPage()); return ro; } /** * @Title: addParams * @Description: 添加查询条件 * @param key * @param value */ public void addParams(String key, Object value) { this.getMo().put(key, value); } /** * @Title: getParams * @Description: 获取查询条件 * @param key * @return */ public Object getParams(String key) { return this.getMo().get(key); } /** * @return the mo */ public Map<String, Object> getMo() { return mo; } /** * @param mo * the mo to set */ public void setMo(Map<String, Object> mo) { this.mo = mo; } @Override public String toString() { return "条件:" + pageNum + "," + numPerPage + "," + totalCount + "," + orderField + "," + orderDirection + "," + mo; } }
分页的查询数据对象,包括分页、排序、检索域。
protected BaseConditionVO getBaseConditionVOForTable() { BaseConditionVO vo = new BaseConditionVO(); // 分页的参数 int currentPage = getParaToInt("page"); int sizes = getParaToInt("rows"); String sortOrder = getPara("sord"); String sortCol = getPara("sidx"); vo.setNumPerPage(sizes); vo.setPageNum(currentPage); vo.setOrderField(sortCol); vo.setOrderDirection(sortOrder); return vo; } 将jqGrid传递的参数转换为BaseConditionVO分页查询对象。 protected void renderXml(HttpServletResponse res, String xmlResponse) { try { res.setCharacterEncoding("UTF-8"); res.setHeader("Content-type", "text/xml"); PrintWriter out = res.getWriter(); out.print(xmlResponse); if (out != null) { out.close(); } } catch (IOException e) { logger.error(e.getMessage()); logger.error(e.getMessage(), e); } }
将xml写入到输出流中。
定义完了这些基础的对象,接下来,我们就要着手获取数据和传递数据了。
@SuppressWarnings("rawtypes") @RequestMapping(value = "datablePayDealOrdersList") public void datablePayDealOrdersList(HttpServletResponse response) { try { logger.debug("获取我支付的订单"); XStreamComponent xstreamComponent = XStreamComponent.newInstance(); // 获取列表参数 BaseConditionVO vo = getBaseConditionVOForTable(); vo.addParams("name", getPara("name")); logger.debug("我支付的订单查询" + vo); // 我创建的项目 List myDealOrders = dealOrderService.getByIssueUid(vo, vo.createRowBounds()); Long count = dealOrderService.searchIssueTotalCount(vo); String xmlResponse = xstreamComponent.toPageXML(createPageGrid(myDealOrders, vo, count.intValue())); renderXml(response, xmlResponse.replaceAll("__", "_")); } catch (UncategorizedSQLException e) { logger.error(e.getMessage()); logger.error(e.getMessage(), e); renderXml(response, Constants.QUERY_ERROR); } catch (Exception e) { logger.error(e.getMessage()); logger.error(e.getMessage(), e); renderXml(response, Constants.SERVER_ERROR); } }
我们来详细说明一下:
1. XStreamComponent.newInstance()
创建xml流对象。
2. BaseConditionVO vo = getBaseConditionVOForTable();
创建分页查询参数对象。
3. vo.addParams("name", getPara("name"));
将检索域的值放入到查询对象中。
4. dealOrderService.getByIssueUid(vo, vo.createRowBounds());
mybatis的分页查询方式,超简单,之前一个群里的朋友专门做了一种mybatis的分页组件,我觉得用原始的mybatis查询方法更有效率,之后,我们会写出对应的mybatis中xml的sql写法。
5. renderXml(response, xmlResponse.replaceAll("__", "_"));
将数据写入到jsp的out输出流中。
最后,我们来介绍,通过mybatis如何获取分页数据。
mapper.java
package com.honzh.biz.database.mapper; import java.math.BigDecimal; import java.util.HashMap; import java.util.List; import org.apache.ibatis.session.RowBounds; import com.honzh.common.persistence.BaseConditionVO; public interface DealOrderMapper { @SuppressWarnings("rawtypes") List<HashMap> getByIssueUid(BaseConditionVO vo, RowBounds createRowBounds); }
想mapper.xml传递的两个对象,分别是BaseConditionVO 还有分页的RowBounds ,xml中sql就会自动分页。
mapper.xml
<select id="getByIssueUid" resultType="hashmap" parameterType="map"> select * from daa WHERE is_delete=0 <if test="mo.name != null and mo.name != ''"> and y.name like CONCAT('%','${mo.name}','%') </if> <choose> <when test="orderField !=null and orderField !=''"> ORDER BY ${orderField} <if test="orderDirection != null and orderDirection != ''">${orderDirection}</if> </when> <otherwise> order by d.order_time DESC </otherwise> </choose> </select>
你完全可以不关注RowBounds ,mybatis内部会自动为你封装好limit的。检索域的name可以直接通过mo.name或得到。orderField、orderDirection也传递过来了。
到此为止,整篇的Bootstrap嵌入jqGrid就圆满结束了,ok,使你的table牛逼起来吧!