利用JAVA动态编译重构系统

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

猜你喜欢

转载自json20080301.iteye.com/blog/1024975
今日推荐