All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jquicker.persistent.rdb.sqlfile.SQLParser Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
package com.jquicker.persistent.rdb.sqlfile;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import com.jquicker.args.MethodInfo;
import com.jquicker.commons.util.ObjectUtils;
import com.jquicker.commons.util.RandomUtils;
import com.jquicker.commons.util.RegexUtils;
import com.jquicker.commons.util.StringUtils;
import com.jquicker.model.BaseEntity;
import com.jquicker.persistent.rdb.model.FinalSQL;
import com.jquicker.persistent.rdb.model.DynamicSQL;
import com.jquicker.persistent.rdb.model.SQLExpression;
import com.jquicker.persistent.rdb.model.SQLParam;


public class SQLParser {

	public static final String COMMENT = "/\\*[\\S\\s]*?\\*/";
	public static final String PARAMS = "(#|$)\\(([A-Za-z0-9_]+?)\\)"; // #(paramName)
	public static final String EXPRESSION = "#(if|else\\s*if|else|for)\\s*(?:\\(([\\S\\s]+?)\\))?\\s*\\{([\\S\\s]*?)\\}";
	
	public static final String IF = "if";
	public static final String ELSE_IF = "elseif";
	public static final String ELSE = "else";
	public static final String FOR = "for";
	
	static ScriptEngineManager engineManager = new ScriptEngineManager();
	
	private static Map methodMap = new HashMap();
	
	public static MethodInfo getMethodInfo(String className, String methodName) {
		return methodMap.get(StringUtils.concat(".", className, methodName));
	}
	
	public static void addMethodInfo(String className, String methodName, MethodInfo methodInfo) {
		methodMap.put(StringUtils.concat(".", className, methodName), methodInfo);
	}
	
	/**
	 * 取得原始sql中的所有表达式
	 * @param sqlStatement
	 * @return
	 * @author OL
	 */
	public static List findExpressions(String sqlStatement){
		List list = new ArrayList();
		Pattern pattern = Pattern.compile(EXPRESSION);
		Matcher matcher = pattern.matcher(sqlStatement);
		while (matcher.find()) {
			SQLExpression expression = new SQLExpression();
			expression.setContent(matcher.group(0));
			expression.setKey(matcher.group(1).trim().replace(" ", ""));
			expression.setCondition(matcher.group(2) == null ? null : matcher.group(2).trim());
			expression.setSqlPart(matcher.group(3) == null ? null : matcher.group(3).trim());
			list.add(expression);
		}
		return list;
	}
	
	/**
	 * 取得sql语句中的参数列表
	 * @param sqlStatement
	 * @return
	 * @author OL
	 */
	public static List findParams(String sqlStatement){
		List list = new ArrayList();
		Pattern pattern = Pattern.compile(PARAMS);
		Matcher matcher = pattern.matcher(sqlStatement);
		while (matcher.find()) {
			SQLParam param = new SQLParam();
			param.setContent(matcher.group(0));
			param.setKey(matcher.group(1));
			param.setName(matcher.group(2));
			list.add(param);
		}
		return list;
	}
	
