//SQLScriptPlugin JFinal插件类
//SQL脚本目录:/WEB-INF/sql-script
public class SQLScriptPlugin implements IPlugin {
private static final Log log = Log.getLog(SQLScriptPlugin.class);
private static final String LOADPATH = PathKit.getWebRootPath()
+ File.separator + "WEB-INF" + File.separator + "sql-script";
public SQLScriptPlugin() {
try {
File file = new File(LOADPATH);
if(!file.exists()) {
file.mkdirs();
}
SQLScript.init(new File(LOADPATH));
} catch (IOException e) {
log.error("SQLScriptPlugin Load Fail");
log.error(ErrorKit.toString(e));
}
}
@Override
public boolean start() {
return true;
}
@Override
public boolean stop() {
return true;
}
}
//SQLScript 核心类主要完成语句的解析功能
//加载文件需要依赖apache.commons.io
public class SQLScript {
private static Pattern SQLID_REG = Pattern.compile("(?:^/[*][+][*]\\s+[(])([\\w.]+)(?:[)]\\s+[*][+][*]/$)");
private static Pattern SQLKEY_REG = Pattern.compile("(?<=(?:^|[^\\w@:?]))[@:?]([\\w]+)(?=(?:[^\\w@:?]|$))");
private static Pattern SPLITIN_REG = Pattern.compile("(?<=\\bin\\b)(?:\\s*[(]\\s*)[@:?]([\\w]+)(?:\\s*[)])",
Pattern.CASE_INSENSITIVE);
private static Pattern REPLACE_REG = Pattern.compile("(?<=(?:^|\\s))#INS#(?=(?:\\s|$))",
Pattern.CASE_INSENSITIVE);
private static String[] EXTENSIONS = new String[] { "sql", "SQL" };
private static Map<String, String> SQL_MAP = new HashMap<String, String>();
private SQLScript() {}
public static synchronized void init(File input) throws IOException {
SQL_MAP.clear();
Collection<File> sqlFiles = FileUtils.listFiles(input, EXTENSIONS, true);
if (sqlFiles != null && sqlFiles.size() > 0) {
for (File file : sqlFiles) {
List<String> lines = FileUtils.readLines(file, "UTF-8");
String sql_id = null;
boolean append = false;
StringBuilder sql = null;
if (lines != null && lines.size() > 0) {
for (int i = 0; i < lines.size(); i++) {
String line = lines.get(i);
if (line == null) continue;
Matcher matcher = SQLID_REG.matcher(line.trim());
if (matcher.matches()) {
if (sql_id != null && sql != null) {
if (!StrKit.isBlank(sql.toString())) {
if (SQL_MAP.containsKey(sql_id)) {
throw new RuntimeException("脚本加载异常: 存在相同的SQL_ID: " + sql_id);
}
SQL_MAP.put(sql_id, sql.toString().trim());
append = false;
}
}
sql_id = matcher.group(1);
sql = new StringBuilder();
append = true;
} else if (append) {
sql.append(line).append("\r\n");
}
if (lines.size() == i + 1) {
if (sql_id != null && sql != null) {
if (!StrKit.isBlank(sql.toString())) {
if (SQL_MAP.containsKey(sql_id)) {
throw new RuntimeException("脚本加载异常: 存在相同的SQL_ID: " + sql_id);
}
SQL_MAP.put(sql_id, sql.toString().trim());
append = false;
}
}
}
}
}
}
}
}
public static synchronized void load(File input) throws IOException {
List<String> lines = FileUtils.readLines(input, "UTF-8");
String sql_id = null;
boolean append = false;
StringBuilder sql = null;
if (lines != null && lines.size() > 0) {
for (int i = 0; i < lines.size(); i++) {
String line = lines.get(i);
if (line == null) continue;
Matcher matcher = SQLID_REG.matcher(line.trim());
if (matcher.matches()) {
if (sql_id != null && sql != null) {
if (!StrKit.isBlank(sql.toString())) {
SQL_MAP.put(sql_id, sql.toString().trim());
append = false;
}
}
sql_id = matcher.group(1);
sql = new StringBuilder();
append = true;
} else if (append) {
sql.append(line).append("\r\n");
}
if (lines.size() == i + 1) {
if (sql_id != null && sql != null) {
if (!StrKit.isBlank(sql.toString())) {
SQL_MAP.put(sql_id, sql.toString().trim());
append = false;
}
}
}
}
}
}
public static SQLBean parse(String sqlid) {
return parse(sqlid, null, null);
}
public static SQLBean parse(String sqlid, String replace) {
return parse(sqlid, replace, null);
}
public static SQLBean parse(String sqlid, SQLParam param) {
return parse(sqlid, null, param);
}
public static SQLBean parse(String sqlid, String replace, SQLParam params) {
String sqlText = SQL_MAP.get(sqlid);
if (StrKit.isBlank(sqlText)) {
return null;
}
Matcher matcher = REPLACE_REG.matcher(sqlText);
if (matcher.find()) {
if (StrKit.isBlank(replace)) {
sqlText = matcher.replaceAll("");
} else {
sqlText = matcher.replaceAll(replace);
}
}
matcher = SQLKEY_REG.matcher(sqlText);
Map<String, Integer> psmap = null;
List<Object> value = null;
if (params != null) {
while (matcher.find()) {
if (value == null) {
value = new ArrayList<Object>();
}
String key = matcher.group(1);
Object val = params.get(key);
if (val instanceof Object[]) {
if (psmap == null) {
psmap = new HashMap<String, Integer>();
}
Object[] obj = (Object[]) val;
psmap.put(key, obj.length);
if (obj.length > 0) {
for (Object item : obj) {
value.add(item);
}
} else {
value.add(null);
}
} else if (val instanceof List) {
if (psmap == null) {
psmap = new HashMap<String, Integer>();
}
List<?> obj = (List<?>) val;
psmap.put(key, obj.size());
if (obj.size() > 0) {
for (Object item : obj) {
value.add(item);
}
} else {
value.add(null);
}
} else {
value.add(val);
}
}
}
if (psmap != null) {
matcher = SPLITIN_REG.matcher(sqlText);
while (matcher.find()) {
String key = matcher.group(1);
String str = inSqlString(psmap.get(key));
sqlText = matcher.replaceFirst(str);
matcher = matcher.reset(sqlText);
}
matcher = SQLKEY_REG.matcher(sqlText);
}
String sql = matcher.replaceAll("?");
if (value == null) {
return new SQLBean(sql.trim(), new Object[0]);
}
return new SQLBean(sql.trim(), value.toArray());
}
public static SQLBean parseSql(String sqlText) {
return parseSql(sqlText, null);
}
public static SQLBean parseSql(String sqlText, SQLParam params) {
Matcher matcher = SQLKEY_REG.matcher(sqlText);
Map<String, Integer> psmap = null;
List<Object> value = null;
if (params != null) {
while (matcher.find()) {
if (value == null) {
value = new ArrayList<Object>();
}
String key = matcher.group(1);
Object val = params.get(key);
if (val instanceof Object[]) {
if (psmap == null) {
psmap = new HashMap<String, Integer>();
}
Object[] obj = (Object[]) val;
psmap.put(key, obj.length);
if (obj.length > 0) {
for (Object item : obj) {
value.add(item);
}
} else {
value.add(null);
}
} else if (val instanceof List) {
if (psmap == null) {
psmap = new HashMap<String, Integer>();
}
List<?> obj = (List<?>) val;
psmap.put(key, obj.size());
if (obj.size() > 0) {
for (Object item : obj) {
value.add(item);
}
} else {
value.add(null);
}
} else {
value.add(val);
}
}
}
if (psmap != null) {
matcher = SPLITIN_REG.matcher(sqlText);
while (matcher.find()) {
String key = matcher.group(1);
String str = inSqlString(psmap.get(key));
sqlText = matcher.replaceFirst(str);
matcher = matcher.reset(sqlText);
}
matcher = SQLKEY_REG.matcher(sqlText);
}
String sql = matcher.replaceAll("?");
if (value == null) {
return new SQLBean(sql.trim(), new Object[0]);
}
return new SQLBean(sql.trim(), value.toArray());
}
public static String getSqlString(String sqlid) {
SQLBean bean = parse(sqlid, null, null);
if (bean != null) {
return bean.sql;
}
return null;
}
public static String getSqlString(String sqlid, String replace) {
SQLBean bean = parse(sqlid, replace, null);
if (bean != null) {
return bean.sql;
}
return null;
}
public static String getSqlString(String sqlid, SQLParam params) {
SQLBean bean = parse(sqlid, null, params);
if (bean != null) {
return bean.sql;
}
return null;
}
public static String getSqlString(String sqlid, String replace, SQLParam params) {
SQLBean bean = parse(sqlid, replace, params);
if (bean != null) {
return bean.sql;
}
return null;
}
public static String getSqlSource(String sqlid) {
return SQL_MAP.get(sqlid);
}
private static String inSqlString(Integer size) {
if (size == null || size == 0) {
return " (?)";
}
StringBuffer sb = new StringBuffer();
sb.append(" (");
for (int i = 0; i < size; i++) {
if (i > 0) sb.append(", ");
sb.append("?");
}
sb.append(")");
return sb.toString();
}
}
//SQLBean 解析后生成的对象
public class SQLBean implements Serializable {
private static final long serialVersionUID = 1L;
public String sql;
public Object[] params;
public SQLBean() {}
public SQLBean(String sql, Object[] params) {
this.sql = sql;
this.params = params;
}
@Override
public String toString() {
return "{\r\n" + sql + ";\r\n" + Arrays.toString(params) + "\r\n}";
}
}
//SQLParam 绑定参数传入对象
public class SQLParam implements Serializable {
private static final long serialVersionUID = 1L;
private Map<String, Object> columns = new HashMap<String, Object>();
public SQLParam() {}
public SQLParam(String key, Object value) {
set(key, value);
}
public SQLParam(Map<String, Object> columns) {
setColumns(columns);
}
public Map<String, Object> getColumns() {
return columns;
}
public SQLParam setColumns(Map<String, Object> columns) {
getColumns().putAll(columns);
return this;
}
public SQLParam set(String column, Object value) {
getColumns().put(column, value);
return this;
}
@SuppressWarnings("unchecked")
public <T> T get(String column) {
return (T)getColumns().get(column);
}
@SuppressWarnings("unchecked")
public <T> T get(String column, Object defaultValue) {
Object result = getColumns().get(column);
return (T)(result != null ? result : defaultValue);
}
}
//使用方法
SQLBean bean1 = SQLScript.parse("Test.sql_1", "order by 1,2,3");
System.out.println(bean1);
Db.find(bean1.sql, 110100, 110100, 1);
SQLBean bean2 = SQLScript.parse("Test.sql_2", "order by 1,2,3",
new SQLParam("id", 110100).set("status", 1));
System.out.println(bean2);
Db.find(bean2.sql, bean2.params);
SQLBean bean3 = SQLScript.parse("Test.sql_3", "order by 1,2,3",
new SQLParam("id", new Object[]{110100,110200,110300}).set("status", 1));
System.out.println(bean3);
Db.find(bean2.sql, bean2.params);
/WEB-INF/sql-script/Test.sql
/*+* (Test.sql_1) *+*/
select t.*
from g_area t
where t.id = ?
and t.parent_id <> ?
#INS#
/*+* (Test.sql_2) *+*/
select t.*
from g_area t
where t.id = :id
and t.parent_id <> :id
and t.status = :status
#INS#
/*+* (Test.sql_3) *+*/
select t.*
from g_area t
where t.id in (:id)
and t.parent_id not in (:id)
and t.status = :status
#INS#
//脚本文件格式说明:
1、/*+* (sqlid) *+*/
每条SQL以这样的格式作为开头(注意括号外面有空格),
括号里面的sqlid是sql语句的唯一标识。
2、@id、:id、?id 命名参数占位符
绑定变量参数占位符,支持以上3种
3、#INS# 文本替换占位符
可以在调用语句时追加额外语句进来