package cn.jiayi.framework.kit.sql; import cn.jiayi.web.kit.commons.StringKit; import com.jfinal.log.Logger; import com.jfinal.plugin.activerecord.Model; import com.jfinal.plugin.activerecord.Record; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 用於生成JFinal的SQL查詢語句<br> * 工具說明: * 1.setFiledQuery 指定字段查詢的TYPE,經過record或者model對象將查詢須要的值傳入,並生成sql。<br> * 例如:<br> * setFiledQuery(FUZZY_LEFT,"name","phone");<br> * modelToCondition(new Model().set("name","admin");<br> * 此時生成sql爲:and name like "%admin" //由於只傳了name的值沒有phone的,故不生成phone<br> * * 2.當setValueQuery中字段和BizUser對象中的字段重疊時,以setValueQuery爲準.<br> * 例如:<br> * conditions.setValueQuery(Conditions.FUZZY_LEFT,BizUser.COL_NAME,"admin");<br> * //傳入name和phone的值<br> * modelToCondition(new Model().set("name","admin").set("phone","13012341234"));<br> * 此時生成sql爲:and name like "%admin" //由於setValueQuery中只有name的查詢類型;<br> * * 3.若是須要以modal中的參數和值爲準,請將modelToCondition方法的isAll設爲false. * * Created by konbluesky * Date : 14-9-16 下午4:58 * Project : JiaYi_WebServer * http://my.oschina.net/helloyangxp/blog/294231 * */ public class Conditions { static Logger log = Logger.getLogger(Conditions.class); public static final String EQUAL = "EQUAL"; // 相等 public static final String NOT_EQUAL = "NOT_EQUAL"; // 不相等 public static final String LESS_THEN = "LESS_THEN"; // 小於 public static final String LESS_EQUAL = "LESS_EQUAL"; // 小於等於 public static final String GREATER_EQUAL = "GREATER_EQUAL"; // 大於等於 public static final String GREATER_THEN = "GREATER_THEN"; // 大於 public static final String FUZZY = "FUZZY"; // 模糊匹配 %xxx% public static final String FUZZY_LEFT = "FUZZY_LEFT"; // 左模糊 %xxx public static final String FUZZY_RIGHT = "FUZZY_RIGHT"; // 右模糊 xxx% public static final String NOT_EMPTY = "NOT_EMPTY"; // 不爲空值的狀況 public static final String EMPTY = "EMPTY"; // 空值的狀況 public static final String IN = "IN"; // 在範圍內 public static final String NOT_IN = "NOT_IN"; // 不在範圍內 // 用於接收SQL語句 private ThreadLocal<String> sql = new ThreadLocal<String>(); //select * from private ThreadLocal<String> selectorsql = new ThreadLocal<String>(); // 用於接收參數數組 private ThreadLocal<ArrayList<Object>> paramList = new ThreadLocal<ArrayList<Object>>(); //String-column;object-value private ThreadLocal<Map<String,Object>> colvaluesMap = new ThreadLocal<Map<String, Object>>(); // 用於存放設置的條件 private ThreadLocal<Map<String, Object[]>> conditionMap = new ThreadLocal<Map<String, Object[]>>(); // 用於存放須要排除的字段 private ThreadLocal<Map<String, String>> excludeFieldMap = new ThreadLocal<Map<String, String>>(); // 構造方法(表示沒有設置查詢類型的字段所有按照等於來處理) public Conditions() { colvaluesMap.set(new HashMap<String, Object>()); conditionMap.set(new HashMap<String, Object[]>()); excludeFieldMap.set(new HashMap<String, String>()); } // 構造方法(設置後表示字段全部的查詢方式按照設置類型來處理,除非後面針對字段的從新設置) public Conditions(String type) { Map<String, Object[]> map = new HashMap<String, Object[]>(); map.put("GLOBALTYPE", new String[] { type }); conditionMap.set(map); excludeFieldMap.set(new HashMap<String, String>()); } /*************************************************************************** * 設置字段的查詢類型 * * @param QueryType * 查詢類型 * @param filedName * 字段名稱數組 */ public Conditions setFiledQuery(String QueryType, String... filedName) { if (StringKit.notBlank(QueryType) && StringKit.notNull(filedName)) { Map<String, Object[]> map = conditionMap.get(); map.put(QueryType, filedName); conditionMap.set(map); } return this; } /*************************************************************************** * 設置須要排除的字段 * * setexcludeField<br> * * @param filedName * @return 返回對象 * @Exception 異常對象 * */ public Conditions setExcludeField(String... filedName) { if (StringKit.notNull(filedName)) { Map<String, String> map = excludeFieldMap.get(); for (String str : filedName) { map.put(str, str); } excludeFieldMap.set(map); } return this; } /*************************************************************************** * 查詢空值或者不爲空值的狀況 setNullFieldQuery * * @param QueryType * @param filedName * @return 返回對象 * @Exception 異常對象 */ public void setNullOrNotNullFieldQuery(String QueryType, String... filedName) { if (StringKit.notBlank(QueryType) && StringKit.notNull(filedName)) { if (!NOT_EMPTY.equals(QueryType) && !EMPTY.equals(QueryType)) { log.error("空值或者非空查詢的類型只能爲:EMPTY、NOT_EMPTY"); throw new RuntimeException("空值或者非空查詢的類型只能爲:EMPTY、NOT_EMPTY"); } Map<String, Object[]> map = conditionMap.get(); map.put(QueryType, filedName); conditionMap.set(map); } } /*************************************************************************** * <b>傳值查詢</b><br> * 注:若是QueryType爲<b>in</b>或者<b>not in</b>那麼filedValue必須爲一個list對象 * * @param QueryType * 查詢類型 * @param fieldName * 字段名稱 * @param filedValue * 字段值 */ public Conditions setValueQuery(String QueryType, String fieldName, Object filedValue) { if (StringKit.notBlank(QueryType) && StringKit.notBlank(fieldName) && StringKit.notNull(filedValue)) { Object[] param = new Object[2]; param[0] = fieldName; // 字段名 param[1] = filedValue;// 字段值 Map<String, Object[]> map = conditionMap.get(); map.put(QueryType + "#" + fieldName, param);// 避免類型重複被覆蓋掉就加上字段名 conditionMap.set(map); } return this; } /** * 當非主動調用modelToCondition,recordToCondition方法時 * 須要此方法觸發sql拼接方法 * @param val * @TODO * @return */ public Conditions buildSQL(HashMap<String,Object> val){ //@TODO // buildCondition("", val.keySet().toArray(new String[val.size()]), val); return this; } /*************************************************************************** * 用於生成SQL條件語句不帶別名 * * @param modelClass * 必須繼承於Model */ public void modelToCondition(Model<?> modelClass) { modelToCondition(modelClass, null,true); } /*************************************************************************** * 用於生成SQL條件語句不帶別名 * * @param recordClass * 必須是一個Record類 */ public void recordToCondition(Record recordClass) { recordToCondition(recordClass, null,true); } /*************************************************************************** * 用於生成SQL條件語句帶別名 * 生成時以modelClass對象中的非空非null字段爲準 * @param modelClass 必須繼承於Model * @param alias 別名 默承認覺得[null or ""] * @param isAll 是否須要以Modelclass中的屬性和值爲準,默認爲true <br> * [true 使用conditionMap過濾,false 只用excludeFieldMap 過濾] */ public void modelToCondition(Model<?> modelClass, String alias,boolean isAll) { alias = StringKit.notBlank(alias) ? alias + "." : ""; if (modelClass != null) { // 全部的字段 String[] fieldNames = modelClass.getAttrNames(); // 字段名和值的map集合 // Map<String, Object> valueMap = Common.modelToMap(modelClass); Map<String, Object> valueMap = new HashMap<String, Object>(); for(Map.Entry<String,Object> en : modelClass.getAttrsEntrySet()){ //不在excludeFieldMap 可是存在與conditionMap中的value才能傳入生成sql if (!excludeFieldMap.get().containsKey(en.getKey()) && (isAll || conditionMap.get().containsKey(en.getKey()))) { valueMap.put(en.getKey(), en.getValue()); } } // 構建查詢條件 buildCondition(alias, fieldNames, valueMap); } else { if (!conditionMap.get().isEmpty()) { buildCondition(alias, new String[] {}, new HashMap<String, Object>()); } else { sql.set(""); paramList.set(new ArrayList<Object>(0)); } } } /*************************************************************************** * 用於生成SQL條件語句不帶別名 * * @param recordClass * 必須是一個Record類 * @param alias 別名 默承認覺得[null or ""] * @param isAll 是否須要以Modelclass中的屬性和值爲準,默認爲true <br> * [true 使用conditionMap過濾,false 只用excludeFieldMap 過濾] */ public void recordToCondition(Record recordClass, String alias,boolean isAll) { // 別名 alias = StringKit.notBlank(alias) ? alias + "." : ""; if (recordClass != null) { // 全部的字段 String[] fieldNames = recordClass.getColumnNames(); // 字段名和值的map集合 // Map<String, Object> valueMap = Common.recordToMap(recordClass); Map<String, Object> valueMap = recordClass.getColumns(); for(Map.Entry<String,Object> en : recordClass.getColumns().entrySet()){ //即便按照#查詢 也要從exclude過濾 if (!excludeFieldMap.get().containsKey(en.getKey()) && (isAll || conditionMap.get().containsKey(en.getKey()))) { valueMap.put(en.getKey(), en.getValue()); } } // 構建查詢條件 buildCondition(alias, fieldNames, valueMap); } else { if (!conditionMap.get().isEmpty()) { buildCondition(alias, new String[] {}, new HashMap<String, Object>()); } else { sql.set(""); paramList.set(new ArrayList<Object>(0)); } } } /*************************************************************************** * 構建條件語句 * * @param alias * 別名 * @param fieldNames * 全部查詢的字段名稱 * @param valueMap * 全部的值的map */ private void buildCondition(String alias, String[] fieldNames, Map<String, Object> valueMap) { try { // 構建條件前先清空變量 sql.set(""); paramList.set(new ArrayList<Object>()); // 用於存放參數列表 ArrayList<Object> paramArrayList = new ArrayList<Object>(); StringBuilder sb = new StringBuilder(); // 全部的字段名稱 Map<String, String> usedFieldMap = new HashMap<String, String>(); if (!conditionMap.get().isEmpty()) { for (Map.Entry<String, Object[]> map : conditionMap.get().entrySet()) { String queryType = map.getKey(); Object[] array = map.getValue(); if (queryType.indexOf("#") > 0) {// 傳值查詢 String fieldQueryType = queryType.split("#")[0]; String fieldName = array[0] != null ? array[0].toString() : ""; Object fieldValue = array[1]; // 將設置過的字段保存到數組中 usedFieldMap.put(fieldName, fieldName); // 構建SQL語句 buildSQL(sb, fieldQueryType, fieldName, fieldValue, alias, paramArrayList); } else {// 字段查詢 if (!"GLOBALTYPE".equals(queryType)) { for (Object field : array) { String filedName = field != null ? field.toString() : ""; if (!excludeFieldMap.get().containsKey(filedName)) { Object fieldValue = valueMap.get(filedName); // 將設置過的字段保存到數組中 usedFieldMap.put(filedName, filedName); // 構建查詢語句 buildSQL(sb, queryType, filedName, fieldValue, alias, paramArrayList); } } } } } } // 對沒有設置條件的字段進行查詢類型設置 String queryType = EQUAL; if (conditionMap.get().containsKey("GLOBALTYPE")) { String[] typeArray = (String[]) conditionMap.get().get("GLOBALTYPE"); queryType = typeArray[0]; } // 對未使用過的字段進行build for (String field : fieldNames) { if (!usedFieldMap.containsKey(field)) { Object fieldValue = valueMap.get(field); // 構建查詢語句 buildSQL(sb, queryType, field, fieldValue, alias, paramArrayList); } } // 合併傳入的參數到參數對象中 sql.set(sb.toString()); paramList.set(paramArrayList); conditionMap.set(new HashMap<String, Object[]>(0));// 清空本次的條件map excludeFieldMap.set(new HashMap<String, String>(0));// 清空本次的排除字段 } catch (Exception e) { log.error("Conditions構建SQL語句出現錯誤,請仔細檢查!",e); e.printStackTrace(); } } /*************************************************************************** * 構建SQL語句 * * @param sb * 用於拼接SQL語句 * @param queryType * 查詢類型 * @param fieldName * 字段名稱 * @param fieldValue * 字段值 * @param alias * 別名 * @return */ @SuppressWarnings("unchecked") private void buildSQL(StringBuilder sb, String queryType, String fieldName, Object fieldValue, String alias, ArrayList<Object> params) { // 非空的時候進行設置 if (StringKit.notNull(fieldValue) && StringKit.notNull(fieldName)) { if (EQUAL.equals(queryType)) { sb.append(" and " + alias + fieldName + " = ? "); params.add(fieldValue); } else if (NOT_EQUAL.equals(queryType)) { sb.append(" and " + alias + fieldName + " <> ? "); params.add(fieldValue); } else if (LESS_THEN.equals(queryType)) { sb.append(" and " + alias + fieldName + " < ? "); params.add(fieldValue); } else if (LESS_EQUAL.equals(queryType)) { sb.append(" and " + alias + fieldName + " <= ? "); params.add(fieldValue); } else if (GREATER_THEN.equals(queryType)) { sb.append(" and " + alias + fieldName + " > ? "); params.add(fieldValue); } else if (GREATER_EQUAL.equals(queryType)) { sb.append(" and " + alias + fieldName + " >= ? "); params.add(fieldValue); } else if (FUZZY.equals(queryType)) { sb.append(" and " + alias + fieldName + " like ? "); params.add("%" + fieldValue + "%"); } else if (FUZZY_LEFT.equals(queryType)) { sb.append(" and " + alias + fieldName + " like ? "); params.add("%" + fieldValue); } else if (FUZZY_RIGHT.equals(queryType)) { sb.append(" and " + alias + fieldName + " like ? "); params.add(fieldValue + "%"); } else if (IN.equals(queryType)) { try { List list = (List) fieldValue; StringBuffer instr = new StringBuffer(); sb.append(" and " + alias + fieldName + " in ("); for (Object obj : list) { instr.append(StringKit.notBlank(instr) ? ",?" : "?"); params.add(obj); } sb.append(instr + ") "); } catch (Exception e) { throw new RuntimeException("使用IN條件的時候傳入的值必須是個List對象,不然將會轉換出錯!例如將 in('1','2','3')中的'1','2','3'分爲三個分別添加到List中作爲值傳入.",e); } } else if (NOT_IN.equals(queryType)) { try { List list = (List) fieldValue; StringBuffer instr = new StringBuffer(); sb.append(" and " + alias + fieldName + " not in ("); for (Object obj : list) { instr.append(StringKit.notBlank(instr) ? ",?" : "?"); params.add(obj); } sb.append(instr + ") "); } catch (Exception e) { throw new RuntimeException("使用NOT IN條件的時候傳入的值必須是個List對象,不然將會轉換出錯!例如將 not in('1','2','3')中的'1','2','3'分爲三個分別添加到List中作爲值傳入.",e); } } } else { if (EMPTY.equals(queryType)) { sb.append(" and " + alias + fieldName + " is null "); } else if (NOT_EMPTY.equals(queryType)) { sb.append(" and " + alias + fieldName + " is not null "); } } } public String getSql() { return sql.get(); } public List<Object> getParamList() { return paramList.get(); } public Map<String, Object> getParamMap() { return colvaluesMap.get(); } public String getSelector(){ return selectorsql.get(); } public void setSelector(String selector){ selectorsql.set(selector); } public static void main(String[] args){ // conditions.setFiledQuery(Conditions.FUZZY, BizUser.COL_NAME,BizUser.COL_PHONE); // System.out.println(conditions.getSql()); // conditions=new Conditions(); // conditions.modelToCondition(BizUser.dao.searchFirst(BizUser.COL_LIVEFLAG, 1)); // conditions.modelToCondition(new BizUser()); // System.out.println(conditions.getSql()); // System.out.println(conditions.getParamList()); // conditions=new Conditions().setExcludeField(BizUser.COL_UUID); /*當setValueQuery中字段和BizUser對象中的字段重疊時,以setValueQuery爲準*/ // conditions.setValueQuery(Conditions.FUZZY_LEFT,BizUser.COL_NAME,"wang"); // conditions.modelToCondition(new BizUser().set(BizUser.COL_NAME,"wang")); // System.out.println(conditions.getSql()); // System.out.println(conditions.getParamList()); } }