Bootstrap의 기본 테이블 구성 요소는 단순한 데이터 표시만 충족할 수 있지만 더 많은 운영 요구 사항을 충족할 수는 없습니다. 물론 "DataTables-1.10.11"이라는 부트스트랩 기반의 테이블 컴포넌트를 찾을 수 있지만, API를 잘 모르면 사용하기 힘들겠지만, jqGrid를 사용하기로 결정했다면 이 튜토리얼은 이러한 종류의 풍부한 운영 테이블에 대한 솔루션을 제공합니다.
1. 효과 표시
이 사진을 보여드리겠습니다. jqGrid의 부트스트랩 버전이 마음에 드셨을 것입니다. 이는 부트스트랩과 매우 호환되며 완벽합니다. 물론 이를 위해서는 jqGrid와 동시에 특정 캡슐화를 수정합니다.
2. 리소스 다운로드
어쨌든 jqGrid의 컴포넌트 코드는 jqGrid 공식 홈페이지에서 다운로드 받을 수 있는데, 다운로드 후 몇 가지 변경이 필요해서 수정된 jqGrid를 git에 직접 업로드하면 됩니다. 파일을 해당 프로젝트로 가져오기만 하면 됩니다.
추가로 jquery-ui-1.10.0.custom.css도 다운로드해야 합니다. 다운로드 주소는 제공하지 않지만, 꼭 찾게 되리라 믿습니다. 주파수를 이용하여 사고를 당한 Du Niang을 찾을 수도 있습니다.
3. 이 글은 어떤 내용인가요?
QQ 그룹을 결성한 이후 동급생들이 그룹에 합류하는 '무한 흐름'이 있었지만, 그룹에 합류한 사람들이 나에게 직접 와서 데모나 프로젝트 코드를 요구하는 것을 발견했습니다. 시도해 보고 다음을 구현하고 몇 가지 사항을 변경하여 자신만의 코드로 만드십시오. 분명히 내 코드를 완전히 복사한다고 해서 더 많은 도움을 얻을 수는 없을 것입니다.
위의 작은 헛소리에 대해 이야기한 후, 본론으로 돌아가서 우리 블로그의 주요 내용에 대해 이야기해 보겠습니다. 부트스트랩에 jqGrid를 삽입하는 핵심은 무엇입니까?
부트스트랩의 jqGrid 레이아웃 체계 jqGrid의 자체 구조적 매개변수 jqGrid의 모듈식 jqGrid의 부트스트랩 데이터 작업
설명은 위의 부분으로 잠정적으로 나누어져 있으나 지면의 제약으로 인해 블로그에서는 아이디어와 코드의 일부만 제공하고 있다는 점 유의하시기 바랍니다.
①, 부트스트랩의 jqGrid 레이아웃 구성표
<!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>
모든 사람의 프로젝트가 다르기 때문에 나열된 코드 중 jqGrid 부분에만 중점을 둡니다.
id="jqgridForm"
여기에는 렌더링에 나열된 검색 부분인 jqGrid에 대한 검색 조건 레이어가 포함된 양식 양식이 포함되어 있습니다. 검색 버튼을 클릭하면 양식 양식 필드의 쿼리 조건이 제출됩니다. 컨트롤러를 사용하여 데이터를 얻습니다. id="searchBtn"
는 나중에 모듈화에 대해 이야기할 때 사용할 검색 버튼을 정의합니다. <table id="pageGrid" rel="jqgridForm" class="jqgrid"></table> <div id="pageGridPager"></div>
jqGrid의 테이블 요소와 jqGrid의 바닥글 요소를 정의합니다. 사용되는 규칙은 내 프로젝트에서 임시로 합의됩니다. rel을 통해 양식의 ID를 지정하면 테이블을 사용하여 양식을 보다 편리하게 검색할 수 있습니다. ②.jqGrid 자체 구조 매개변수
구축된 매개변수를 ①의 my_pay_list.js에 추출했습니다.
$(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); });
jqGrid에 전혀 익숙하지 않은 학생들은 jqGrid 데모와 jqGrid 공식 문서를 읽어보는 것이 좋습니다. 물론 이미 jqGrid에 익숙한 학생들에게는 문서와 데모가 꼭 필요합니다. 읽습니다.
위 파일에는 많은 속성이 나열되어 있습니다. 이 기사의 주요 목적은 jqGrid를 부트스트랩에 삽입하는 방법을 소개하는 것입니다. 몇 가지 핵심 사항을 소개합니다.
formatter: function(cellvalue, options, rowObject) {
, 포맷터는 여전히 자주 사용되므로 해당 셀의 값을 가져오는 방법이 매우 중요합니다. 내 jqGrid는 xml(데이터 유형: "xml") 데이터 형식을 사용하므로 $(rowObject).find("deal_id").text()
을 전달할 수 있습니다. deal_id 열에 해당하는 값을 찾습니다. xmlReader : { repeatitems : false, root : "PageGrid",
, xmlReader의 매개변수 값에 주목하세요. ④jqGrid의 데이터 작업은 배경 xml 데이터 캡슐화와 관련하여 다음에 자세히 소개됩니다. $("#pageGrid").footerData("set", {image_str : "支付总花费:", order_price : json.message});
, footerData 방식도 사용하기 매우 편리합니다. 효과는 렌더링을 참고하세요. initEnv(jqOption);
메소드는 페이지가 온로드된 후 jqGrid의 초기화 매개변수를 initEnv 메소드에 전달합니다. initEnv 메소드는 나중에 부트스트랩의 jqGrid 모듈화에서 소개됩니다. ③. 부트스트랩에서 jqGrid 모듈화
②에서는 initEnv 메소드를 주목했는데, 이 메소드 내부는 jqGrid를 위한 모듈식 캡슐화 작업입니다.
initEnv 메소드
function initEnv(jqOption) { $(window).resize(function() { initLayout(); }); initUI(null, jqOption); }
该方法中,我们将会看到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牛逼起来吧!