如何用Java实现Maven JAR文件直接与传递依赖的黑名单校验?
解决方案:Maven JAR依赖(含传递依赖)校验方案
一、修复Java调用mvn dependency:tree的问题
你在Java中调用该命令失败,通常是因为环境变量未配置Maven路径、未指定正确工作目录、未处理命令流导致进程阻塞这几个原因,以下是修复后的实现方案:
具体实现步骤
- 从上传的JAR文件中提取
pom.xml到临时目录 - 指定Maven命令的完整路径(需匹配服务器实际安装路径),并将工作目录设为临时目录
- 同步读取命令的输出流与错误流,避免进程挂起
示例代码片段:
import java.io.*; import java.nio.file.Files; import java.nio.file.Path; public class MavenDependencyTree { public static String getDependencyTree(Path tempPomDir) throws IOException, InterruptedException { // 替换为服务器上Maven的实际路径 String mvnCmd = "/usr/local/maven/bin/mvn dependency:tree -DoutputType=text"; ProcessBuilder pb = new ProcessBuilder(mvnCmd.split(" ")); pb.directory(tempPomDir.toFile()); pb.redirectErrorStream(true); // 合并错误流到输出流,避免进程阻塞 Process process = pb.start(); StringBuilder output = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { output.append(line).append("\n"); } } int exitCode = process.waitFor(); if (exitCode != 0) { throw new RuntimeException("Maven命令执行失败,输出:" + output.toString()); } return output.toString(); } }
解析输出时,可按[groupId]:[artifactId]:[version]格式提取所有依赖,再与黑名单比对。
二、更可靠的方案:使用Maven Resolver(Aether)API
直接调用外部Maven命令依赖服务器环境配置,在云端场景下稳定性不足。推荐使用Maven Resolver(原Aether)——Maven官方的依赖解析库,可直接在Java代码中解析pom.xml,获取完整依赖树(含传递依赖)。
实现步骤
- 添加Maven Resolver相关依赖到项目pom.xml:
<dependencies> <dependency> <groupId>org.apache.maven.resolver</groupId> <artifactId>maven-resolver-api</artifactId> <version>1.9.15</version> </dependency> <dependency> <groupId>org.apache.maven.resolver</groupId> <artifactId>maven-resolver-impl</artifactId> <version>1.9.15</version> </dependency> <dependency> <groupId>org.apache.maven.resolver</groupId> <artifactId>maven-resolver-transport-http</artifactId> <version>1.9.15</version> </dependency> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-core</artifactId> <version>3.9.5</version> </dependency> </dependencies>
- 编写解析代码获取所有依赖:
import org.apache.maven.model.Model; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.apache.maven.resolver.examples.util.BasicRepositorySystemFactory; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.collection.CollectRequest; import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.graph.DependencyNode; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.DependencyRequest; import org.eclipse.aether.resolution.DependencyResult; import java.io.InputStream; import java.util.ArrayList; import java.util.List; public class DependencyChecker { private static final RepositorySystem system = BasicRepositorySystemFactory.newRepositorySystem(); public static List<String> getAllDependencies(InputStream pomInputStream) throws Exception { List<String> allDependencies = new ArrayList<>(); // 读取pom.xml MavenXpp3Reader reader = new MavenXpp3Reader(); Model model = reader.read(pomInputStream); // 构建依赖请求 RepositorySystemSession session = BasicRepositorySystemFactory.newSession(system); DefaultArtifact artifact = new DefaultArtifact( model.getGroupId(), model.getArtifactId(), "pom", model.getVersion() ); CollectRequest collectRequest = new CollectRequest(); collectRequest.setRoot(new Dependency(artifact, null)); // 添加公司私有仓库或中央仓库,按需调整 collectRequest.addRepository(new RemoteRepository.Builder("central", "default", "https://repo1.maven.org/maven2/").build()); DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, null); DependencyResult result = system.resolveDependencies(session, dependencyRequest); // 遍历依赖树收集所有依赖 traverseDependencyTree(result.getRoot(), allDependencies); return allDependencies; } private static void traverseDependencyTree(DependencyNode node, List<String> dependencies) { if (node.getArtifact() != null) { String depKey = node.getArtifact().getGroupId() + ":" + node.getArtifact().getArtifactId() + ":" + node.getArtifact().getVersion(); dependencies.add(depKey); } for (DependencyNode child : node.getChildren()) { traverseDependencyTree(child, dependencies); } } }
- 黑名单校验:将收集到的依赖列表与黑名单(可存储为
Set<String>)比对,若存在交集则返回false,禁止文件上传。
三、云端场景优化建议
- 缓存依赖树:对同一版本的依赖缓存解析结果,提升校验效率
- 配置私有仓库:在Maven Resolver中添加公司内部Maven仓库,确保能解析内部私有依赖
- 离线模式支持:若云端无法访问外部仓库,可提前同步常用依赖到本地仓库,使用离线解析
内容的提问来源于stack exchange,提问作者HRL
相关产品推荐
相关产品推荐

