网站中经常会用到搜索功能。单个条件的搜索很好实现,多条件组合搜索时,如何优美地实现参数的组装和传递就成了一个重要的问题。 html
最近在用JFinal作点小东西,遇到了这个功能需求,通过一番努力实现了这个功能,记录分享以下: java
JFinal在提交搜索后,须要对搜索条件一个个getPara()获取,若是参数多了确定不方便;而且因为JFinal将表单提交的参数封装成了HashMap,没法知道实体对象属性的类型。由于对于不一样的类型,在sql语句里会有不一样的处理,好比String类型使用 like '%value%',Integer类型使用 =value 等等。 sql
JFinal的实体类代码很简单: 数组
public class Item extends Model<Item> { public static final Item dao = new Item(); }在增长了私有属性定义及get、set方法后,页面的list不能正常显示值,不解后放弃了对实体类的改动。
因而给Item增长了一个对应的搜索实体类: cookie
package com.demo.item; /** * ItemSearch model. */ public class ItemSearch { private Integer id; private String name; private String color; private String picture; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } ... ... public ItemSearch() { super(); } }里面的属性和Item一一对应。
接下来就是处理多搜索条件,自动拼接sql和urlParas的方法: session
public static String[] makePara(Object obj, String objSearch, Map<String,String[]> paraMap) { String[] returnStr = new String[2]; StringBuffer sqlStr = new StringBuffer(128); StringBuffer paraStr = new StringBuffer(128); Set<String> nameSet = paraMap.keySet(); try { for(String name:nameSet){ String[] props = name.split("\\."); if(props[0].equals(objSearch)){ Class<?> type = obj.getClass().getDeclaredField(props[1]).getType(); if (paraMap.get(name) != null && !paraMap.get(name)[0].equals("")) { if(type == String.class){ sqlStr.append(" and ").append(props[1]).append(" like '%").append(paraMap.get(name)[0]).append("%'"); }else if(type == Integer.class){ sqlStr.append(" and ").append(props[1]).append("=").append(paraMap.get(name)[0]); }else if(type == Double.class){ sqlStr.append(" and ").append(props[1]).append("=").append(paraMap.get(name)[0]); }else if(type == Boolean.class){ sqlStr.append(" and ").append(props[1]).append("=").append(paraMap.get(name)[0]); }else if(type == Date.class){ sqlStr.append(" and ").append(props[1]).append(" ='").append(paraMap.get(name)[0]).append("'"); } paraStr.append("&").append(name).append("=").append(paraMap.get(name)[0]); } } } } catch (Exception e) { e.printStackTrace(); } returnStr[0] = sqlStr.toString(); returnStr[1] = paraStr.toString(); return returnStr; }你会发现返回值是个String数组,由于这里我须要两个东西,查询用的sql条件语句和翻页时传递这些搜索条件的字符串。
好了,而后在Controller中怎么使用呢?请看下面的代码: app
private ItemSearch itemSearch = new ItemSearch(); public ItemSearch getItemSearch() { return itemSearch; } public void setItemSearch(ItemSearch itemSearch) { this.itemSearch = itemSearch; }首先是定义一个itemSearch的搜索条件对象,这样经过反射能够获得每一个属性的类型,而后是:
String sqlCondition = " 1=1"; Map<String,String[]> paraMap = getParaMap(); String[] paraStr = Utility.makePara(itemSearch, "itemSearch", paraMap); sqlCondition += paraStr[0]; setAttr("productPage", Item.dao.paginate(page, 15, "select *", "from item where" + sqlCondition + " order by id desc")); setAttr("searchCon", paraStr[1]);JFinal中获取表单提交的所有数据用getParaMap()便可,而后就是调用上面拼接sql的方法makePara,这里须要传入3个参数,分别是itemSearch对象,搜索实体类的名字“itemSearch”(稍后判断有用),以及表单提交的所有搜索参数paraMap。
列表页面在用到分页组件时,须要增长一个参数: post
urlParas=searchCon其中,urlParas是在paginate模版里会用到的,searchCon就是刚才在Controller的方法里setAttr的paraStr[1]。
在paginate模版里是这样的: 网站
<#macro paginate currentPage totalPage actionUrl urlParas> <#if (totalPage <= 0) || (currentPage > totalPage)><#return></#if> <#local startPage = currentPage - 4> <#if (startPage < 1)><#local startPage = 1></#if> <#local endPage = currentPage + 4> <#if (endPage > totalPage)><#local endPage = totalPage></#if> <div class="pagination"> <ul> <#if (currentPage <= 8)> <#local startPage = 1> </#if> <#if ((totalPage - currentPage) < 8)> <#local endPage = totalPage> </#if> <#if (currentPage == 1)> <li class="disabled prev_page"><a>Prev</a></li> <#else> <li class="prev_page"><a href="${actionUrl}#{currentPage - 1}${urlParas!}">Prev</a></li> </#if> <#list startPage..endPage as i> <#if currentPage == i> <li class="active"><a>#{i}</a></li> <#else> <li><a href="${actionUrl}#{i}${urlParas!}">#{i}</a></li> </#if> </#list> <#if (currentPage == totalPage)> <li class="disabled next_page"><a>Next</a></li> <#else> <li class="next_page"><a href="${actionUrl}#{currentPage + 1}${urlParas!}">Next</a></li> </#if> </ul> </div> </#macro>
原来第一行的urlParas参数是="",这里把=""去掉,而后放在分页连接的最后便可。 this
在搜索页面只要这样写就能够:
<form method="post" action="/search"> <input type="text" name="itemSearch.name"> <input type="text" name="itemSearch.color"> <input type="submit" value="Search" /> </form>初看着好像没什么不一样,但当你增长搜索条件时,只须要在form里增长一个input,name就是搜索对象.属性名, 而其它地方的代码不用再作任何改动。对于String类型自动使用like模糊搜索,数值类型使用=。
以上是我目前能想到且正在使用的方法,只须要为实体类增长一个包含私有属性及get、set方法的搜索实体类,参数拼接的方法类能够通用,翻页时也能够将搜索条件一直带着。
通常翻页携带参数能够是url、cookies、session这几种,上面方法使用的是url携带参数,固然你也能够把搜索条件放到session里,而后在非搜索访问任意列表action时删除搜索条件的session就能够了。
这是我在oschina发表的第一篇文章,但愿对须要的人能有点点帮助就行了。