一个信息系统查询必不可少,如果是定制化的开发那么查询语句还可能是经常变动的;IBATIS提供了这样的sql配置查询的功能;这里有另一种解决方案:利用JAVA动态编译的方式实现SQL语句的配置化!
SQL的拼装有时候会很复杂,这个时候如何使用IBATIS的话,就不得不深入学习他的语法,对于新手来说上手就变得困难啦。如果有一种方案可以配置SQL在XML文件中,同时又使用JAVA的语法来拼SQL,那该多好。
利用JAVA动态编译的方式实现SQL语句的配置化!!!
/**
* 编译文件
*
* @param file
* @throws Exception
*/
private String compileFile(File file) throws Exception {
String classPath = getClassPath();
String[] arg = {"-classpath", classPath, "-d", classPath,
file.getAbsolutePath() };
StringWriter writer = new StringWriter(1024);
int code = com.sun.tools.javac.Main.compile(arg,
new PrintWriter(writer));
return code == 0 ? "0" : writer.toString();
}
/**
* 创建实例
*
* @param file
* @return
* @throws Exception
*/
private SqlBuilder createInstance(File file) throws Exception {
String filename = file.getName();
String classname = filename.substring(0, filename.lastIndexOf('.'));
return (SqlBuilder) Class.forName(packageName + "." + classname)
.newInstance();
}
/**
* 删除临时文件
*
* @param file
* @throws Exception
*/
private void removeTempFile(File file) throws Exception {
String classDir = getClassDir();
int last = file.getName().lastIndexOf('.');
String name = file.getName().substring(0, last);
String classFile = classDir + File.pathSeparator + name + ".java";
String javaFile = classDir + File.pathSeparator + name + ".class";
new File(javaFile).delete();
new File(classFile).delete();
}
/**
* 取得Class路径
*
* @return
*/
private String getClassPath() {
// URL url = this.getClass().getResource("/");
URL url = Thread.currentThread().getContextClassLoader().getResource("/");
File file = new File(url.getPath());
return file.getAbsolutePath();
}
/**
* 生成 JAVA代码片段
* @param classname
* @param sqlCode
* @return
*/
private String getJavaCode (String classname ,String sqlCode ){
StringBuffer code = new StringBuffer(1024);
code.append("\npackage " + packageName + "; \n");
code.append("public class " + classname + " implements "
+ superClass + "{\n");
code.append(" public String getSql(java.util.Map map) throws Exception{ \n");
code.append(" " + sqlCode + " \n");
// 兼容配置中有return语句的SQL
if (!sqlCode.contains("return ")) {
code.append(" return sql.toString();\n");
}
code.append(" }\n");
code.append("}\n");
return code.toString();
}
/**
* 取得Java路径
*
* @return
*/
private String getClassDir() {
return getClassPath() + "/" + packageName;
}
/**
* 验证 JAVA语法
* @param sqlCode
* @return
* @throws Exception
*/
public String validateJavaCode ( String sqlCode) throws Exception {
log.info("################ Class Dir[" + getClassDir()
+ "] #################");
File file = createFile(sqlCode);
String classname = file.getName().substring(0, file.getName().lastIndexOf('.'));
try {
Debug debug = new Debug("Dyna Complie");
debug.start("ComplieFile");
String result = compileFile(file);
if (!"0".equals(result)) {
// 保存错误信息
return "语法验证不通过:\n【\n" + getJavaCode(classname,sqlCode) + "\n】\n"+"验证信息如下:\n【\n" + result + "\n】\n";
}
debug.end("ComplieFile");
log.info(debug);
return "语法验证通过:\n【\n" + getJavaCode(classname,sqlCode) + "\n】\n" ;
} catch (Exception e) {
log.error(e);
return ("\n【\n" + getJavaCode(classname,sqlCode) + "\n】\n");
} finally {
removeTempFile(file);
}
}