package com.norteksoft.product.util; import java.math.BigDecimal; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.fasterxml.jackson.databind.type.CollectionType; import com.fasterxml.jackson.databind.type.MapType; import com.fasterxml.jackson.databind.type.TypeFactory; import com.norteksoft.mms.form.entity.ListView; import com.norteksoft.mms.form.service.ListViewManager; import com.norteksoft.product.enumeration.QueryConditionProperty; import com.norteksoft.product.web.struts2.Struts2Utils; public class SearchUtils { private static SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private static final String SEARCH_STRING_NAME = "searchParameters"; public static final String SQL_OR_HQL = "_sql_or_hql"; public static final String PARAMETERS = "_parameters"; private static Log log = LogFactory.getLog(SearchUtils.class); /** * 处理查询参数 * @param sqlOrHql 查询语句 * @param isHql 是否原生sql * @param values 原有条件 * @return */ public static Map<String, Object> processSearchParameters(String sqlOrHql, boolean isHql, Object... values){ Map<String, Object> result = new HashMap<String, Object>(); result.put(SQL_OR_HQL, sqlOrHql); result.put(PARAMETERS, values); String searchParameters = Struts2Utils.getParameter(SEARCH_STRING_NAME); log.debug(" *** search parameters: /*" + searchParameters + "*/ ***"); if(StringUtils.isNotBlank(searchParameters)){ result = processQuerySentence(sqlOrHql, isHql, searchParameters, values); } return result; } /** * 处理查询参数 * @param sqlOrHql 查询语句 * @param isHql 是否原生sql * @param values 原有条件 * @return */ public static Map<String, Object> processSearchSubParameters(String sqlOrHql, boolean isHql, Object... values){ Map<String, Object> result = new HashMap<String, Object>(); result.put(SQL_OR_HQL, sqlOrHql); result.put(PARAMETERS, values); String searchSubParameters = getSearchSubParameters(Struts2Utils.getParameter(SEARCH_STRING_NAME),isHql); log.debug(" *** search sub parameters: /*" + searchSubParameters + "*/ ***"); if(StringUtils.isNotBlank(searchSubParameters)){ result = processQuerySentence(sqlOrHql, isHql, searchSubParameters, values); } return result; } private static String getSearchSubParameters(String searchParameters, boolean isHql){ String parameter=""; if(StringUtils.isNotEmpty(searchParameters)&&searchParameters.contains("$")){ MapType mt = TypeFactory.defaultInstance().constructMapType( HashMap.class, QueryConditionProperty.class, String.class); CollectionType ct = TypeFactory.defaultInstance().constructCollectionType(ArrayList.class, mt); List<Map<QueryConditionProperty,String>> prms = JsonParser.json2Object(ct, searchParameters); String propName=""; String dbName=""; for(Map<QueryConditionProperty,String> obj:prms){ propName=obj.get(QueryConditionProperty.propName); dbName=obj.get(QueryConditionProperty.dbName); if(isHql){ if(propName.startsWith("$")){ if(StringUtils.isNotEmpty(parameter)){ parameter+=","; } parameter+=packagingParameter(obj); } }else{ if(("null".equals(dbName)&&propName.startsWith("$")) || (!"null".equals(dbName)&&dbName.startsWith("$"))){ if(StringUtils.isNotEmpty(parameter)){ parameter+=","; } parameter+=packagingParameter(obj); } } } if(StringUtils.isNotEmpty(parameter)){ parameter="["+parameter+"]"; } } return parameter; } private static String packagingParameter(Map<QueryConditionProperty,String> obj){ String parameter=""; for(QueryConditionProperty prop : QueryConditionProperty.values()){ if(StringUtils.isNotEmpty(parameter)){ parameter+=","; } String name=prop.name(); parameter+="\""+name+"\""+":"+"\""; String value=obj.get(prop); if(StringUtils.isNotEmpty(value)){ parameter+=value; } parameter+="\""; } if(StringUtils.isNotEmpty(parameter)){ parameter="{"+parameter+"}"; } return parameter; } // public static void main(String[] args) { // is null // String s = "[{leftBracket:\"\",propName:\"vin.inner_color\",enumName:\"\",optSign:\"is null\",propValue:\"\",rightBracket:\"\",joinSign:\"and\",dataType:\"STRING\"},{leftBracket:\"\",propName:\"vin.dispose_result\",enumName:\"com.norteksoft.cbm.base.enumeration.SpecialCarStateEnum\",optSign:\"=\",propValue:\"NODISPOSAL\",rightBracket:\"\",joinSign:\"and\",dataType:\"ENUM\"}]"; // String s = "[{leftBracket:\"\",propName:\"vin.dispose_result\",enumName:\"com.norteksoft.cbm.base.enumeration.SpecialCarStateEnum\",optSign:\"=\",propValue:\"NODISPOSAL\",rightBracket:\"\",joinSign:\"and\",dataType:\"ENUM\"},{leftBracket:\"\",propName:\"vin.inner_color\",enumName:\"\",optSign:\"is null\",propValue:\"\",rightBracket:\"\",joinSign:\"and\",dataType:\"STRING\"}]"; // is not null // String s = "[{leftBracket:\"\",propName:\"vin.inner_color\",enumName:\"\",optSign:\"is not null\",propValue:\"\",rightBracket:\"\",joinSign:\"and\",dataType:\"STRING\"},{leftBracket:\"\",propName:\"vin.dispose_result\",enumName:\"com.norteksoft.cbm.base.enumeration.SpecialCarStateEnum\",optSign:\"=\",propValue:\"NODISPOSAL\",rightBracket:\"\",joinSign:\"and\",dataType:\"ENUM\"}]"; // String s = "[{leftBracket:\"\",propName:\"vin.dispose_result\",enumName:\"com.norteksoft.cbm.base.enumeration.SpecialCarStateEnum\",optSign:\"=\",propValue:\"NODISPOSAL\",rightBracket:\"\",joinSign:\"and\",dataType:\"ENUM\"},{leftBracket:\"\",propName:\"vin.inner_color\",enumName:\"\",optSign:\"is not null\",propValue:\"\",rightBracket:\"\",joinSign:\"and\",dataType:\"STRING\"}]"; // Map<String, Object> result = processQuerySentence("", false, s); // System.out.println(result); // String s = "[{leftBracket:\"\",propName:\"vin.inner_color\",enumName:\"\",optSign:\"is null\",propValue:\"\",rightBracket:\"\",joinSign:\"and\",dataType:\"STRING\"}," + // "{leftBracket:\"\",propName:\"vin\",enumName:\"\",optSign:\"=\",propValue:\"2011-01-01\",rightBracket:\"\",joinSign:\"and\",dataType:\"DATE\"}," + // "{leftBracket:\"\",propName:\"vin.inner_color\",enumName:\"\",optSign:\"is null\",propValue:\"\",rightBracket:\"\",joinSign:\"and\",dataType:\"STRING\"}]"; // Map<String, Object> result = processQuerySentence("", false, s); // System.out.println(result); // } private static Map<String, Object> processQuerySentence( String sqlOrHql, boolean isHql, String searchParameters, Object... values){ Map<String, Object> result = new HashMap<String, Object>(); List<Object> list = getParameters(sqlOrHql, isHql, searchParameters); //重新拼接sql,封装参数 String newSql = processSentence(sqlOrHql, list.get(0).toString()); Object[] newValues = processParameter(list, values); result.put(SQL_OR_HQL, newSql); result.put(PARAMETERS, newValues); return result; } // list 0 号元素为sql, 其余为参数 private static List<Object> getParameters(String sqlOrHql, boolean isHql, String searchParameters){ List<Object> result = new ArrayList<Object>(); StringBuilder additionalWhere = new StringBuilder(); result.add(additionalWhere); MapType mt = TypeFactory.defaultInstance().constructMapType( HashMap.class, QueryConditionProperty.class, String.class); CollectionType ct = TypeFactory.defaultInstance().constructCollectionType(ArrayList.class, mt); List<Map<QueryConditionProperty,String>> prms = JsonParser.json2Object(ct, searchParameters); List<Object> value = null; String alias = ""; if(isHql) alias = getAlias(sqlOrHql); for(int i = 0; i < prms.size(); i++){ if(i == prms.size()-1){ additionalWhere.append(getSql(prms.get(i), alias, false,isHql)); } else { additionalWhere.append(getSql(prms.get(i), alias, true,isHql)); } value = getValue(prms.get(i), isHql); if(value != null){ result.addAll(value); } } //处理创建时间相等的情况 List<Object> newResult = new ArrayList<Object>(); int flag = 0; for(int i=0;i<result.size();i++){ if(result.get(i) instanceof StringBuilder){ StringBuilder dateStr = (StringBuilder)result.get(i); if(dateStr.toString().indexOf("t.createDate >= ? and t.createDate <= ?")!=-1){ flag = 1; }else if(dateStr.toString().indexOf("l.logTime >= ? and l.logTime <= ?")!=-1){ flag = 2; } } if(flag==1){ StringBuilder dateSb = (StringBuilder)result.get(i); String dateStr = dateSb.toString(); String beforStr = dateStr.substring(0, dateStr.toString().indexOf("t.createDate >= ? and t.createDate <= ?")); String afterStr = dateStr.substring( dateStr.toString().indexOf("t.createDate >= ? and t.createDate <= ?")+39,dateStr.length()); newResult.add(beforStr+"t.createDate between ? and ?"+afterStr); flag = 0; }else if(flag==2){ StringBuilder dateSb = (StringBuilder)result.get(i); String dateStr = dateSb.toString(); String beforStr = dateStr.substring(0, dateStr.toString().indexOf("l.logTime >= ? and l.logTime <= ?")); String afterStr = dateStr.substring( dateStr.toString().indexOf("l.logTime >= ? and l.logTime <= ?")+33,dateStr.length()); newResult.add(beforStr+"l.logTime between ? and ?"+afterStr); flag = 0; }else{ newResult.add(result.get(i)); } } log.debug(" *** additional where: /*" + result.toString() + "*/ ***"); /** String alias = ""; if(isHql) alias = getAlias(sqlOrHql); JSONArray array = JSONArray.fromObject(searchParameters); JSONObject obj = null; List<Object> value = null; for(int i = 0; i < array.size(); i++){ obj = (JSONObject) array.get(i); if(i == array.size()-1){ additionalWhere.append(getSql(obj, alias, false)); } else { additionalWhere.append(getSql(obj, alias, true)); } value = getValue(obj, isHql); if(value != null){ result.addAll(value); } } */ return newResult; } /** * 获取查询条件 * @return */ public static List<Map<QueryConditionProperty,String>> getQueryParameter(){ String searchParameters = Struts2Utils.getParameter(SEARCH_STRING_NAME); if(StringUtils.isNotBlank(searchParameters)){ MapType mt = TypeFactory.defaultInstance().constructMapType( HashMap.class, QueryConditionProperty.class, String.class); CollectionType ct = TypeFactory.defaultInstance().constructCollectionType(ArrayList.class, mt); List<Map<QueryConditionProperty,String>> prms = JsonParser.json2Object(ct, searchParameters); return prms; } return new ArrayList<Map<QueryConditionProperty,String>>(); } /** * hql语句别名 * @param hql * @return */ public static String getAlias(String hql){ String order_by = "order by"; String where = "where"; String from = "from"; if(!hql.contains(from) && hql.contains("FROM")) from = "FROM"; if(!hql.contains(where) && hql.contains("WHERE")) where = "WHERE"; if(!hql.contains(order_by) && hql.contains("ORDER BY")) order_by = "ORDER BY"; String fromHql = StringUtils.substringAfter(hql, from); fromHql = StringUtils.substringBefore(fromHql, order_by); fromHql = StringUtils.substringBefore(fromHql, where); if(fromHql.indexOf(",")>=0){//TaskReport tr, WorkRepoet wr, ViewReport vr String[] fromHql1 = fromHql.split(","); return alias(fromHql1[0], fromHql); }else{//TaskReport tr与TaskReport tr inner join tr.workReport wr left outer join wr.viewReport vr if(fromHql.contains("join")){ String[] fromParts = fromHql.trim().split("join"); String hostTable = fromParts[0].trim(); String[] tableAlias = null; if(hostTable.contains("inner")){ tableAlias = hostTable.split("inner"); return alias(tableAlias[0].trim(), fromHql); }else if(hostTable.contains("left outer")){ tableAlias = hostTable.split("left outer"); return alias(tableAlias[0].trim(), fromHql); }else if(hostTable.contains("right outer")){ tableAlias = hostTable.split("right outer"); return alias(tableAlias[0].trim(), fromHql); }else{ return alias(hostTable, fromHql); } }else{ return alias(fromHql.trim(), fromHql); } } } private static String alias(String str, String fromHql){ String[] strs = str.split(" "); for(int i = strs.length-1; i >= 0; i--){ if(StringUtils.isNotBlank(strs[i])){ log.debug(" *** entity alias ["+strs[i]+"] hql : [" + fromHql + "]"); return strs[i].trim(); } } return ""; } /** * @param sql 源sql * @param additionalWhere 需添加的where子句 * @return newSql */ private static String processSentence(String sql, String additionalWhere){ StringBuilder newSql = new StringBuilder(); newSql.append(removeOrders(sql)); if(!sql.contains(" where ")&&!sql.contains(" WHERE ")){ newSql.append("where "); newSql.append(additionalWhere); } else { newSql.append(" and ("); newSql.append(additionalWhere).append(")"); } if(sql.contains("order by")) { newSql.append(" order by ").append(StringUtils.substringAfter(sql, "order by")); } return newSql.toString(); } private static Object[] processParameter(List<Object> list, Object... values){ Object[] newValues = null; if(values == null){ newValues = new Object[list.size()-1]; } else { newValues = new Object[values.length + list.size()-1]; System.arraycopy(values, 0, newValues, 0, values.length); int index = newValues.length -1; for(int j = list.size() - 1; j > 0;j--){ newValues[index--] = list.get(j); } } return newValues; } private static String removeOrders(String hql) { Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE); Matcher m = p.matcher(hql); StringBuffer sb = new StringBuffer(); while (m.find()) { m.appendReplacement(sb, ""); } m.appendTail(sb); return sb.toString(); } private static String getSql(Map<QueryConditionProperty, String> obj, String alias, boolean needJoinSign,boolean isHql){ StringBuilder sql = new StringBuilder(); String propName = ""; String tempName = ""; String value = null; boolean neetLeftBracket = false; String dataType = obj.get(QueryConditionProperty.dataType); for(QueryConditionProperty prop : QueryConditionProperty.values()){ if(QueryConditionProperty.dataType == prop) break; if(QueryConditionProperty.joinSign == prop && !needJoinSign) break; // 2011-08-08 if(QueryConditionProperty.joinSign == prop && needJoinSign){ if("is null".equals(obj.get(QueryConditionProperty.optSign)) && "STRING".equals(dataType)){ sql.append(" or ").append(propName).append("='') "); neetLeftBracket = true; } if("is not null".equals(obj.get(QueryConditionProperty.optSign)) && "STRING".equals(dataType)){ sql.append(" and ").append(propName).append("!='') "); neetLeftBracket = true; } if("not like".equals(obj.get(QueryConditionProperty.optSign)) && "STRING".equals(dataType)){ sql.append(" or ").append(propName).append(" is null) "); neetLeftBracket = true; } } //2011-10-26 日期等于时的特殊处理 if(QueryConditionProperty.optSign == prop && "=".equals(obj.get(QueryConditionProperty.optSign)) && "DATE".equals(dataType)){ continue; } if(QueryConditionProperty.propValue == prop && "=".equals(obj.get(QueryConditionProperty.optSign)) && "DATE".equals(dataType)){ sql.append(" between ? and ? "); continue; } //2011-10-26 00:00:00 时间等于时的特殊处理 if(QueryConditionProperty.optSign == prop && "=".equals(obj.get(QueryConditionProperty.optSign)) && "TIME".equals(dataType)){ continue; } if(QueryConditionProperty.propValue == prop && "=".equals(obj.get(QueryConditionProperty.optSign)) && "TIME".equals(dataType)){ sql.append(" between ? and ? "); continue; } //============= if(QueryConditionProperty.propValue == prop){ if(!"is null".equals(obj.get(QueryConditionProperty.optSign)) && !"is not null".equals(obj.get(QueryConditionProperty.optSign))){ sql.append("? "); } continue; } value = obj.get(prop); if(!isHql&&QueryConditionProperty.propName == prop)tempName=value; if(StringUtils.isNotBlank(value)){ if(isHql&&QueryConditionProperty.dbName != prop){ if(QueryConditionProperty.propName == prop && value.startsWith("$")){ propName = value.replaceFirst("\\$", ""); sql.append(propName).append(" "); }else{ if(QueryConditionProperty.propName == prop && StringUtils.isNotBlank(alias)) { propName = alias+"." + value; //sql.append(propName); sql.append(propName).append(" "); }else{ if(QueryConditionProperty.propName == prop) propName = value; sql.append(value).append(" "); } } }else if(!isHql&&QueryConditionProperty.propName != prop){ if("null".equals(value)){//为了兼容以前的数据dbName为空时就取propName的值 value=tempName; } if(QueryConditionProperty.dbName == prop && value.startsWith("$")){ propName = value.replaceFirst("\\$", ""); sql.append(propName).append(" "); }else{ if(QueryConditionProperty.dbName == prop) propName = value; sql.append(value).append(" "); } } } } // 2011-08-08 if(!needJoinSign && "is null".equals(obj.get(QueryConditionProperty.optSign)) && "STRING".equals(dataType)){ sql.append(" or ").append(propName).append("='') "); neetLeftBracket = true; } if(!needJoinSign && "is not null".equals(obj.get(QueryConditionProperty.optSign)) && "STRING".equals(dataType)){ if(!"oracle".equals(PropUtils.getDataBase())){//oracle数据库中不认识name!='' sql.append(" and ").append(propName).append("!='') "); neetLeftBracket = true; } } if(!needJoinSign && "not like".equals(obj.get(QueryConditionProperty.optSign)) && "STRING".equals(dataType)){ sql.append(" or ").append(propName).append(" is null) "); neetLeftBracket = true; } if(neetLeftBracket){ return "(" + sql.toString(); } //============= return sql.toString(); } private static List<Object> getValue(Map<QueryConditionProperty, String> obj, boolean isHql){ String optSign = obj.get(QueryConditionProperty.optSign); String propValue = obj.get(QueryConditionProperty.propValue); String dataType = obj.get(QueryConditionProperty.dataType); String enumName = obj.get(QueryConditionProperty.enumName); List<Object> result = new ArrayList<Object>(); if("like".equals(optSign) || "not like".equals(optSign)){ String listCode=Struts2Utils.getParameter("_list_code"); ListViewManager listViewManager = (ListViewManager) ContextUtils.getBean("listViewManager"); ListView listView=listViewManager.getListViewByCode(listCode); if(listView.getSearchFaint()){//是否启用模糊查询,默认是启用的 result.add("%"+propValue+"%"); }else{ result.add(propValue+"%"); } }else if("is null".equals(optSign) || "is not null".equals(optSign)){ result = null; }else{ try { Object value = getObjectByType(propValue, dataType, enumName, isHql); if(DataType.valueOf(dataType) == DataType.DATE && "=".equals(optSign)){ result.add(value); result.add(new Date(((Date)value).getTime()+(24*3600000-1))); }else if(DataType.valueOf(dataType) == DataType.TIME && "=".equals(optSign)){ result.add(value); result.add(new Date(((Date)value).getTime()+(60000))); }else{ result.add(value); } } catch (ParseException e) { log.debug(" *** format parameters error : ", e); } } return result; } private static Object getObjectByType(String value, String type, String enumName, boolean isHql) throws ParseException{ log.debug(" *** format parameters: /*" + value + " to " + type + "*/ ***"); switch(DataType.valueOf(type)){ case AMOUNT: return new BigDecimal(value); case STRING: return value; case DATE: return dataFormat.parse(value); case TIME: return dataFormat.parse(value); case INTEGER: return Integer.valueOf(value); case LONG: return Long.valueOf(value); case BOOLEAN: if("1".equals(value)||"true".equals(value)){ return true; }else if("0".equals(value)||"false".equals(value)){ return false; } case DOUBLE: return Double.valueOf(value); case FLOAT: return Float.valueOf(value); case ENUM: return getEnumObject(enumName, value, isHql); default: break; } log.debug(" *** format parameters end *** "); return null; } @SuppressWarnings("unchecked") private static Object getEnumObject(String enumName, String value, boolean isHql) { try { Class clazz = Class.forName(enumName); if(isHql){ return Enum.valueOf(clazz, value); }else{ return Enum.valueOf(clazz, value).ordinal(); } } catch (ClassNotFoundException e) { log.debug(" *** format Enum error: [" + enumName + ":" + value + "]", e); } return null; } } enum DataType { AMOUNT("金额"), STRING("文本"), DATE("日期"), TIME("时间"), INTEGER("整型"), LONG("长整型"), DOUBLE("双精度浮点数"), FLOAT("单精度浮点数"), BOOLEAN("布尔型"), ENUM("枚举型"); public String code; DataType(String code){ this.code=code; } public Short getIndex(){ return (short)(this.ordinal()+1); } public String getCode(){ return this.code; } public String getEnumName(){ return this.toString(); } }