设计器基本完成,就剩打磨了,今天换个口味,完成最后目标,JRT的框架申明的是业务脚本化,而写业务基本离不开实体类,实体类是经常改动的,所以实体的可维护性也很重要,需要给发布程序直接放实体代码,支持命令编译实体。
Windows下效果
Linux上效果
实现代码
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.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/**
* 编译JRT架构下的实体jar包,编译的实体工程文件和代码放在Web的CompileModel下面,驱动java -cp D:\JRTPlan\WebLoader\WebSrc\webapps\JRTWeb\CompileModel BuildModel JRT.Model来编译,
* JRT.Model为实体的文件名称,将借助此工具实现JRT的业务脚本化目标部分的实体代码脚本化部分,在Web下的CompileModel放实体代码,需要改实体时候修改代码后运行jrt命令选8编译实体即可,
* 实体的业务脚本化不采用自动编译的模式,和普通业务脚本的差别就是让人命令执行
*/
public class BuildModel {
/**
* 实体名称
*/
private static String ModeDirName = "JRT.Model";
/**
* 实体编译入口
*
* @param args
*/
public static void main(String[] args) {
try {
//检查参数
if (args == null || args.length == 0) {
System.out.println("请传入实体文件夹名字");
return;
} else {
ModeDirName = args[0];
}
System.out.println("开始编译实体...");
//创建编译对象
BuildModel bl = new BuildModel();
//开始编译
bl.BuildJava();
} catch (Exception ex) {
ex.printStackTrace(System.out);
}
}
/**
* 编译java代码
*
* @throws Exception
*/
public void BuildJava() throws Exception {
//得到.class所在的路径CompileModel
String srcpath = this.getClass().getResource("").getPath();
String curPath = new File(srcpath).toString();
//上一级是Web的路径
String webPath = new File(curPath).getParent();
//编译成功了就生成这样的文件表示成功
String successFilePath = Paths.get(curPath, "buildsuccess.jrt").toString();
File successFile = new File(successFilePath);
//删删除成功标志
if (successFile.exists()) {
successFile.delete();
}
//编译执行
int retcode = BuildJavaDo(webPath, curPath);
//编译成功
if (retcode == 0) {
successFile.createNewFile();
}
System.out.println("编译结束返回:" + retcode);
}
/**
* 编译java执行
*
* @param webPath 网站路径
* @param curPath 编译程序class所在路径
* @return 返回0编译成功
* @throws Exception
*/
private int BuildJavaDo(String webPath, String curPath) throws Exception {
File fiBase = new File(webPath);
String parentPath = fiBase.getParent();
//到webapps一级
File fiParent = new File(parentPath);
//到WebSrc一级
File fiParent1 = new File(fiParent.getParent());
//jar包存放路径
String libPath = Paths.get(fiParent1.toString(), "lib").toString() + File.separator;
System.out.println("jar包路径:" + libPath);
String cmd = "javac -encoding UTF-8 -classpath ";
//实体代码文件夹
String modelPath = Paths.get(curPath, ModeDirName).toString();
//实体代码工程文件
String imlFile = Paths.get(modelPath, ModeDirName + ".iml").toString();
//判断配置是否存在
File iml = new File(imlFile);
if (!iml.exists()) {
System.out.println(imlFile + "文件不存在,请确认!");
return -1;
}
//解析xml
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(iml);
//获得根节点
Element rootElement = document.getDocumentElement();
//获得根节点下的所有子节点
NodeList students = rootElement.getElementsByTagName("component");
String classPath = "";
String sp = ";";
if (IsOSLinux()) {
sp = ":";
}
//解析配置,得到依赖jar包
for (int i = 0; i < students.getLength(); i++) {
//由于节点多种类型,而一般我们需要处理的是元素节点
Node childNode = students.item(i);
//元素节点就是非空的子节点,也就是还有孩子的子节点
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
Element childElement = (Element) childNode;
NodeList children = childElement.getChildNodes();
for (int k = 0; k < children.getLength(); k++) {
Node child = children.item(k);
if (child.getNodeType() == Node.ELEMENT_NODE) {
childElement = (Element) child;
//不是对象配置元素就忽略
if (childElement.getNodeName() != "orderEntry") {
continue;
}
//解析得到包名
String name = childElement.getAttribute("name");
String type = childElement.getAttribute("type");
if (!type.equals("library")) {
continue;
}
String oneJarPath = Paths.get(libPath, name + ".jar").toString();
if (classPath == "") {
classPath = oneJarPath;
} else {
classPath += sp + oneJarPath;
}
}
}
}
}
//遍历目录下所有java文件,组装成路径串,英文,分割路径
File modeldir = new File(modelPath);
System.out.println("查找:" + modeldir + "下的.java文件");
//遍历文件
List<String> files = SeeFile(modeldir, ".java");
int execode = -1;
Runtime exe = Runtime.getRuntime();
//循环遍历路径编译文件
if (files.size() > 0) {
System.out.println("找到:" + files.size() + "个.java文件");
String pathstr = "";
int count = 0;
for (int i = 0; i < files.size(); i++) {
String path = files.get(i);
//空路径退出
if (path.isEmpty()) {
continue;
}
if (pathstr.isEmpty()) {
pathstr = path;
} else {
pathstr = pathstr + " " + path;
}
count++;
//一次编译100个文件,太多文件导致串太长,编译报错
if (((count) % 100 == 0) || ((i + 1) == files.size())) {
System.out.println("执行编译:" + i + 1);
String execcmd = cmd + classPath + " " + pathstr;
//执行编译命令
execode = Exec(exe, execcmd, webPath);
pathstr = "";
if (execode != 0) {
break;
}
}
}
System.out.println("编译结束!");
} else {
execode = 0;
System.out.println("找到:" + files.size() + "个.java文件");
System.out.println("没有需要编译的.java文件");
}
//编译成功,打包编译的class文件为jar包
if (execode == 0) {
System.out.println("编译成功!");
String modelpath = Paths.get(curPath, ModeDirName).toString();
String jarFileStr = ModeDirName + ".jar";
//临时目录
Path tmppath = Paths.get(curPath, "ModelTmp");
if (!tmppath.toFile().exists()) {
Files.createDirectory(tmppath);
}
String[] modelArr = ModeDirName.split("\\.");
Path tmpmodel = Paths.get(tmppath.toString(), modelArr[0], modelArr[1]);
//没有的路径就创建
if (!tmpmodel.toFile().exists()) {
Files.createDirectories(tmpmodel);
}
//拷贝class文件到临时目录
Files.walk(Paths.get(modelpath)).filter(Files::isRegularFile).forEach((Path var) -> {
try {
File file = var.toFile();
String fileabpath = file.getAbsolutePath().replace(modelpath, tmpmodel.toString());
//不是.class的退出
if (!fileabpath.endsWith(".class")) {
return;
}
Path par = Paths.get(fileabpath).getParent();
//没路径的创建
if (!par.toFile().exists()) {
Files.createDirectories(par);
}
//把class文件复制到新的目录,方便打包
Files.copy(var, Paths.get(fileabpath), StandardCopyOption.REPLACE_EXISTING);
} catch (Exception ex) {
ex.printStackTrace(System.out);
}
});
System.out.println("打包:" + tmppath + "到:" + jarFileStr);
cmd = "jar cf " + jarFileStr + " -C " + tmppath + " .";
execode = Exec(exe, cmd, curPath);
if (execode == 0) {
System.out.println("打包完成!");
//打包完成清除class文件,减少网站目录的文件数
Files.walk(tmppath).filter(Files::isRegularFile).map(Path::toFile).forEach(File::deleteOnExit);
}
}
return execode;
}
/**
* 执行cmd命令
*
* @param exe
* @param cmd
* @param workdir
* @return
* @throws Exception
*/
private int Exec(Runtime exe, String cmd, String workdir) throws Exception {
if (workdir == null || workdir.isEmpty()) {
workdir = ".";
}
System.out.println("执行:" + cmd);
Process ps = exe.exec(cmd, null, Paths.get(workdir).toFile());
// 获取命令行程序的输出结果
StringBuilder retsb = new StringBuilder();
//windows默认gb18030编码读取错误信息
String charset = "gb18030";
if (IsOSLinux()) {
//linux用fut-8编码
charset = "utf-8";
}
BufferedReader reader = new BufferedReader(new InputStreamReader(ps.getErrorStream(), charset));
String line;
while ((line = reader.readLine()) != null) {
retsb.append(line);
}
int execode = ps.waitFor();
ps.destroy();
if (execode == 0) {
System.out.println("执行成功!");
} else {
System.out.println("执行失败!");
System.out.println(retsb);
}
return execode;
}
/**
* 判断OS
*
* @return 得到是否是Linux
*/
public static boolean IsOSLinux() {
Properties prop = System.getProperties();
String os = prop.getProperty("os.name");
if (os != null && os.toLowerCase().indexOf("linux") > -1) {
return true;
} else {
return false;
}
}
/**
* 扫描文件
*
* @param dir
* @param fileext
* @return
* @throws Exception
*/
public static List<String> SeeFile(File dir, String fileext) throws Exception {
ArrayList<String> list = new ArrayList<>();
if (!dir.exists()) return list;
if (dir.isFile()) {
list.add(dir.getPath());
return list;
}
Files.walk(dir.toPath()).filter(Files::isRegularFile).map(Path::toFile).forEach((File f) -> {
String file = f.getPath();
if (fileext != null && !fileext.isEmpty() && !file.toLowerCase().endsWith(fileext.toLowerCase())) {
return;
}
if (fileext.equals(".java")) {
String clspath = file.replace(".java", ".class");
File clsfile = new File(clspath);
if (clsfile.exists()) {
//java文件与之相应的class文件修改时间对比,class文件修改时间新就不编译
long clsmodtime = clsfile.lastModified();
long javamodtime = new File(file).lastModified();
if (clsmodtime > javamodtime) {
return;
}
}
}
list.add(f.getPath());
});
return list;
}
}
用cpp实现jrt命令
sh代码
投放目录
Linux下发布https,编译实体测试
这样除了打印设计器需要完善,各种难点全部解决,已经达到发布水平