	/**
	 * 根据传入参数动态解析表达式
* @param sql * @param params * @return * @author OL */ public static FinalSQL parse(DynamicSQL sql, Map params){ boolean mark = false; List expressions = sql.getExpressions(); String sqlStatement = sql.getSqlStatement(); for (int i = 0; i < expressions.size(); i++) { SQLExpression expression = expressions.get(i); String key = expression.getKey(); String sqlPart = expression.getSqlPart(); String condition = expression.getCondition(); boolean isTrue = false; if(IF.equals(key)) { mark = false; // 碰上IF则把mark置为false mark = isTrue = eval(condition, params); } if(ELSE_IF.equals(key)) { if(mark) { // 当mark为true时,表示在一个IF()...ELSE IF()...里面已经有满足条件的分支了 isTrue = false; } else { mark = isTrue = eval(condition, params); } } if(ELSE.equals(key)) { if(mark == false) { isTrue = true; } } if(FOR.equals(key)){ isTrue = true; sqlPart = parseFor(expression, params); } if(isTrue){ sqlStatement = sqlStatement.replace("expression_" + i, sqlPart); } else { sqlStatement = sqlStatement.replaceAll("expression_" + i + "\\s*", ""); } } List sqlParams = findParams(sqlStatement); // 取得sql中的参数列表 Object[] finalArgs = new Object[sqlParams.size()]; for (int i = 0; i < finalArgs.length; i++) { SQLParam param = sqlParams.get(i); String name = param.getName(); finalArgs[i] = params.get(name); } FinalSQL finalSQL = new FinalSQL(); finalSQL.setSql(SQLParser.makeFinalSql(sqlStatement)); finalSQL.setParams(finalArgs); return finalSQL; } /** * 根据传入参数动态解析表达式 * @param sql * @param methodInfo * @param args * @return * @author OL */ public static FinalSQL parse(DynamicSQL sql, MethodInfo methodInfo, Object... args){ Map params = convertArgs(methodInfo, args); return parse(sql, params); } /** * 去掉注释 * * @return * @author OL */ public static void removeComment(DynamicSQL sql) { String sqlStatement = sql.getSqlStatement().replaceAll(COMMENT, " "); sql.setSqlStatement(sqlStatement); } public static boolean eval(String script, Map params) { boolean result = false; if(script.matches("[a-zA-Z0-9_]+")) { Object obj = params.get(script); if(obj == null || obj == "" || obj.equals("")) { return false; } else { Class clazz = obj.getClass(); if(clazz.isArray()){ if(Array.getLength(obj) == 0){ return false; } } else if(Collection.class.isAssignableFrom(clazz)){ Collection c = (Collection) obj; if(c.isEmpty()){ return false; } } else if(Map.class.isAssignableFrom(clazz)){ Map m = (Map) obj; if(m.isEmpty()){ return false; } } return true; } } ScriptEngine engine = engineManager.getEngineByName("JavaScript"); try { if(params != null) { Set> set = params.entrySet(); for (Entry entry : set) { engine.put(entry.getKey(), entry.getValue()); } } result = (boolean) engine.eval(script); } catch (ScriptException e) { e.printStackTrace(); } finally { engine = null; } return result; } /** * 生成最终Sql
* 即将命名参数占位符替换成“?” * @param sql * @return * @author OL */ public static String makeFinalSql(String sqlStatement){ return sqlStatement.replaceAll(PARAMS, "?"); } /** * 将方法入参按类型转换成Map形式,以便解析动态SQL * @param methodInfo * @param args * @return * @author OL */ @SuppressWarnings("unchecked") private static Map convertArgs(MethodInfo methodInfo, Object[] args) { Class[] types = methodInfo.getParamTypes(); String[] argNames = methodInfo.getNames(); int count = methodInfo.getParamCount(); Map params = new HashMap(); for (int i = 0; i < count; i++) { Class type = types[i]; if(ObjectUtils.isPrimitivePlus(type)) { // 如果是String、Integer... params.put(argNames[i], args[i]); } else if(BaseEntity.class.isAssignableFrom(type)) { // 如果是BaseEntity params.putAll(((BaseEntity) args[i]).getFields()); } else if(Map.class.isAssignableFrom(type)) { // 如果是Map params.putAll((Map) args[i]); } else if(type.isArray() || Collection.class.isAssignableFrom(type)) { // 如果是数组 OR Collection params.put(argNames[i], args[i]); } else { // 普通对象 params.putAll(ObjectUtils.toMap(args[i])); } } return params; } /** * 解析FOR语句 * @param expression * @param params * @author OL */ private static String parseFor(SQLExpression expression, Map params){ StringBuilder sqlPartBuilder = new StringBuilder(); String sqlPart = expression.getSqlPart(); String condition = expression.getCondition(); String[] array = condition.split("\\s*,\\s*(?!\\s*'|\\s*\")"); // 不匹配包在单引号或者双引号之间的逗号 String before = ""; String after = ""; if(array.length > 1){ for (int i = 1; i < array.length; i++) { String[] tmps = array[i].split("\\s*=\\s*"); if(tmps[0].equals("before")){ before = tmps[1].replaceAll("'|\"", ""); } else if(tmps[0].equals("after")){ after = tmps[1].replaceAll("'|\"", ""); } } } String[] forSentence = array[0].split("\\s*:\\s*"); Object obj = params.get(forSentence[1]); if(obj == null){ return sqlPartBuilder.toString(); } String itemName = forSentence[0]; List sqlPartScripts = RegexUtils.find(sqlPart, itemName + "([.][a-zA-Z0-9_]+)?"); String random = RandomUtils.number(4); String prefix = forSentence[1] + "_"; Class clazz = obj.getClass(); if(clazz.isArray()){ Object[] objs = (Object[]) obj; for (int i = 0; i < objs.length; i++) { String tmpPart = sqlPart; sqlPartBuilder.append(before); for (String script : sqlPartScripts) { String name = prefix + script.replace(".", "_") + "_" + random + "_" + i; // sqlPartBuilder.append(eval(sqlPart, itemName, objs[i])); // sqlPart = sqlPart.replace("for.index", i + ""); tmpPart = tmpPart.replace(script, "#(" + name + ")"); params.put(name, getValue(script, itemName, objs[i])); } sqlPartBuilder.append(tmpPart); sqlPartBuilder.append(after); } if(sqlPartBuilder.length() > 0){ sqlPartBuilder.delete(0, before.length()); sqlPartBuilder.delete(sqlPartBuilder.lastIndexOf(after), sqlPartBuilder.length()); } } else if(Collection.class.isAssignableFrom(clazz)){ @SuppressWarnings("unchecked") Collection collection = (Collection) obj; int i = 0; for (Object object : collection) { String tmpPart = sqlPart; sqlPartBuilder.append(before); for (String script : sqlPartScripts) { String name = prefix + script.replace(".", "_") + "_" + random + "_" + i; // sqlPartBuilder.append(eval(sqlPart, itemName, object)); // sqlPart = sqlPart.replace("for.index", i + ""); tmpPart = tmpPart.replace(script, "#(" + name + ")"); params.put(name, getValue(script, itemName, object)); } sqlPartBuilder.append(tmpPart); sqlPartBuilder.append(after); i++; } if(sqlPartBuilder.length() > 0){ sqlPartBuilder.delete(0, before.length()); sqlPartBuilder.delete(sqlPartBuilder.lastIndexOf(after), sqlPartBuilder.length()); } } return sqlPartBuilder.toString(); } private static Object getValue(String script, String itemName, Object itemValue) { Object result = null; Class valueType = itemValue.getClass(); if(ObjectUtils.isPrimitivePlus(valueType)){ result = itemValue; } else if(Map.class.isAssignableFrom(valueType)){ ScriptEngine engine = engineManager.getEngineByName("JavaScript"); try { engine.put(itemName, itemValue); result = engine.eval(script); } catch (ScriptException e) { e.printStackTrace(); } finally { engine = null; } } else { if(script.indexOf(".") == -1){ return itemValue; } Class clazz = itemValue.getClass(); try { Field field = clazz.getDeclaredField(script.split("[.]")[1]); field.setAccessible(true); result = field.get(itemValue); } catch (Exception e) { e.printStackTrace(); } } return result; } }