jQuery学习笔记--jqGrid的单字段和多字段查询 详解


首先说明一下,什么是jqGrid的单字段查询。就是只能通过一个字段作为查询条件的查询。虽然大多数情况下,系统功能需要的查询,都是多个字段组合查询的,jqGrid也提供组合多个字段的查询,但是组合多个字段的查询,其实基于的原理还是单字段的查询。所以这里主要介绍一下单字段的查询,以后有机会在来说明一下高级一点的多字段组合查询。

大家可以先看看图片,对单字段查询有一个直观的了解(图片来源于jqGrid的wiki)

jQuery学习笔记--jqGrid的单字段和多字段查询 详解_第1张图片

这里需要注意的几点分别说明如下:

首先,其实默认jqGrid就有这个功能,所以,向上一篇文章中的例子一样,基本上不需要在js中添加其他的代码。

其次,哪些字段能作为单字段查询,哪些字段不能,这是在jqGrid的colModel属性中可以进行设置的。比如,如果我们对某一个列的数据设置如下:{name:'userName',index:'usrName', width:110,search=false} 那么这个userName列是不会在单字段查询中显示出来的。

第三,点击上面图中的"Find"按钮之后,jqGrid会额外的向服务器发送几个参数过去。想必你已经猜到了,这些参数就是图片中显示的:查询字段searchField,查询操作searchOper以及查询值searchString。这里之所以说是额外的参数,是相对于默认情况下的参数,比如前一篇文章中所说的page,sidx,sord,rows,_search,nd这些参数而言的。当然,这里_search参数的值是true。

第四,最烦处理的,就是如何把我们的searchOper的参数值,转换为对数据库记录的查询操作。

页面上显示的操作,主要包括'equal', 'not equal', 'less', 'less or equal','greater','greater or equal', 'begins with','does not begin with','is in','is not in','ends with','does not end with','contains','does not contain'。相应的,后台获取到的searchOper的值,对应的是'eq','ne','lt','le','gt','ge','bw','bn','in','ni','ew','en','cn','nc'。

最最简单的想法就是像我这养,写一个方法来处理:(以下的例子是基于Hibernate写的)

	

然后在dao类中,像如下这样进行查询和返回

	

