jbase实现业务脚本化

编程入门 行业动态 更新时间:2024-10-25 14:25:57

jbase实现业务<a href=https://www.elefans.com/category/jswz/34/1771291.html style=脚本化"/>

jbase实现业务脚本化

经过晚上和早上的努力,终于补上框架最后一块了,业务脚本侦听变化后自动编译jar包和调用,实现维护成本低,开发效率高的框架的基本体系。

实现自动编译jar包的类

package appcode;import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.nio.file.Paths;
import java.util.concurrent.ConcurrentHashMap;
import java.util.*;
import java.io.*;
import org.apachemons.io.FileUtils;
import java.nio.charset.StandardCharsets;
import java.nio.charset.*;public class AutoBuild {/// <summary>/// 缓存路径和类型,允许多线程读一个线程写/// </summary>private static ConcurrentHashMap<String, Boolean> Building = new ConcurrentHashMap<>();/// <summary>/// 编译指定路径的java代码/// </summary>/// <param name="basePath">根路径</param>/// <param name="codepath">类代码路径</param>/// <param name="proname">工程名称,不带后缀的</param>/// <param name="standprofilepath">标准工程文件全路径</param>/// <returns>返回空成功,非空就是失败原因</returns>public static String Build(String basePath,String codepath, String proname, String standprofilepath){Process proc = null;try{//有编译的退出if (Building.containsKey(codepath)){System.out.println(codepath+"已经有进程在编译了,退出本次编译!");return "";}try{if (!Building.containsKey(codepath)){AutoBuild.HashTryAdd(Building, codepath, true);}}catch (Exception ex){System.out.println("编译并发"+ex.getMessage());}//编译临时总目录String buildPath = Paths.get(basePath, "AutoBuildTmp").toString();File directory = new File(buildPath);//没有编译的临时目录就创建if (!directory.exists()) {directory.mkdirs();}//构建项目编译文件夹String proBuildPath = Paths.get(buildPath, proname).toString();File directoryPro = new File(proBuildPath);//没有编译的临时目录就创建if (!directoryPro.exists()) {directoryPro.mkdirs();}File fi = new File(codepath);//编译目录类全名String clsFullName = Paths.get(proBuildPath, fi.getName()).toString();System.out.println("拷贝:" + codepath + "到:"+ clsFullName);List<String> lines = FileUtils.readLines(fi, "UTF-8");StringBuilder sbNewCode=new StringBuilder();String jarRootPath=proBuildPath;System.out.println("包名称:" + proname);String [] arr=proname.split("\\.");String pakName="";if(arr.length>1){for(int p=0;p<arr.length-1;p++){jarRootPath=Paths.get(jarRootPath,arr[p]).toString();//创建jar包目录结构File directoryProJarChild = new File(jarRootPath);//没有编译的临时目录就创建if (!directoryProJarChild.exists()) {directoryProJarChild.mkdirs();}if(pakName==""){pakName=arr[p];}else{pakName+="."+arr[p];}}}sbNewCode.append("package "+pakName+";"+System.lineSeparator());for (String line : lines) {sbNewCode.append(line+System.lineSeparator());}WriteText2File(clsFullName,sbNewCode.toString());//复制类代码//copyFile(new File(codepath), new File(clsFullName));String cmmand = "javac";StringBuilder retsb = new StringBuilder();//得到javac编译命令串String cmdStr=GetJavacStr(basePath,standprofilepath,fi.getName());System.out.println("编译命令:" + cmdStr);System.out.println("运行路径:" + directoryPro);// 创建进程并执行命令Process process = Runtime.getRuntime().exec(cmdStr,null,directoryPro);// 获取命令行程序的输出结果BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));String line;while ((line = reader.readLine()) != null) {retsb.append(line);}// 等待命令行程序执行完毕int exitCode=process.waitFor();// 关闭资源reader.close();System.out.println("编译返回:" + exitCode);//编译完成if (exitCode == 0){// 获取目录中的所有文件和子目录File[] files = directoryPro.listFiles();// 遍历文件和子目录for (File file : files) {if (!file.isDirectory()) {if (file.getName().endsWith(".class")) {copyFile(new File(file.toString()),new File(Paths.get(jarRootPath,file.getName()).toString()));}}}String pakStr="jar cf "+proname+".jar"+" "+arr[0];System.out.println("打包命令:" + pakStr);System.out.println("打包运行路径:" + directoryPro);//打包jar包Process processPak = Runtime.getRuntime().exec(pakStr,null,directoryPro);// 等待命令行程序执行完毕int exitCodePak=processPak.waitFor();System.out.println("打包返回:" + exitCodePak);if (exitCodePak == 0){String jarOutPath=Paths.get(proBuildPath,proname+".jar").toString();String jarBinPath=Paths.get(basePath,"BinAshx",proname+".jar").toString();System.out.println("从:" + jarOutPath+"拷贝到:"+jarBinPath);//拷贝生成的jar包到BinAshxcopyFile(new File(jarOutPath), new File(jarBinPath));}//删除源文件//DeleteFile(new File(proBuildPath));return "";}String retstr = retsb.toString();return retstr;}catch (Exception ex){return ex.getMessage();}finally{if (Building.containsKey(codepath)){Building.remove(codepath);}}}/// <summary>/// 解决多线程写并发/// </summary>/// <param name="hs"></param>/// <param name="key"></param>/// <param name="value"></param>public static void HashTryAdd(ConcurrentHashMap<String, Boolean> hs, String key, Boolean value){try{//更新类型if (!hs.containsKey(key)){hs.put(key, value);}}catch (Exception ex){System.out.println("并发编译捕获的正常日志,忽略"+ex.getMessage());//更新类型if (!hs.containsKey(key)){hs.put(key, value);}}}///拷贝文件public static void copyFile(File srcFile, File destFile) {//判断原文件是否存在if (!srcFile.exists()) {throw new IllegalArgumentException("源文件:" + srcFile + "不存在!");}//判断原文件是否为一个文件if (!srcFile.isFile()) {throw new IllegalArgumentException(srcFile + "不是一个文件!");}try {FileInputStream in = new FileInputStream(srcFile);FileOutputStream out = new FileOutputStream(destFile);/*** 读取原文件,以字节流的形式读到byte数组,1024个字节=1KB* 循环读取* in.read()读到bytes数组中,位置从0-bytes.length*/byte[] bytes = new byte[10 * 1024];int b;  //b为读取到的字节长度while ((b = in.read(bytes, 0, bytes.length)) != -1) {//写入out.write(bytes, 0, b);out.flush();}//关闭in.close();out.close();}catch (IOException e) {e.printStackTrace();}}///删除文件和目录public static void DeleteFile(File file){//判断文件不为null或文件目录存在if (file == null || !file.exists()){return;}//取得这个目录下的所有子文件对象File[] files = file.listFiles();//遍历该目录下的文件对象for (File f: files){//判断子目录是否存在子目录,如果是文件则删除if (f.isDirectory()){DeleteFile(f);}else {f.delete();}}}///得到javac编译命令///basePath:根地址///standprofilepath:依赖jar包工程地址///javaName:java类文件名称private static String GetJavacStr(String basePath,String standprofilepath,String javaName){String retStr="javac -encoding UTF-8 -classpath ";try {//判断配置是否存在File file = new File(standprofilepath);if (!file.exists()) {System.out.println(standprofilepath + "文件不存在,请确认!");return "";}//解析xmlDocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = factory.newDocumentBuilder();Document document = builder.parse(file);// 获得根节点Element rootElement = document.getDocumentElement();// 获得根节点下的所有子节点NodeList students = rootElement.getChildNodes();String classPath="";for (int i = 0; i < students.getLength(); i++) {// 由于节点多种类型,而一般我们需要处理的是元素节点Node childNode = students.item(i);// 元素节点就是非空的子节点,也就是还有孩子的子节点if (childNode.getNodeType() == Node.ELEMENT_NODE) {Element childElement = (Element) childNode;//不是对象配置元素就忽略if (childElement.getNodeName() != "orderEntry") {continue;}//解析得到包名String name = childElement.getAttribute("name");String oneJarPath=Paths.get(basePath,name+".jar").toString();if(classPath==""){classPath=oneJarPath;}else{classPath+=";"+oneJarPath;}}}retStr+=classPath+" "+javaName;return retStr;}catch (Exception ex) {System.out.println(standprofilepath + ex.getMessage());ex.printStackTrace();}return "";}/*** 将文本写入文件** @param filePath 文件全路径* @param text     文本**/public static void WriteText2File(String filePath, String text) {// 创建文件File file = new File(filePath);if (!file.exists()) {try {// 创建文件父级目录File parentFile = file.getParentFile();if (!parentFile.exists()) {parentFile.mkdirs();}// 创建文件file.createNewFile();}catch (IOException e) {e.printStackTrace();}}// 将文本写入文件WriteText2File(file, text);}/*** 将文本写入文件** @param file 文件对象* @param text 文本**/public static void WriteText2File(File file, String text) {BufferedWriter writer = null;try {FileOutputStream writerStream = new FileOutputStream(file);writer = new BufferedWriter(new OutputStreamWriter(writerStream, "UTF-8"));writer.write(text);writer.flush();}catch (IOException e) {e.printStackTrace();}finally {if (writer != null) {try {writer.close();} catch (IOException e) {e.printStackTrace();}}}}}

然后实现目录Java监控调用编译

import java.io.*;
import org.apachemons.io.monitor.FileAlterationListenerAdaptor;
import org.apachemons.io.monitor.FileAlterationObserver;//监控文件
public class FileListener extends FileAlterationListenerAdaptor {//启动@Overridepublic void onStart(FileAlterationObserver observer) {super.onStart(observer);}//新建目录@Overridepublic void onDirectoryCreate(File directory){}//目录修改@Overridepublic void onDirectoryChange(File directory){}//目录删除@Overridepublic void onDirectoryDelete(File directory){}//创建文件@Overridepublic void onFileCreate(File file) {String compressedPath = file.getAbsolutePath();if(compressedPath.contains("AutoBuildTmp")){return;}if (file.canRead()) {String confStr = compressedPath.replace(MainInit.BllJavaBasePath, "").replace("\\", "/").split("\\.")[0];MainMiddleware.GetObjectByConfString(confStr,null,"",compressedPath);}}//修改文件@Overridepublic void onFileChange(File file) {String compressedPath = file.getAbsolutePath();if(compressedPath.contains("AutoBuildTmp")){return;}String confStr = compressedPath.replace(MainInit.BllJavaBasePath, "").replace("\\", "/").split("\\.")[0];MainMiddleware.GetObjectByConfString(confStr,null,"",compressedPath);}//删除文件@Overridepublic void onFileDelete(File file) {}//停止@Overridepublic void onStop(FileAlterationObserver observer) {super.onStop(observer);}
}

文件侦听器

import org.apachemons.io.monitor.FileAlterationListener;
import org.apachemons.io.monitor.FileAlterationMonitor;
import org.apachemons.io.monitor.FileAlterationObserver;
import org.apachemons.io.filefilter.IOFileFilter;
import org.apachemons.io.filefilter.FileFilterUtils;
import org.apachemons.io.filefilter.HiddenFileFilter;import java.io.File;//监控文件
public class FileMonitor {//监视器private FileAlterationMonitor monitor;//构造函数public FileMonitor(long interval){monitor = new FileAlterationMonitor(interval);}/*** 给文件添加监听** @param path     文件路径* @param listener 文件监听器*/public void monitor(String path, FileAlterationListener listener) {IOFileFilter directories = FileFilterUtils.and(FileFilterUtils.directoryFileFilter(),HiddenFileFilter.VISIBLE);IOFileFilter files       = FileFilterUtils.and(FileFilterUtils.fileFileFilter(),FileFilterUtils.suffixFileFilter(".java"));IOFileFilter filter = FileFilterUtils.or(directories, files);FileAlterationObserver observer = new FileAlterationObserver(new File(path),filter);monitor.addObserver(observer);observer.addListener(listener);}//停止public void stop() throws Exception {monitor.stop();}//启动public void start() throws Exception {monitor.start();}
}

主初始化实现java脚本监控

import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;
import java.nio.file.*;
import java.io.*;public class MainInit {//是否已经执行了初始化private static boolean HasInit=false;//网站根地址private static String webBasePath="";//业务脚本根地址public static String BllJavaBasePath="";//执行初始化public static void TryInit(String basePath) {//只初始化一次if (HasInit == true) {return;}HasInit = true;webBasePath = basePath;File fiBase=new File(basePath);String parentPath=fiBase.getParent();File fiParent=new File(parentPath);String codeBasePath=basePath;//开发环境if(fiParent.getName().equals("artifacts")){//到out一级File fiParent1=new File(fiParent.getParent());//到WebUI一级File fiParent2=new File(fiParent1.getParent());codeBasePath=Paths.get(fiParent2.toString(),"web").toString()+File.separator;}//用容器的配置xml初始化容器LIS.Core.Context.ObjectContainer.InitIoc(basePath);try{BllJavaBasePath=codeBasePath;System.out.println("监控目录:"+codeBasePath);FileMonitor fileMonitor = new FileMonitor(5000);fileMonitor.monitor(codeBasePath, new FileListener());fileMonitor.start();}catch (Exception ex) {ex.printStackTrace();}}
}

主中间件调整

import appcode.IBaseHttpHandler;import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.concurrent.ConcurrentHashMap;
import java.URL;
import java.URLClassLoader;
import java.nio.file.Path;
import java.nio.file.Paths;import java.util.*;@javax.servlet.annotation.WebServlet(name = "MianMiddleware")
public class MainMiddleware extends javax.servlet.http.HttpServlet {/// <summary>/// 缓存路径和类型,允许多线程读一个线程写/// </summary>private static ConcurrentHashMap<String, Class> hsType = new ConcurrentHashMap<>();///网站根地址public static String WebBasePath="";///执行post请求@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//得到网站根路径if(WebBasePath==""){WebBasePath= getServletContext().getRealPath("/");}//尝试执行初始化主逻辑MainInit.TryInit(WebBasePath);response.setContentType("text/html");request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");String url=request.getRequestURI();//解析得到类名String className = url.split("\\.")[0];PrintWriter writer = response.getWriter();//取第一部分if (className.charAt(0) == '/') {className = className.substring(1);}int index=className.indexOf("/");className=className.substring(index+1);//反射得到类型Object objDeal = GetObjectByConfString(className,writer,WebBasePath,"");//转换处理接口if(objDeal!=null){//转换成接口appcode.IBaseHttpHandler baseDeal=(appcode.IBaseHttpHandler)objDeal;baseDeal.ProcessRequest(request,response);}else{Write(writer,"未找到名称为:"+className+"的处理类");}}/// <summary>/// 通过配置得当对象/// </summary>/// <param name="confStr">配置UI/login/ashx/AshDemo</param>/// <param name="writer">输出</param>/// <param name="basePath">Web根</param>/// <param name="isBuild">是否是编译</param>/// <returns></returns>public static Object GetObjectByConfString(String confStr,PrintWriter writer,String basePath,String javaBllClsPath) {try {//根if(basePath==""){basePath=WebBasePath;}System.out.println("confStr:"+confStr);//不包含类型或者要强行编译就进行编译if (!hsType.containsKey(confStr)||javaBllClsPath!="") {String [] nameArr=confStr.split("/");String classFullName = "";//类代码全路径String classCodePath = basePath;for (int i = 0; i < nameArr.length; i++){//类代码文件全名classCodePath = Paths.get(classCodePath, nameArr[i]).toString();//类带命名空间的全名if(classFullName!=""){classFullName += "." + nameArr[i];}else{classFullName = nameArr[i];}}//类代码地址,后面实现用脚本编译用classCodePath = classCodePath + ".java";if(javaBllClsPath!=""){classCodePath=javaBllClsPath;}String standardPath=Paths.get(basePath,"Conf","StandAshxProj.iml").toString();//编译返回String buildRet=appcode.AutoBuild.Build(basePath,classCodePath,classFullName,standardPath);System.out.println("buildRet:"+buildRet);//编译的jar名字String clsJarPath = Paths.get(basePath, "BinAshx", classFullName + ".jar").toString();System.out.println("加载jar包:"+clsJarPath);//自己生成jar包路径URL url = new File(clsJarPath).toURI().toURL();URL[] urls = new URL[]{url};//加载程序集,这里很重要,一定要指定父加载器,否则加载的类和父加载器的类不认为是一个类URLClassLoader loader = new URLClassLoader(urls, MainMiddleware.class.getClassLoader());//加载类Class c = loader.loadClass(classFullName);//先写死,后面执行编译和从jar包反射hsType.put(confStr, c);}Class c = hsType.get(confStr);//创建对象Object o = c.newInstance();return o;}catch (Exception ex) {ex.printStackTrace();}return null;}//get直接走post的逻辑@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doPost(request,response);}///输出数据到前台private static void Write(PrintWriter writer,String str){writer.println(str);writer.flush();writer.close();}}

自动编译的临时目录结构

自动生成的jar包

在idea里面改业务脚本代码后用浏览器访问就能立即生效,简单高效,适用于服务型系统。整个涉及到目录文件监控、驱动javac和jar打包、反射重复加载类、文件读写等。

更多推荐

jbase实现业务脚本化

本文发布于:2023-11-16 21:07:06,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1634089.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:脚本   业务   jbase

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!