Bootstrap嵌入jqGrid,使你的table牛逼起来

网友投稿 164 2023-07-18


Bootstrap嵌入jqGrid,使你的table牛逼起来

Bootstrap原生的table组件只能满足简单的数据展示,满足不了更富有操作性的要求。当然了,你可以找到一款叫做“DataTables-1.10.11”的基于bootstrap的table组件,但如果你对API看得不甚了解的话,用起来可就痛苦了,但是如果你选择使用jqGrid,那么本篇教程就给你带来了解决这种富操作性table的解决方案。

一、效果展示

OK,就展示这一张图片,相信你已经爱上了bootstrap版的jqGrid,和bootstrap很兼容,简直完美,当然了,这需要我们在缘由的jqGrid上进行一些改动,同时对组件进行一定的封装。

二、资源下载

我反正挺热爱分享的,关于jqGrid的组件代码,你可以从jqGrid的官网上下载,但是下载下来需要一些改动,那么我直接将改动后的jqGrid上传到了git,你只需要把提供的文件导入到你对应的项目即可。

另外,你还需要下载一个jquery-ui-1.10.0.custom.css,我就不提供下载地址了,不过我相信,你肯定会找得到,就算是用频出事故的度娘,你也可以找得到。

三、本篇都讲一些什么

自从建了QQ群后,“络绎不绝”的有同学加入到群中,但我也发现,进群的一步人直接来找我要demo,或者项目代码,这个我可不喜欢,自己动手做一做,去实现以下,改造一下,才会是你自己的东西,完全照搬我的代码显然你得不到更多的帮助,希望以上同学学习的时候再主动一些。

说完上面这点小废话后,我们言归正传,来说说我们本篇博客主要来讲些什么,什么才是在bootstrap中嵌入jqGrid的关键所在,我总结有如下:

jqGrid在bootstrap中的布局方案jqGrid自身的构造化参数jqGrid在bootstrap中的模块化jqGrid的数据操作

暂定分为以上部分来说明,但必须注意,限于篇幅,博客中只提供思路和部分代码。

①、 jqGrid在bootstrap中的布局方案

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>

<%@ include file="/components/common/taglib.jsp"%>

<%@ include file="/components/common/csslib.jsp"%>

method="post">

<%@ include file="/components/common/jslib.jsp"%>

介于每个人的项目千差万别,列出的代码中我们只关注jqGrid部分:

id="jqgridForm",此处我们为jqGrid包含一层检索条件的form表单,也就是效果图上列出的search部分,当点击检索按钮时,就把form表单域的查询条件提交到controller,进而获取的数据。id="searchBtn",定义检索按钮,后面讲模块化会用得到。

构造化参数,我把他提取到了①中的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 '去支付';

}

if (status == 1 || status == 3) {

return '查看详情';

}

if (status == 2) {

return '确认收货';

}

},

} ],

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的demo,以及jqGrid的官方文档,当然了,对于已经熟悉jqGrid的同学,doc和demo肯定是必看的。

以上文件列出的属性非常多,对于jqGrid,我不做过多的介绍,本篇的主旨主要来介绍如何将jqGrid嵌入到bootstrap,那么重点就不在于介绍jqGrid上,我只介绍几个关键点:

formatter: function(cellvalue, options, rowObject) {,formatter还是很经常要使用的,那么对于如何获得对应单元格的值就很重要,我的jqGrid使用的是xml(datatype : “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);方法,在页面onload后,我们将jqGrid的初始化参数传递给initEnv方法,后续③jqGrid在bootstrap中的模块化会介绍initEnv方法。③、jqGrid在bootstrap中的模块化

②中我们注意到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"));由于我们在jqGhttp://rid上关联了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;

/**

* 分页查询kzEyFxOXVn时的参数设置类.

*

*

* 1.PAGE_SHOW_COUNT──当然默认一页显示10。

* 2.pageNum──第几页。

* 3.numPerPage──一页显示多少,为空时,显示PAGE_SHOW_COUNT。

* 4.totalCount──总共数目。totalCount/numPerPage=多少页

* 5.orderField──排序的列。

* 6.orderDirection──排序的方向。

*

*/

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 mo = new HashMap();

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 getMo() {

return mo;

}

/**

* @param mo

* the mo to set

*/

public void setMo(Map 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 getByIssueUid(BaseConditionVO vo, RowBounds createRowBounds);

}

想mapper.xml传递的两个对象,分别是BaseConditionVO 还有分页的RowBounds ,xml中sql就会自动分页。

mapper.xml

select * from daa

WHERE is_delete=0

and y.name like CONCAT('%','${mo.name}','%')

ORDER BY ${orderField} ${orderDirection}

order by d.order_time DESC

你完全可以不关注RowBounds ,mybatis内部会自动为你封装好limit的。检索域的name可以直接通过mo.name或得到。orderField、orderDirection也传递过来了。

到此为止,整篇的Bootstrap嵌入jqGrid就圆满结束了,ok,使你的table牛逼起来吧!


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:详解Java中使用泛型实现快速排序算法的方法
下一篇:javaweb Servlet开发总结(二)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~