一个信息系统查询必不可少,如果是定制化的开发那么查询语句还可能是经常变动的;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); } }