QBC中用得比较普遍的莫过于 property op value 这种形式
较常用的一些方法
而在界面的表单上,我们的查询,做成公共实现还是有较多方案的,不过问题在于像between,not等这类关系,并不能很好的控制,尤其是between,一个property对应两个value,表示一个区间。
之前我做的一个项目中,前端使用extjs,后台索引部分使用compass,而compass与spring结合后,风格跟spring-hibernate,以及hibernate的qbc很像。
下面就以extjs3.2,以及compass进行简要说明我的思路。
1、有一个这样的查询
"添加日期"是精确匹配,即"eq"
当然,你也可以处理时间跨度的查询,即between,不过这种方式使用">"、"<"相结合计较好实现。
like你也可以自己设定规则,如headLike,endLike等,只要后台有相应的解析处理程序。
2、我希望界面能传给后台这样的一个信息:
[{ name:'companyName', value:'长江', relation:'like' },{ name:'createDate', value:'2011-08-03', relation:'eq' }]
我希望不需要每次都手工去拼写这样的JSON,ExtJs的FormPanel(实际上是BasicForm的方法)有提供这样的一种方式获取json,用以提交:
var formJSON = formPanel.getForm().getValues();
可是通过这样获取到的JSON格式是:
{companyName:'长江',createDate:'2011-08-03'}
这并不是我所希望的格式,我想要的是三元关系。
要得到三元关系JSON的效果,需要对ExtJs的BasicForm进行扩展,如下:
Ext.override(Ext.form.BasicForm, { getRelations : function(tarName, tarFun) { var _this = this; var form = this.el.dom; var fElements = form.elements || (document.forms[form] || Ext.getDom(form)).elements, hasSubmit = false, encoder = encodeURIComponent, name, relation, data = [], type, hasValue; Ext.each(fElements, function(element) { var record; name = element.name; type = element.type; if (_this.findField(name)) { relation = _this.findField(name).relation; nullValue = _this.findField(name).nullValue; hiddenValue = _this.findField(name).hiddenValue; } if (!element.disabled && name) { if (/select-(one|multiple)/i.test(type)) { Ext.each(element.options, function(opt) { if (opt.selected) { hasValue = opt.hasAttribute ? opt.hasAttribute('value') : opt .getAttributeNode('value').specified; data += String.format("{0}={1}&", encoder(name), encoder(hasValue ? opt.value : opt.text)); } }); } else if (!(/file|undefined|reset|button/i.test(type))) { if (!(/radio|checkbox/i.test(type) && !element.checked) && !(type == 'submit' && hasSubmit)) { var value = hiddenValue ? hiddenValue : element.value; if (relation && value && value != '' && value != nullValue) { if (/\./.test(name)) { name = name.substring(0, name.indexOf('.')); } record = 'name=' + encoder(name) + '&value=' + encoder(value) + '&relation=' + relation; var json = Ext.urlDecode(record); if (tarName == name && tarFun) { json = tarFun(json); } data.push(json); } hasSubmit = /submit/i.test(type); } } } relation = null; }); return data; } });
使用的时候,form还是一样的写法,只是多了一个relation属性
this.formPanel = new Ext.form.FormPanel({ xtype : 'form', title : '查询区', region : 'north', height : 65, layout : 'column', frame : true, items : [{ xtype : 'panel', columnWidth : 0.4, layout : 'form', labelPad : 0, labelWidth : 60, items : [{ xtype : 'textfield', name : 'company.companyName', relation : 'like', width : 100, fieldLabel : '公司名称', anchor : '95%' }] }, { xtype : 'panel', columnWidth : 0.4, layout : 'form', labelPad : 0, labelWidth : 60, items : [{ xtype : 'datefield', name : 'startDate', relation : 'eq', fieldLabel : '添加日期', format : 'Y-m-d', editable : false, maxValue : new Date(), anchor : '95%' }] }, { xtype : 'panel', items : [{ xtype : 'button', columnWidth : 0.2, text : '查询', iconCls : 'ux-icon-search', handler : this.onQuery.createDelegate(this), scope : this }] }], keys : [{ key : Ext.EventObject.ENTER, fn : this.onQuery.createDelegate(this), scope : this }] });
提交时只需要
var formJSON= this.formPanel.getForm().getRelations(); 即可拿到对应的三元JSON串。 通过ajax方式提交,params可以如下设置: params:{ data:Ext.util.JSON.encode(formJSON), xxx:'其他参数' }
3、我希望后台能够读懂这样格式的数据
当然,这里实际是用compass提供的qbc,但若用在hibernate上亦是类似。
如果你不喜欢直接传JSON作为参数,亦可做一次转换。Map或者Bean集合。这里只是想说明问题。
public static CompassBooleanQueryBuilder generateQueryBuilder(Class entity, CompassSession session, JSONArray queryArray) { CompassQueryBuilder queryBuilder = session.queryBuilder(); CompassBooleanQueryBuilder query = queryBuilder.bool(); query.addMust(queryBuilder.term("alias",entity.getSimpleName())); if (null==queryArray || queryArray.size()==0) { logger.debug("[OSEM] "+query.toQuery().toString()+" [OSEM]"); return query; } for (int i = 0; i < queryArray.size(); i++) { java.lang.reflect.Field field; String name = queryArray.getJSONObject(i).getString("name"); try { field = entity.getDeclaredField(name); } catch (NoSuchFieldException e) { try { field = entity.getSuperclass().getDeclaredField(name); } catch (NoSuchFieldException e1) { // TODO Auto-generated catch block e1.printStackTrace(); throw new NoSuchElementException("error.class.no.field"); } } Class type = field.getType(); Object value = queryArray.getJSONObject(i).get("value"); String relation = queryArray.getJSONObject(i).getString("relation"); if (relation.equals("like")) { query.addShould(queryBuilder.term(name, generateSpace(value.toString())+splitStrings(value.toString()))); }else if (relation.equals("eq")) { query.addMust(queryBuilder.term(name, value)); }else if (relation.equals("<")) { query.addMust(queryBuilder.lt(name, value)); }else if (relation.equals("<=")) { query.addMust(queryBuilder.le(name, value)); }else if (relation.equals(">")) { query.addMust(queryBuilder.gt(name, value)); }else if (relation.equals(">=")) { query.addMust(queryBuilder.ge(name, value)); }else if (relation.equals("between")) { JSONArray array = (JSONArray)value; query.addMust(queryBuilder.between(name, array.getString(0), array.getString(i), true)); } } logger.debug("[OSEM] "+query.toQuery().toString()+" [OSEM]"); return query; }
这样处理了之后,基本ExtJs表单配置完成,即可,而且不局限于Bean一一映射的那一类查询方式。