網站中經常會用到搜索功能。單個條件的搜索很好實現,多條件組合搜索時,如何優美地實現參數的組裝和傳遞就成了一個重要的問題。 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發表的第一篇文章,但願對須要的人能有點點幫助就行了。