当然了,在Action类中,我们还需要单独设置几个属性字段,并同时生成其相应的Getter和Setter。

	private String searchField;	private String searchString;	private String searchOper;......	@SuppressWarnings("unchecked")	public String queryAllBrand()	{				try		{						if(page == null ) page= "1";			if(sidx==null) sidx ="brandId";			if(rows==null) rows ="30";			if(sord==null) sord ="asc";			if(_search == null) _search="";			if(nd == null) nd = "0";						log.info("Page="+page+";sidx="+sidx+";rows="+rows+";sord="+sord+";_search="+_search+";nd="+nd);			log.info("searchField="+searchField+";searchValue="+searchString+";searchOper="+searchOper);						PageModel pm = this.brandService.findAll(Integer.parseInt(page), Integer.parseInt(rows),sidx,sord,searchField,searchString,searchOper);			//封装成JSON对象返回			HttpServletResponse response = ServletActionContext.getResponse();			response.setContentType("text/json; charset=UTF-8");			PrintWriter out = response.getWriter();						JSONObject obj = new JSONObject();			obj.put("page", pm.getPage());			obj.put("total",pm.getTotal());			obj.put("records",pm.getRecords());						JSONArray lineitemArray = new JSONArray();			List data = pm.getDatas();			Iterator it = data.iterator();			while (it.hasNext()){				MProductBrand mpb = (MProductBrand)it.next();				lineitemArray.add(mpb.getJSON());			}			obj.put("rows", lineitemArray);			out.print(obj.toString());		}		catch(Exception e)		{			e.printStackTrace();		}		return null;	}

看上面这个代码可能会有点糊涂,因为我们的Pojo对象中,还有一个重要的方法,把POJO转换为JSON对象。

	//注意,JSON数据插入的顺序是和页面显示的顺序相关的。	public JSONObject getJSON(){		JSONObject json = new JSONObject();		json.put("brandId", brandId);		json.put("code", code);		json.put("brandName", brandName);		json.put("status", status);		return json;	}

感觉比较丑陋的,还是那个getOperation方法,一个是本身还有很多的bug,比如对空值的处理不够完善;二是对日期类型的处理功能基本上没有等等。呵呵,暂时先这样吧!有兴趣大家也可以帮忙修改一下!

多字段查询,相对于单字段的过滤而言,可以称得上是高级查询了。见下图。

jQuery学习笔记--jqGrid的单字段和多字段查询 详解_第2张图片

多字段查询的jqGrid调用方式如下:

			$(document).ready(function(){
				$("#grid").jqGrid({        
				   	url:'queryAllBrand.action',
					datatype: "json",
					mtype: 'POST',
				  	colNames:['品牌ID','品牌代码', '品牌名称', '品牌状态','最后修改时间'],
				    colModel:[
				     	{name:'brandId',index:'brandId', width:90},
				   		{name:'code',index:'code', width:110},
				      	{name:'brandName',index:'brandName', width:100},
				   		{name:'status',index:'status', width:80},
				   		{name:'lastModifiedDatetime',index:'lastModifiedDatetime', width:100}
				    ],
				   	rowNum:30,
				   	rowList:[30,40,50],
				   	pager: '#nav',
				   	sortname: 'brandId',
				    viewrecords: true,
				    width: 500,
				    height: 500,
				    sortorder: "ASC",
					jsonReader: {
						repeatitems : false,
						id: "0"
					},
					caption: "品牌信息"
				}).navGrid('#nav',{edit:false,add:false,del:false})
				.searchGrid({multipleSearch:true});	
			});

大家可以看到最后一句话:.searchGrid({multipleSearch:true}),对,就是这么简单。(不过这种拼接调用的方式有一个问题。页面进入的时候,默认就会出来一个查询框,就像上面的图显示的一样,这感觉很不爽!暂时还没有找到好的办法!!??)

那么这种方式和单字段查询的区别在什么地方呢?

单字段查询,jqGrid向服务器传递的参数是searchField、searchString、searchOper这三个参数。多字段查询的时候,jqGrid不再采用这种方式,因为多个查询条件,参数数目就不是固定的了。这种情况下,jqGrid向服务器传递的参数是一个名字叫做filters的json字符串。类似于如下的形式:

filters = 
    {"groupOp":"AND",
     "rules":[
       {"field":"invdate","op":"ge","data":"2007-10-06"},
       {"field":"invdate","op":"le","data":"2007-10-20"}, 
       {"field":"name","op":"bw","data":"Client 3"}
      ]
    }

知道了这一点,我们就可以在Action类中定义一个变量是filters,然后用json-lib包提供的JSONObject类来进行json参数的解析。

json-lib包不仅提供了把Bean或容器类List、Map等转换为json格式数据的方法,而且提供了把json格式数据转换为容器类或者Bean类对象的方法。

为了方便转换,我们这里定义了两个Transfer Object对象,分别是JqGridSearchTo对象以及JqGridSearchDetailTo对象。

JqGridSearchTo对象的定义如下:(为了方便,我们把一些其他jqGrid上传的参数也封装了进去)

public class JqGridSearchTo implements java.io.Serializable{

	private String groupOp;		//多字段查询时分组类型,主要是AND或者OR
	private List rules; //多字段查询时候,查询条件的集合
	
	private int page;	//当前第几页
	private int rows;	//每页显示多少条数据
	private String sidx; 	//排序字段	
	private String sord;	//排序类型 ASC或者DESC
	private boolean _search;	//是否是查询 true 或者 false
	private String nd;		//暂时不清楚啥用的
	
	private String searchField;		//单字段查询的时候,查询字段名称
	private String searchString;	//单字段查询的时候,查询字段的值
	private String searchOper;		//单字段查询的时候,查询的操作
	
	public JqGridSearchTo(){
		
	}
	......//省略Getter和Setter方法定义
}

然后定义jqGridSearchDetailTo对象,这个对象只是为多字段查询的rules中的查询条件设计的,相对非常简单:

public class JqGridSearchDetailTo implements java.io.Serializable{
	
	private String field;  	//查询字段
	private String op;		//查询操作
	private String data;	//选择的查询值
	
	public JqGridSearchDetailTo(){
		
	}
	......//省略Getter和Setter方法定义
}

这里需要说明一下,大家应该看到了,这两个类定义的属性和获取的json数据格式是一样的。这就方便json-lib进行转换。

然后大家看看Action中的执行方法类的定义:

	@SuppressWarnings("unchecked")
	public String queryAllBrand()
	{		
		try
		{
			if(page == null ) page= "1";
			if(sidx==null) sidx ="brandId";
			if(rows==null) rows ="30";
			if(sord==null) sord ="asc";
			if(_search == null) _search="";
			if(nd == null) nd = "0";
					
			log.info("Page="+page+";sidx="+sidx+";rows="+rows+";sord="+sord+";_search="+_search+";nd="+nd);
			log.info("searchField="+searchField+";searchValue="+searchString+";searchOper="+searchOper);
			log.info("filters="+filters);
			
			JqGridSearchTo to = new JqGridSearchTo();
			if(_search.equals("true") && filters != null ){
				JSONObject filt = JSONObject.fromObject(filters);
				Map m = new HashMap(); m.put("rules", JqGridSearchDetailTo.class); to = (JqGridSearchTo)JSONObject.toBean(filt, JqGridSearchTo.class, m); 				log.info(to.toString());
			}
			to.setPage(Integer.parseInt(page));
			to.setRows(Integer.parseInt(rows));
			to.setSidx(sidx);
			to.setSord(sord);
			to.setSearchField(searchField);
			to.setSearchOper(searchOper);
			to.setSearchString(searchString);
			to.set_search(Boolean.parseBoolean(_search));
			
			
			PageModel pm = this.brandService.findAll(to);

			//封装成JSON对象返回
			HttpServletResponse response = ServletActionContext.getResponse();
			response.setContentType("text/json; charset=UTF-8");
			PrintWriter out = response.getWriter();
			
			JSONObject ja = JSONObject.fromObject(pm); 			
			out.print(ja.toString());
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return null;
	}

这里需要说明一下的是:我们在转换jqGrid上传的json数据的时候,没有直接用JSONObject.toBean(filt,JqGridSearchTo.class)这种方式,而是首先定义了一个Map对象,并指定了rules转换的目标对象。这是因为如果不用Map指定rules的List包含的对象类,那么,json-lib默认会把rules的List中包含的对象转换成一个叫做ezmorphDynaBean的对象,而不会按照我们的定义转换成JqGridSearchDetailTo对象。

另外,相比于我上一篇文章中的转换对象为Json数据的方式,本文中直接使用了JSONObect.fromObject方法,是不是更简单了!!

然后就该重新设定一个方法来解析我们获取到的查询条件了。

	/**
	 * 根据表名称的别名以及JqGridSearchTo的查询条件组合HQL语句
	 * @param alias  查询对象对应的别名
	 * @param to
	 * @return
	 */
	public static String getCombOperation(String alias,JqGridSearchTo to){
		StringBuilder result = new StringBuilder("");
		
		if (to != null) {
			if(!to.get_search()){  //不是查询,则直接组合排序条件即可
				result.append(" order by ");
				result.append(alias);
				result.append(".");
				result.append(to.getSidx());
				result.append(" "+to.getSord());
			}
			else if (to.get_search() && to.getSearchField() != null && to.getSearchOper() != null ) {
				//只是单字段的查询
				
		    	String cond = SearchOperationUtil.getOperation(to.getSearchField(), to.getSearchOper(), to.getSearchString());
		    	if(cond != null && cond.trim().length() != 0){
		    		result.append(" WHERE ");
					result.append(alias);
					result.append(".");
		    		result.append(cond);
		    	}
				
				result.append(" order by ");
				result.append(alias);
				result.append(".");
				result.append(to.getSidx());
				result.append(" "+to.getSord());
			}
			else if (to.get_search() && to.getGroupOp() != null && to.getRules()!= null && to.getRules().size() != 0){
				//多字段的组合查询
				String groupOp = to.getGroupOp();
				Iterator it = to.getRules().iterator();
				result.append(" WHERE ");
				int i = 0;
				while (it.hasNext()) {  //循环处理所有的查询条件
					i++;
					JqGridSearchDetailTo dto = (JqGridSearchDetailTo) it.next();
					result.append(alias);
					result.append(".");
					result.append(SearchOperationUtil.getOperation(dto
							.getField(), dto.getOp(), dto.getData()));
					if (i < to.getRules().size())
						result.append(" " + groupOp + " ");
				}
				
				result.append(" ORDER BY ");
				result.append(alias);
				result.append(".");
				result.append(to.getSidx());
				result.append(" "+to.getSord());
			}
		}
		
		log.info(result.toString());
		return result.toString();
	}

OK,在最后看一下我们的Dao实现类是如何实现的吧。

	@SuppressWarnings("unchecked")
	public PageModel findAll(JqGridSearchTo to)
	{	   
		if (to == null )
			return null;
		Session s = null;
		try
		{
			s = this.getSession();

			int page = to.getPage();
			int rows = to.getRows();
			String whereCond = SearchOperationUtil.getCombOperation("brand", to);
		    //得到总记录数   
		    String queryCountHql = "select count(*) from MProductBrand brand" + whereCond;		       
		    Query query = s.createQuery(queryCountHql);  
		    int records = ((Long)query.uniqueResult()).intValue();
		    int offset  =  (page-1) * rows;

		    List datas = s.createQuery("from MProductBrand brand" + whereCond)
		                .setFirstResult(offset)
		                .setMaxResults(rows)
		                .list();   
		    //得到结果集   
		    PageModel pm = new PageModel();   
		    
		    int totalPage = records/rows;
		    if(records % rows > 0)
		    	totalPage += 1;
		    
		    pm.setTotal(totalPage);
		    pm.setRows(datas);
		    pm.setPage(page);
		    pm.setRecords(records);
		       
		    return pm;   
		}
		finally
		{
			if(s!=null)
				s.close();
		}
	}

看起来比以前更简单了。

以上部分代码存在一些隐患,请勿用于您的正式环境!

你可能感兴趣的:(jquery)