diff --git a/cloud-rule-engine/pom.xml b/cloud-rule-engine/pom.xml index b899d8e..6f33720 100644 --- a/cloud-rule-engine/pom.xml +++ b/cloud-rule-engine/pom.xml @@ -107,6 +107,12 @@ 2.3.3 + + com.itranswarp + compiler + 1.0 + + junit junit diff --git a/cloud-rule-engine/src/main/java/com/muyu/compile/MemoryClassLoader.java b/cloud-rule-engine/src/main/java/com/muyu/compile/MemoryClassLoader.java new file mode 100644 index 0000000..ea3f855 --- /dev/null +++ b/cloud-rule-engine/src/main/java/com/muyu/compile/MemoryClassLoader.java @@ -0,0 +1,33 @@ +package com.muyu.compile; + +import java.net.URL; +import java.net.URLClassLoader; +import java.util.HashMap; +import java.util.Map; + +/** + * Load class from byte[] which is compiled in memory. + * + * @author michael + */ +class MemoryClassLoader extends URLClassLoader { + + // class name to class bytes: + Map classBytes = new HashMap(); + + public MemoryClassLoader(Map classBytes) { + super(new URL[0], MemoryClassLoader.class.getClassLoader()); + this.classBytes.putAll(classBytes); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + byte[] buf = classBytes.get(name); + if (buf == null) { + return super.findClass(name); + } + classBytes.remove(name); + return defineClass(name, buf, 0, buf.length); + } + +} diff --git a/cloud-rule-engine/src/main/java/com/muyu/compile/MemoryJavaFileManager.java b/cloud-rule-engine/src/main/java/com/muyu/compile/MemoryJavaFileManager.java new file mode 100644 index 0000000..29b82bb --- /dev/null +++ b/cloud-rule-engine/src/main/java/com/muyu/compile/MemoryJavaFileManager.java @@ -0,0 +1,91 @@ +package com.muyu.compile; + +import javax.tools.*; +import javax.tools.JavaFileObject.Kind; +import java.io.ByteArrayOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.nio.CharBuffer; +import java.util.HashMap; +import java.util.Map; + +/** + * In-memory java file manager. + * + * @author michael + */ +class MemoryJavaFileManager extends ForwardingJavaFileManager { + + // compiled classes in bytes: + final Map classBytes = new HashMap(); + + MemoryJavaFileManager(JavaFileManager fileManager) { + super(fileManager); + } + + public Map getClassBytes() { + return new HashMap(this.classBytes); + } + + @Override + public void flush() throws IOException { + } + + @Override + public void close() throws IOException { + classBytes.clear(); + } + + @Override + public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, + FileObject sibling) throws IOException { + if (kind == Kind.CLASS) { + return new MemoryOutputJavaFileObject(className); + } else { + return super.getJavaFileForOutput(location, className, kind, sibling); + } + } + + JavaFileObject makeStringSource(String name, String code) { + return new MemoryInputJavaFileObject(name, code); + } + + static class MemoryInputJavaFileObject extends SimpleJavaFileObject { + + final String code; + + MemoryInputJavaFileObject(String name, String code) { + super(URI.create("string:///" + name), Kind.SOURCE); + this.code = code; + } + + @Override + public CharBuffer getCharContent(boolean ignoreEncodingErrors) { + return CharBuffer.wrap(code); + } + } + + class MemoryOutputJavaFileObject extends SimpleJavaFileObject { + final String name; + + MemoryOutputJavaFileObject(String name) { + super(URI.create("string:///" + name), Kind.CLASS); + this.name = name; + } + + @Override + public OutputStream openOutputStream() { + return new FilterOutputStream(new ByteArrayOutputStream()) { + @Override + public void close() throws IOException { + out.close(); + ByteArrayOutputStream bos = (ByteArrayOutputStream) out; + classBytes.put(name, bos.toByteArray()); + } + }; + } + + } +} diff --git a/cloud-rule-engine/src/main/java/com/muyu/compile/OSSFileCompile.java b/cloud-rule-engine/src/main/java/com/muyu/compile/OSSFileCompile.java new file mode 100644 index 0000000..a484a98 --- /dev/null +++ b/cloud-rule-engine/src/main/java/com/muyu/compile/OSSFileCompile.java @@ -0,0 +1,36 @@ +package com.muyu.compile; + + +import javax.tools.*; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * @Author:蓬叁 + * @Package:com.muyu.compile + * @Project:cloud-rule + * @name:OSSFileCompile + * @Date:2024/8/31 下午7:08 + */ +public class OSSFileCompile{ + + public static Map compile(String fileName, String source,String extLib) throws IOException { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager stdManager = compiler.getStandardFileManager(null, null, null); + try (MemoryJavaFileManager manager = new MemoryJavaFileManager(stdManager)) { + JavaFileObject javaFileObject = manager.makeStringSource(fileName, source); + // 传入诊断监听器 size和传入的javaObject相同 + DiagnosticCollector diagnosticCollector = new DiagnosticCollector(); + List optionList = Arrays.asList("-extdirs",extLib); + JavaCompiler.CompilationTask task = compiler.getTask(null, manager,diagnosticCollector, optionList, null, Arrays.asList(javaFileObject)); + Boolean result = task.call(); + if (result == null || !result.booleanValue()) { + throw new RuntimeException("Compilation failed."); + } + return manager.getClassBytes(); + } + } + +} diff --git a/cloud-rule-engine/src/main/java/com/muyu/load/OSSFileLoad.java b/cloud-rule-engine/src/main/java/com/muyu/load/OSSFileLoad.java new file mode 100644 index 0000000..1e699e6 --- /dev/null +++ b/cloud-rule-engine/src/main/java/com/muyu/load/OSSFileLoad.java @@ -0,0 +1,72 @@ +package com.muyu.load; + +import com.aliyun.oss.OSSClient; +import com.aliyun.oss.model.OSSObject; +import com.muyu.common.core.domain.Result; +import com.muyu.compile.OSSFileCompile; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Map; + +/** + * @Author:蓬叁 + * @Package:com.muyu.load + * @Project:cloud-rule + * @name:OSSFileLoad + * @Date:2024/8/31 下午6:38 + */ +public class OSSFileLoad { + + // 阿里云 endpoint + private static final String endpoint = "oss-cn-shanghai.aliyuncs.com"; + // 阿里云 accessKeyId + private static final String accessKeyId = "LTAI5tHKdDATVKeBjFH8mb8D"; + // 阿里云 accessKeySecret   + private static final String accessKeySecret = "5ejb4qdgukfD1FdM181kdeAkSuURo7"; + // bucket + private static final String bucketName = "java-web-generating-class"; + + public static Result streamingDownload(String fileName) { + try { + // 创建 OSSClient 实例 + OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret); + // 判断 bucket 是否存在 + Boolean flag_bucket = ossClient.doesBucketExist(bucketName); + if (!flag_bucket) { + return Result.error("bucket不存在"); + } + // 判断 要下载的文件 是否存在 + Boolean flag_file = ossClient.doesObjectExist(bucketName, fileName); + if (!flag_file) { + return Result.error("预下载文件不存在"); + } + // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流 + OSSObject ossObject = ossClient.getObject(bucketName, fileName); + // 按行读取文件内容 + BufferedReader reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent())); + + String source = null; + + while(true){ + String line = reader.readLine(); + source = source + line; + if (line == null) break; + } + + // 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作 + reader.close(); + // 关闭oss + ossClient.shutdown(); + + Map compile = OSSFileCompile.compile(fileName, source, "target/classes/com/muyu/generate"); + compile.forEach((key, value) -> {}); + + } catch (IOException e) { + e.fillInStackTrace(); + } + return Result.success(null,"编译成功"); + } + +} diff --git a/cloud-rule-engine/src/main/java/com/muyu/upload/ALiYunUpload.java b/cloud-rule-engine/src/main/java/com/muyu/upload/ALiYunUpload.java index 253afda..67fd0bd 100644 --- a/cloud-rule-engine/src/main/java/com/muyu/upload/ALiYunUpload.java +++ b/cloud-rule-engine/src/main/java/com/muyu/upload/ALiYunUpload.java @@ -45,7 +45,7 @@ public class ALiYunUpload { OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // 上传到OSS后文件保存的目录,例如:folder/subfolder/,最后以斜杠结尾 - String objectName = "build/rule/"+fileName+".java"; + String objectName = "build/version/rule/"+fileName+".java"; try { // 将内容转换为字节数组输入流 diff --git a/cloud-rule-engine/src/main/java/com/muyu/upload/OssUtil.java b/cloud-rule-engine/src/main/java/com/muyu/upload/OssUtil.java deleted file mode 100644 index e2b631f..0000000 --- a/cloud-rule-engine/src/main/java/com/muyu/upload/OssUtil.java +++ /dev/null @@ -1,162 +0,0 @@ -package com.muyu.upload; - -import com.aliyun.oss.OSS; -import com.aliyun.oss.OSSClientBuilder; -import com.aliyun.oss.model.GetObjectRequest; -import com.aliyun.oss.model.PutObjectRequest; -import lombok.extern.log4j.Log4j2; -import org.springframework.web.multipart.MultipartFile; - -import java.io.*; -import java.time.LocalDateTime; -import java.util.UUID; - -/** - * Oss服务调用 - */ -@Log4j2 -public class OssUtil { - - /** - * Endpoint 存储对象概述 阿里云主账号AccessKey,accessKeySecret拥有所有API的访问权限 访问路径前缀 存储对象概述 - */ - private static String endPoint = "oss-cn-shanghai.aliyuncs.com"; - private static String accessKeyId = "LTAI5tHKdDATVKeBjFH8mb8D"; - private static String accessKeySecret = "5ejb4qdgukfD1FdM181kdeAkSuURo7"; - private static String accessPre = "https://mall-bw.oss-cn-shanghai.aliyuncs.com/"; - - /** - * bucket名称 - * - * @return - */ - private static String bucketName = "mall-bw"; - - private static OSS ossClient; - - static { - ossClient = new OSSClientBuilder().build( - endPoint, - accessKeyId, - accessKeySecret); - log.info("oss服务连接成功!"); - } - - /** - * 默认路径上传本地文件 - * - * @param filePath - */ - public static String uploadFile(String filePath) { - return uploadFileForBucket(bucketName, getOssFilePath(filePath), filePath); - } - - /** - * 默认路径上传multipartFile文件 - * - * @param multipartFile - */ - public static String uploadMultipartFile(MultipartFile multipartFile) { - return uploadMultipartFile(bucketName, getOssFilePath(multipartFile.getOriginalFilename()), multipartFile); - } - - /** - * 上传 multipartFile 类型文件 - * - * @param bucketName - * @param ossPath - * @param multipartFile - */ - public static String uploadMultipartFile(String bucketName, String ossPath, MultipartFile multipartFile) { - InputStream inputStream = null; - try { - inputStream = multipartFile.getInputStream(); - } catch (IOException e) { - e.printStackTrace(); - } - uploadFileInputStreamForBucket(bucketName, ossPath, inputStream); - return accessPre + ossPath; - } - - /** - * 使用File上传PutObject上传文件 ** 程序默认使用次方法上传 - * - * @param bucketName 实例名称 - * @param ossPath oss存储路径 - * @param filePath 本地文件路径 - */ - public static String uploadFileForBucket(String bucketName, String ossPath, String filePath) { - // 创建PutObjectRequest对象。 - PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, ossPath, new File(filePath)); - - // 上传 - ossClient.putObject(putObjectRequest); - return accessPre + ossPath; - } - - /** - * 使用文件流上传到指定的bucket实例 - * - * @param bucketName 实例名称 - * @param ossPath oss存储路径 - * @param filePath 本地文件路径 - */ - public static String uploadFileInputStreamForBucket(String bucketName, String ossPath, String filePath) { - - // 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。 - InputStream inputStream = null; - try { - inputStream = new FileInputStream(filePath); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - // 填写Bucket名称和Object完整路径。Object完整路径中不能包含Bucket名称。 - uploadFileInputStreamForBucket(bucketName, ossPath, inputStream); - return accessPre + ossPath; - } - - public static void uploadFileInputStreamForBucket(String bucketName, String ossPath, InputStream inputStream) { - ossClient.putObject(bucketName, ossPath, inputStream); - } - - /** - * 下载 - * - * @param ossFilePath - * @param filePath - */ - public static void downloadFile(String ossFilePath, String filePath) { - downloadFileForBucket(bucketName, ossFilePath, filePath); - } - - /** - * 下载 - * - * @param bucketName 实例名称 - * @param ossFilePath oss存储路径 - * @param filePath 本地文件路径 - */ - public static void downloadFileForBucket(String bucketName, String ossFilePath, String filePath) { - ossClient.getObject(new GetObjectRequest(bucketName, ossFilePath), new File(filePath)); - } - - /** - * @return - */ - public static String getOssDefaultPath() { - LocalDateTime now = LocalDateTime.now(); - String url = - now.getYear() + "/" + - now.getMonth() + "/" + - now.getDayOfMonth() + "/" + - now.getHour() + "/" + - now.getMinute() + "/"; - return url; - } - - public static String getOssFilePath(String filePath) { - String fileSuf = filePath.substring(filePath.indexOf(".") + 1); - return getOssDefaultPath() + UUID.randomUUID().toString() + "." + fileSuf; - } - -} diff --git a/cloud-rule-server/src/main/java/com/muyu/controller/RuleVersionController.java b/cloud-rule-server/src/main/java/com/muyu/controller/RuleVersionController.java index 106b251..9dc8bc4 100644 --- a/cloud-rule-server/src/main/java/com/muyu/controller/RuleVersionController.java +++ b/cloud-rule-server/src/main/java/com/muyu/controller/RuleVersionController.java @@ -8,6 +8,7 @@ import com.muyu.common.domain.req.RuleDataUpdReq; import com.muyu.common.domain.req.RuleVersionAddReq; import com.muyu.common.domain.req.RuleVersionUpdReq; import com.muyu.common.domain.resp.RuleVersionResp; +import com.muyu.load.OSSFileLoad; import com.muyu.servier.RuleVersionService; import com.muyu.upload.ALiYunUpload; import io.swagger.v3.oas.annotations.Operation; diff --git a/cloud-rule-server/src/main/java/com/muyu/servier/impl/RuleVersionServiceImpl.java b/cloud-rule-server/src/main/java/com/muyu/servier/impl/RuleVersionServiceImpl.java index 321ebbf..4b80edb 100644 --- a/cloud-rule-server/src/main/java/com/muyu/servier/impl/RuleVersionServiceImpl.java +++ b/cloud-rule-server/src/main/java/com/muyu/servier/impl/RuleVersionServiceImpl.java @@ -10,6 +10,7 @@ import com.muyu.common.domain.RuleVersion; import com.muyu.common.domain.req.RuleVersionUpdReq; import com.muyu.common.domain.resp.RuleVersionResp; import com.muyu.constant.GenerateConstant; +import com.muyu.load.OSSFileLoad; import com.muyu.mapper.RuleVersionMapper; import com.muyu.servier.RuleDataService; import com.muyu.servier.RuleVersionService; @@ -76,6 +77,7 @@ public class RuleVersionServiceImpl RuleData ruleData = ruleDataService.getById(ruleVersion.getRuleId()); ruleVersion.setRuleVersionType("generate"+"_"+ruleData.getRuleCoding()+"_"+ruleVersion.getRuleVersionCode()); ruleVersion.setRuleVersionText(GenerateConstant.generateConstant(ruleData,ruleVersion)); + OSSFileLoad.streamingDownload(ruleVersion.getRuleVersionType()+".java"); return ruleVersion; }