# Java使用Maven及Gitlab ## Java使用Maven ### 所需依赖 ```xml org.apache.maven maven-embedder 3.9.6 org.apache.maven maven-compat 3.9.6 org.apache.maven.resolver maven-resolver-transport-http 1.9.18 org.apache.maven.resolver maven-resolver-connector-basic 1.9.18 org.apache.maven maven-resolver-provider 3.9.6 org.apache.maven maven-settings-builder 3.9.6 ``` ### 使用Archetype生成项目 ```java package org.jeecg.modules.devops.archetype; import lombok.extern.slf4j.Slf4j; import org.apache.maven.cli.MavenCli; import org.jeecg.modules.devops.model.YuanMengOnlineService; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @Slf4j public class MavenUtils { private static final String ARCHETYPE_GROUP_ID = "com.yuanmeng.engine"; private static final String ARCHETYPE_ARTIFACT_ID = "engine-archetype-web"; private static final String ARCHETYPE_VERSION = "2.0.2-SNAPSHOT"; public static Path createProject(YuanMengOnlineService archetypeInfo) { try { // 配置项目目录 Path projectDir = Files.createTempDirectory(archetypeInfo.getArchetypeArtifactId()); log.info("项目生成目录: {}", projectDir); // 创建 settings.xml 文件 Path settingsFile = createTempSettingsFile(); // 下面这行代码不能缺少,否则无法执行 configureSystemProperties(settingsFile); // 使用 Maven Embedder 生成项目 generateMavenProject(projectDir.toFile(), settingsFile, archetypeInfo); Path path = projectDir.resolve(archetypeInfo.getArchetypeArtifactId()); log.info("✅ 项目成功创建于: {}", path); return path; } catch (Exception e) { log.error("❌ 出现错误: {}, {}", e.getMessage(), archetypeInfo, e); throw new RuntimeException("项目初始化失败:" + e.getMessage()); } } private static void generateMavenProject(File baseDir, Path settingsFile, YuanMengOnlineService archetypeInfo) { // 构建 Maven 参数 String[] mvnArgs = new String[]{ "archetype:generate", "-DinteractiveMode=false", "-DarchetypeGroupId=" + ARCHETYPE_GROUP_ID, "-DarchetypeArtifactId=" + ARCHETYPE_ARTIFACT_ID, "-DarchetypeVersion=" + ARCHETYPE_VERSION, "-DgroupId=" + archetypeInfo.getArchetypeGroupId(), "-DartifactId=" + archetypeInfo.getArchetypeArtifactId(), "-Dversion=" + archetypeInfo.getArchetypeVersion(), "-Dapp=" + archetypeInfo.getArchetypeApp(), "-Dpackage=" + archetypeInfo.getArchetypePackage(), "-B", // 开启批处理模式 "-s", settingsFile.toString() }; log.info("Maven 项目生成指令:{}", String.join(" ", mvnArgs)); // 使用 Maven Embedder MavenCli cli = new MavenCli(); int result = cli.doMain(mvnArgs, baseDir.getAbsolutePath(), System.out, System.err); if (result != 0) { throw new RuntimeException("Maven 项目生成失败 (退出码: " + result + ")"); } log.info("✅ Maven 项目生成成功"); } private static Path createTempSettingsFile() { try { // 创建临时 settings.xml 文件 Path settingsPath = Files.createTempFile("maven-settings", ".xml"); // 构建 settings.xml 内容 String settingsContent = buildSettingsXml(); // 写入文件 Files.write(settingsPath, settingsContent.getBytes()); // 设置文件删除钩子(程序退出时删除) settingsPath.toFile().deleteOnExit(); return settingsPath; } catch (IOException e) { throw new RuntimeException("Failed to create temp settings.xml", e); } } private static String buildSettingsXml() { return "\n" + " /tmp/repository\n" + " \n" + " \n" + " private-repo\n" + " developer\n" + " deve@123\n" + " \n" + " \n" + " \n" + " \n" + " private-repo\n" + " Private Repository Mirror\n" + " http://120.79.68.191:8081/repository/maven-public/\n" + " *\n" + " \n" + " \n" + " \n" + " \n" + " default\n" + " \n" + " \n" + " private-repo\n" + " http://120.79.68.191:8081/repository/maven-public/\n" + " true\n" + " true\n" + " \n" + " \n" + " \n" + " \n" + " private-repo\n" + " http://120.79.68.191:8081/repository/maven-public/\n" + " true\n" + " true\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " default\n" + " \n" + ""; } private static void configureSystemProperties(Path settingsPath) { System.setProperty("maven.multiModuleProjectDirectory", System.getProperty("user.dir")); // 使用自定义 settings.xml System.setProperty("maven.user.settings", settingsPath.toString()); // 配置超时(可选) System.setProperty("maven.wagon.http.readTimeout", "300000"); // 5分钟 System.setProperty("maven.wagon.http.connectionTimeout", "120000"); // 禁用 SSL 验证(如果私服使用 HTTP) System.setProperty("maven.wagon.http.ssl.insecure", "true"); System.setProperty("maven.wagon.http.ssl.allowall", "true"); // 启用调试日志(可选) System.setProperty("org.slf4j.simpleLogger.log.org.apache.maven.cli", "info"); } } ``` ---- ## Java操作Git及Gitlab ### 依赖引入 ```xml org.eclipse.jgit org.eclipse.jgit 6.10.1.202505221210-r org.gitlab4j gitlab4j-api 5.3.0 ``` ### Java代码调用 #### Gitlab调用工具类 ```java package org.jeecg.modules.devops.archetype; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSONObject; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.gitlab4j.api.GitLabApi; import org.gitlab4j.api.GitLabApiException; import org.gitlab4j.api.models.*; import java.util.List; import java.util.Objects; /** * insert description here * * @author liuxiaohua * @since 2025-06-11 */ @Slf4j public class GitlabUtils { private static volatile GitLabApi gitLabApi; public static synchronized void init(ArchetypeProperties archetypeProperties) { if (gitLabApi == null) { synchronized (GitlabUtils.class) { if (gitLabApi == null) { gitLabApi = new GitLabApi(archetypeProperties.getGitlabUrl(), archetypeProperties.getAccessToken()); } } } } @SneakyThrows public static void deleteProject(Long projectId) { gitLabApi.getProjectApi().deleteProject(projectId); } @SneakyThrows public static Project createProject(String group, String project, String desc) { Group groupInfo = getGroupId(group); if (Objects.isNull(groupInfo) || Objects.isNull(groupInfo.getId())) { throw new RuntimeException("获取分组信息失败"); } Project gitLabRepository = createRepository(groupInfo, project, desc); if (gitLabRepository == null || gitLabRepository.getId() == null) { throw new RuntimeException("创建仓库失败"); } return gitLabRepository; } @SneakyThrows public static ProtectedBranch protectedBranch(Long projectId, Integer retryTimes) { try { // 获取已保护的分支 List protectedBranches = gitLabApi.getProtectedBranchesApi().getProtectedBranches(projectId); log.info("protected branches: {}", JSONObject.toJSONString(protectedBranches)); // 保护分支 if (CollUtil.isNotEmpty(protectedBranches) && protectedBranches.stream().map(ProtectedBranch::getName).anyMatch("master"::equalsIgnoreCase)) { // 取消旧的配置 unprotectedBranch(projectId); } // 添加分支保护 return gitLabApi.getProtectedBranchesApi() .protectBranch(projectId, "master", AccessLevel.NONE, AccessLevel.MAINTAINER); } catch (GitLabApiException e) { log.warn("protected branch failed: {}", e.getMessage()); } if (retryTimes < 3) { return protectedBranch(projectId, ++retryTimes); } log.warn("protected branch failure: {}", retryTimes); throw new RuntimeException(ArchetypeUtils.WARN_MESSAGE_1); } private static void unprotectedBranch(Long projectId) { try { gitLabApi.getProtectedBranchesApi().unprotectBranch(projectId, "master"); log.info("unprotected branch master success"); } catch (Exception e) { log.warn("unprotected branch error: {}", e.getMessage()); } } /** * 根据分组路径获取分组ID */ private static Group getGroupId(String groupPath) throws GitLabApiException { return gitLabApi.getGroupApi().getOptionalGroup(groupPath).orElse(null); } /** * 在 GitLab 创建新仓库 */ private static Project createRepository(Group group, String projectName, String desc) { Project exists = gitLabApi.getProjectApi().getOptionalProject(group.getName(), projectName).orElse(null); if (Objects.nonNull(exists)) { throw new RuntimeException("项目已经存在"); } try { Project project = new Project() .withName(projectName) .withDefaultBranch("master") .withDescription(desc) .withNamespaceId(group.getId()) .withVisibility(Visibility.PRIVATE); // 私有库用 PRIVATE return gitLabApi.getProjectApi().createProject(project); // 返回 HTTPS 仓库地址 } catch (Exception e) { log.warn("create project error: {}", e.getMessage()); } return null; } public static ProjectHook addWebhook(Long projectId, String webhookUrl, Integer retryTimes) { try { // 配置 webhook ProjectHook projectHook = gitLabApi.getProjectApi().addHook( projectId, webhookUrl, Boolean.FALSE, Boolean.FALSE, Boolean.TRUE); log.info("add project hook: {}", JSONObject.toJSONString(projectHook)); return projectHook; } catch (GitLabApiException e) { log.warn("add project hook failed: {}", e.getMessage()); } if (retryTimes < 3) { return addWebhook(projectId, webhookUrl, ++retryTimes); } log.warn("add project hook failure: {}", retryTimes); throw new RuntimeException(ArchetypeUtils.WARN_MESSAGE_2); } public static Member addMembers(Long projectId, String email, Integer retryTimes) { try { if (StrUtil.isBlank(email)) { email = "liuxiaohua@keyfil.com"; } if (!email.endsWith("@keyfil.com")) { email += "@keyfil.com"; } User userByEmail = gitLabApi.getUserApi().getOptionalUserByEmail(email).orElse(null); if (userByEmail == null) { log.warn("get user by email error"); throw new RuntimeException(ArchetypeUtils.WARN_MESSAGE_3); } log.info("add members user: {}", JSONObject.toJSONString(userByEmail)); Member member = gitLabApi.getProjectApi().getOptionalMember(projectId, userByEmail.getId()).orElse(null); log.info("member exists: {}", JSONObject.toJSONString(member)); if (Objects.nonNull(member)) { if (member.getAccessLevel().value < AccessLevel.MAINTAINER.value) { member = gitLabApi.getProjectApi().updateMember(projectId, userByEmail.getId(), AccessLevel.MAINTAINER); } } else { member = gitLabApi.getProjectApi() .getOptionalMember(projectId, userByEmail.getId(), Boolean.TRUE) .orElse(null); if (Objects.isNull(member) || member.getAccessLevel().value < AccessLevel.MAINTAINER.value) { member = gitLabApi.getProjectApi().addMember(projectId, userByEmail.getId(), AccessLevel.MAINTAINER); } } return member; } catch (GitLabApiException e) { log.warn("add members user: failed: {}", e.getMessage()); } if (retryTimes < 3) { return addMembers(projectId, email, ++retryTimes); } log.warn("add members user failure: {}", retryTimes); throw new RuntimeException(ArchetypeUtils.WARN_MESSAGE_3); } } ``` #### Git调用工具类 ```java package org.jeecg.modules.devops.archetype; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.transport.URIish; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.springframework.stereotype.Component; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; /** * insert description here * * @author liuxiaohua * @since 2025-06-11 */ @Slf4j @Component @RequiredArgsConstructor public class GitUtils { /** * 初始化本地仓库并推送到 GitLab */ public static void pushLocalCodeToGitLab(String remoteUrl, String codePath, ArchetypeProperties archetypeProperties) { File localPath = new File(codePath); CredentialsProvider credentials = new UsernamePasswordCredentialsProvider( archetypeProperties.getUsername(), archetypeProperties.getAccessToken()); try (Git git = Git.init().setDirectory(localPath).call()) { // 添加所有文件 git.add().addFilepattern(".").call(); // 提交更改 git.commit() .setMessage(String.format("\uD83C\uDF89 [%s] 初始化提交", new SimpleDateFormat("yyyy-MM-dd").format(new Date()))) .call(); // 添加远程仓库 git.remoteAdd() .setName("origin") .setUri(new URIish(remoteUrl)) .call(); // 推送到 GitLab git.push() .setRemote("origin") .setCredentialsProvider(credentials) .setForce(true) .setPushAll() .call(); } catch (Exception e) { throw new RuntimeException(e); } } } ```