diff --git a/cool-admin.iml b/cool-admin.iml index 738cf87..d001a39 100644 --- a/cool-admin.iml +++ b/cool-admin.iml @@ -1,11 +1,8 @@ - - - - + \ No newline at end of file diff --git a/src/main/java/com/cool/CoolApplication.java b/src/main/java/com/cool/CoolApplication.java index 87be694..aff43b2 100644 --- a/src/main/java/com/cool/CoolApplication.java +++ b/src/main/java/com/cool/CoolApplication.java @@ -1,17 +1,22 @@ package com.cool; +import com.cool.core.util.PathUtils; +import com.tangzc.autotable.springboot.EnableAutoTable; +import java.util.List; +import lombok.extern.slf4j.Slf4j; import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.ApplicationArguments; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.scheduling.annotation.EnableAsync; -import com.tangzc.autotable.springboot.EnableAutoTable; - /** * CoolApplication - 应用程序的主类 * 该类配置并运行应用程序。 */ +@Slf4j @EnableAutoTable // 开启自动建表 @EnableAsync // 开启异步处理 @EnableCaching // 开启缓存 @@ -19,7 +24,51 @@ import com.tangzc.autotable.springboot.EnableAutoTable; @MapperScan("com.cool.modules.*.mapper") // 扫描指定包中的MyBatis映射器 public class CoolApplication { + private static volatile ConfigurableApplicationContext context; + private static ClassLoader mainThreadClassLoader; + public static void main(String[] args) { - SpringApplication.run(CoolApplication.class, args); + mainThreadClassLoader = Thread.currentThread().getContextClassLoader(); + context = SpringApplication.run(CoolApplication.class, args); } -} \ No newline at end of file + + /** + * 通过关闭当前上下文并启动新上下文来重启应用程序。 + */ + public static void restart(List javaPathList) { + // 从当前上下文获取应用程序参数 + ApplicationArguments args = context.getBean(ApplicationArguments.class); + + // 创建新线程来重启应用程序 + Thread thread = new Thread(() -> { + try { + // 关闭当前应用程序上下文 + context.close(); + // 等待上下文完全关闭 + while (context.isActive()) { + Thread.sleep(100); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + // 加载动态生成的代码 + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + javaPathList.forEach(javaPath -> { + try { + classLoader.loadClass(PathUtils.getClassName(javaPath)); + } catch (ClassNotFoundException e) { + log.error("loadClassErr {}", javaPath, e); + } + }); + // 使用相同的参数运行Spring Boot应用程序并设置上下文 + context = SpringApplication.run(CoolApplication.class, args.getSourceArgs()); + }); + // 设置线程的上下文类加载器 + thread.setContextClassLoader(mainThreadClassLoader); + // 确保线程不是守护线程 + thread.setDaemon(false); + // 启动线程 + thread.start(); + } + +} diff --git a/src/main/java/com/cool/core/file/strategy/LocalFileUploadStrategy.java b/src/main/java/com/cool/core/file/strategy/LocalFileUploadStrategy.java index 904d0be..ae7274d 100644 --- a/src/main/java/com/cool/core/file/strategy/LocalFileUploadStrategy.java +++ b/src/main/java/com/cool/core/file/strategy/LocalFileUploadStrategy.java @@ -11,13 +11,11 @@ import com.cool.core.exception.CoolPreconditions; import com.cool.core.file.UpLoadModeType; import com.cool.modules.plugin.entity.PluginInfoEntity; import jakarta.servlet.http.HttpServletRequest; - import java.io.File; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Objects; - import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; @@ -47,16 +45,16 @@ public class LocalFileUploadStrategy implements FileUploadStrategy { String date = DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN); String relativePath = - "/" + localFileProperties.getUploadPath() + "/" + date; + File.separator + localFileProperties.getUploadPath() + File.separator + date; FileUtil.mkdir(filePath + relativePath); for (MultipartFile file : files) { // 保存文件 String fileName = StrUtil.uuid().replaceAll("-", "") + getExtensionName( Objects.requireNonNull(file.getOriginalFilename())); - file.transferTo(new File(filePath + "/" + relativePath - + "/" + fileName)); - fileUrls.add(baseUrl + "/" + date + "/" + fileName); + file.transferTo(new File(filePath + File.separator + relativePath + + File.separator + fileName)); + fileUrls.add(baseUrl + File.separator + date + File.separator + fileName); } if (fileUrls.size() == 1) { return fileUrls.get(0); diff --git a/src/main/java/com/cool/core/plugin/service/CoolPluginService.java b/src/main/java/com/cool/core/plugin/service/CoolPluginService.java index 4155a7c..10d97cf 100644 --- a/src/main/java/com/cool/core/plugin/service/CoolPluginService.java +++ b/src/main/java/com/cool/core/plugin/service/CoolPluginService.java @@ -94,7 +94,7 @@ public class CoolPluginService { String pathStr = pluginPath; if (!PathUtils.isAbsolutePath(pluginPath)) { // 相对路径 - pathStr = System.getProperty("user.dir") + "/" + pluginPath; + pathStr = System.getProperty("user.dir") + File.separator + pluginPath; } // 将路径字符串转换为 Path 对象 Path path = Paths.get(pathStr); @@ -104,7 +104,7 @@ public class CoolPluginService { Files.createDirectories(path); } fileName = - path + "/" + System.currentTimeMillis() + "_" + file.getOriginalFilename() + ".jar"; + path + File.separator + System.currentTimeMillis() + "_" + file.getOriginalFilename() + ".jar"; jarFile = new File(fileName); file.transferTo(jarFile); // 加载jar diff --git a/src/main/java/com/cool/core/util/CompilerUtils.java b/src/main/java/com/cool/core/util/CompilerUtils.java index 2f6f2d9..8f850f9 100644 --- a/src/main/java/com/cool/core/util/CompilerUtils.java +++ b/src/main/java/com/cool/core/util/CompilerUtils.java @@ -3,13 +3,14 @@ package com.cool.core.util; import cn.hutool.core.io.FileUtil; import com.mybatisflex.processor.MybatisFlexProcessor; import java.io.File; +import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.Arrays; import java.util.List; import javax.annotation.processing.Processor; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; import javax.tools.ToolProvider; public class CompilerUtils { @@ -21,66 +22,131 @@ public class CompilerUtils { FileUtil.del(filePathStr); File file = FileUtil.touch(filePathStr); FileUtil.appendString(content, file, StandardCharsets.UTF_8.name()); + compileAndSave(filePathStr); } - public static void createMapper(String actModulePath, String fileName, String mapper) { - String pathStr = actModulePath + "/mapper/"; + public static String createMapper(String actModulePath, String fileName, String mapper) { + String pathStr = actModulePath + File.separator + "mapper" + File.separator; String filePathStr = pathStr + fileName + "Mapper.java"; createFile(mapper, filePathStr); + return filePathStr; } - public static void createServiceImpl(String actModulePath, String fileName, + public static String createServiceImpl(String actModulePath, String fileName, String serviceImpl) { - String pathStr = actModulePath + "/service/impl/"; + String pathStr = actModulePath + File.separator + "service" + File.separator + "impl" + File.separator; String filePathStr = pathStr + fileName + "ServiceImpl.java"; createFile(serviceImpl, filePathStr); + return filePathStr; } - public static void createService(String actModulePath, String fileName, String service) { - String pathStr = actModulePath + "/service/"; + public static String createService(String actModulePath, String fileName, String service) { + String pathStr = actModulePath + File.separator + "service" + File.separator; String filePathStr = pathStr + fileName + "Service.java"; createFile(service, filePathStr); + return filePathStr; } public static String createEntity(String actModulePath, String fileName, String entity) { - String pathStr = actModulePath + "/entity/"; + String pathStr = actModulePath + File.separator + "entity" + File.separator; String filePathStr = pathStr + fileName + "Entity.java"; createFile(entity, filePathStr); return filePathStr; } - public static void createController(String actModulePath, String fileName, String controller) { - String pathStr = actModulePath + "/controller/admin/"; + public static String createController(String actModulePath, String fileName, String controller) { + String pathStr = actModulePath + File.separator + "controller" + File.separator + "admin" + File.separator; String filePathStr = pathStr + "Admin" + fileName + "Controller.java"; createFile(controller, filePathStr); + return filePathStr; } public static String createModule(String modulesPath, String module) { - String pathStr = modulesPath + "/" + module; + String pathStr = modulesPath + File.separator + module; PathUtils.noExistsMk(pathStr); return pathStr; } - public static void compilerEntityTableDef(String path) { -// JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); -// StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); -// -// Iterable compilationUnits = fileManager.getJavaFileObjects( -// path); -// -// // 设置注解处理器 -// Iterable processors = Arrays.asList(new MybatisFlexProcessor()); -// // 添加 -proc:only 选项 -// List options = Arrays.asList("-proc:only"); -// JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, -// null, compilationUnits); -// task.setProcessors(processors); -// -// boolean success = task.call(); -// if (success) { -// System.out.println("Compilation and annotation processing completed successfully."); -// } else { -// System.out.println("Compilation and annotation processing failed."); -// } + public static boolean compileAndSave(String sourceFile) { + // 获取系统 Java 编译器 + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + + // 获取标准文件管理器 + try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)) { + + // 设置编译输出目录 + fileManager.setLocation(StandardLocation.CLASS_OUTPUT, List.of(new File("target" + File.separator + "classes"))); + + // 获取源文件 + List javaFiles = List.of(new File(sourceFile)); + Iterable compilationUnits = fileManager.getJavaFileObjectsFromFiles(javaFiles); + + // 创建编译任务 + JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, compilationUnits); + // 执行编译任务 + return task.call(); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + public static void compilerEntityTableDef(String actModulePath, String fileName, String entityPath, List javaPathList) { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)) { + Iterable compilationUnits = fileManager.getJavaFileObjects( + entityPath); +// // 设置注解处理器 + Iterable processors = List.of(new MybatisFlexProcessor()); +// // 添加 -proc:only 选项 + List options = List.of("-proc:only"); + JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, + null, compilationUnits); + task.setProcessors(processors); + task.call(); + compilationUnits = fileManager.getJavaFileObjects( + javaPathList.toArray(new String[0])); + // 需在entity之后加载 + // 设置编译输出目录 + fileManager.setLocation(StandardLocation.CLASS_OUTPUT, List.of(new File("target/classes"))); + + task = compiler.getTask(null, fileManager, null, null, null, compilationUnits); + String pathStr = actModulePath + File.separator + "entity" + File.separator + "table" + File.separator; + String filePathStr = pathStr + fileName + "EntityTableDef.java"; + javaPathList.add(1, filePathStr); + boolean success = task.call(); + if (success) { + System.out.println("Compilation and annotation processing completed successfully."); + String commPath = PathUtils.getUserDir() + File.separator + "com"; + if (countFiles(new File(commPath)) <= 1) { + FileUtil.clean(commPath); + FileUtil.del(commPath); + } + } else { + System.out.println("Compilation and annotation processing failed."); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + private static int countFiles(File directory) { + File[] files = directory.listFiles(); + if (files == null) { + return 0; + } + + int count = 0; + for (File file : files) { + if (file.isFile()) { + count++; + } else if (file.isDirectory()) { + count += countFiles(file); + } + // If more than one file is found, no need to continue counting + if (count > 1) { + break; + } + } + return count; } } diff --git a/src/main/java/com/cool/core/util/PathUtils.java b/src/main/java/com/cool/core/util/PathUtils.java index 72bed3e..694611b 100644 --- a/src/main/java/com/cool/core/util/PathUtils.java +++ b/src/main/java/com/cool/core/util/PathUtils.java @@ -2,6 +2,7 @@ package com.cool.core.util; import cn.hutool.core.io.file.PathUtil; import com.cool.CoolApplication; +import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; @@ -17,8 +18,21 @@ public class PathUtils { } public static String getModulesPath() { - return getUserDir() + "/src/main/java/" + CoolApplication.class.getPackageName() - .replace(".", "/") + "/modules"; + return getUserDir() + File.separator + "src"+ File.separator + "main" + File.separator + "java" + File.separator + CoolApplication.class.getPackageName() + .replace(".", File.separator) + File.separator + "modules"; + } + + public static String getClassName(String filePath) { + // 定位 "src/main/java" 在路径中的位置 + int srcMainJavaIndex = filePath.indexOf("src" + File.separator + "main" + File.separator + "java"); + if (srcMainJavaIndex == -1) { + throw new IllegalArgumentException("File path does not contain 'src/main/java'"); + } + + // 提取 "src/main/java" 之后的路径 + // 将文件分隔符替换为包分隔符 + return filePath.substring(srcMainJavaIndex + ("src" + File.separator + "main" + File.separator + "java").length() + 1) + .replace(File.separator, ".").replace(".java", ""); } /** diff --git a/src/main/java/com/cool/modules/base/service/sys/impl/BaseSysMenuServiceImpl.java b/src/main/java/com/cool/modules/base/service/sys/impl/BaseSysMenuServiceImpl.java index fb07917..5927db6 100644 --- a/src/main/java/com/cool/modules/base/service/sys/impl/BaseSysMenuServiceImpl.java +++ b/src/main/java/com/cool/modules/base/service/sys/impl/BaseSysMenuServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.json.JSONObject; +import com.cool.CoolApplication; import com.cool.core.base.BaseServiceImpl; import com.cool.core.base.ModifyEnum; import com.cool.core.util.CompilerUtils; @@ -147,24 +148,25 @@ public class BaseSysMenuServiceImpl extends BaseServiceImpl javaPathList = new ArrayList<>(); String modulesPath = PathUtils.getModulesPath(); // 创建的模块地址 String actModulePath = CompilerUtils.createModule(modulesPath, module); - // 创建 controller - CompilerUtils.createController(actModulePath, fileName, controller); + // 创建顺序不能调整,类加载的时候需按这个顺序加载,否则类找不到 // 创建 entity String entityPath = CompilerUtils.createEntity(actModulePath, fileName, entity); - // 创建 service - CompilerUtils.createService(actModulePath, fileName, service); - // 创建 serviceImpl - CompilerUtils.createServiceImpl(actModulePath, fileName, serviceImpl); + javaPathList.add(entityPath); // 创建 mapper - CompilerUtils.createMapper(actModulePath, fileName, mapper); - // 关闭springboot - System.exit(0); + javaPathList.add(CompilerUtils.createMapper(actModulePath, fileName, mapper)); + // 创建 service + javaPathList.add(CompilerUtils.createService(actModulePath, fileName, service)); + // 创建 serviceImpl + javaPathList.add(CompilerUtils.createServiceImpl(actModulePath, fileName, serviceImpl)); + // 创建 controller + javaPathList.add(CompilerUtils.createController(actModulePath, fileName, controller)); // 构建TableDef - // CompilerUtils.compilerEntityTableDef(entityPath); + CompilerUtils.compilerEntityTableDef(actModulePath, fileName, entityPath, javaPathList); // 重启 - // CoolApplication.restart(); + CoolApplication.restart(javaPathList); } } \ No newline at end of file