Windows下Nexus代码私服上传后的jar/aar的目录位置

目录位置

将本地的nexus2依赖仓库jar包、aar包上传到nexus3仓库

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class NexusUploader {
    public static void main(String[] args) {
        c1 = 0;
        c2 = 0;
        uploadDirectory(Paths.get(sourceDir));
    }

    private static int c1, c2 = 0;
    private static final String sourceDir = "C:\Users\admin123\sonatype-work\nexus\storage\releases";
    private static final String baseDir = "C:\Users\admin123\sonatype-work\nexus\storage\releases";

    private static final String REPO_ID = "maven-releases";
    private static final String NEXUS_USERNAME = "admin";
    private static final String NEXUS_PASSWORD = "123456"; // 实际使用时建议从配置文件读取
    private static final String REST_API_URL = "http://192.168.1.221:8081/service/rest/v1/components?repository=" + REPO_ID;


    private static void uploadDirectory(Path directory) {
        try {
            Files.walk(directory).filter(path -> path.toString().endsWith(".jar") ||
                            path.toString().endsWith(".pom") ||
                            path.toString().endsWith(".aar") ||
                            path.toString().endsWith(".war") ||
                            path.toString().endsWith(".zip"))
                    .forEach(NexusUploader::uploadFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.printf("成功:%s,失败:%s%n", c1, c2);
    }

    private static void uploadFile(Path filePath) {
        try {
            // 从文件路径提取 Maven 坐标
            MavenCoordinates coords = extractCoordinates(filePath);
            Thread.sleep(100);
            // 提取文件扩展名
            String fileExtension = filePath.toString().substring(filePath.toString().lastIndexOf("."));
            // 执行上传
            uploadToNexus(filePath, coords, fileExtension);
            System.out.printf("上传成功%s: %s:%s:%s (%s)%n", c1, coords.groupId, coords.artifactId, coords.version, filePath.getFileName());
            c1++;
//            if (c1 >= 5) {
//                System.exit(0);
//            }
        } catch (Exception e) {
            System.err.println("上传失败" + filePath + ": " + e.getMessage());
            e.printStackTrace();
            c2++;
        }
    }

    private static MavenCoordinates extractCoordinates(Path filePath) {
        String pathStr = filePath.toString();
        String fileName = filePath.getFileName().toString();

        // 正则表达式匹配文件名中的 artifactId 和 version
        // 支持格式: artifactId-version.extension 或 artifactId-version-classifier.extension
        Pattern pattern = Pattern.compile("(.+?)-([0-9]+\\.[0-9]+(\\.[0-9]+)?(\\-[a-zA-Z0-9]+)?)(\\..+)?");
        Matcher matcher = pattern.matcher(fileName);

        String artifactId;
        String version;

        if (matcher.matches()) {
            artifactId = matcher.group(1);
            version = matcher.group(2);
        } else {
            // 尝试简单匹配(artifactId-version.extension)
            int lastDashIndex = fileName.lastIndexOf('-');
            int extensionIndex = fileName.lastIndexOf('.');

            if (lastDashIndex > 0 && extensionIndex > lastDashIndex) {
                artifactId = fileName.substring(0, lastDashIndex);
                version = fileName.substring(lastDashIndex + 1, extensionIndex);
            } else {
                throw new IllegalArgumentException("无法从文件名提取坐标: " + fileName);
            }
        }
        // 提取 groupId
        String relativePath = pathStr.substring(baseDir.length());
        // 移除文件名部分
        String directoryPath = relativePath.substring(0, relativePath.lastIndexOf(File.separator) + 1);
        // 移除 version 目录
        String groupIdPath = directoryPath.substring(0, directoryPath.length() - version.length() - 1);
        // 移除 artifactId 目录
        int artifactIdIndex = groupIdPath.lastIndexOf(artifactId + File.separator);
        if (artifactIdIndex > 0) {
            groupIdPath = groupIdPath.substring(0, artifactIdIndex);
        }
        // 转换为 groupId(用点分隔)
        String groupId = groupIdPath.replace(File.separator, ".").replaceAll("\\.$", "");
        if (groupId.startsWith(".")) {
            groupId = groupId.substring(1);
        }
        return new MavenCoordinates(groupId, artifactId, version);
    }

    private static void uploadToNexus(Path filePath, MavenCoordinates coords, String fileExtension) throws IOException, InterruptedException {
        HttpClient client = HttpClient.newBuilder().build();

        // 构建 Multipart 请求体
        String boundary = "---------------------------" + System.currentTimeMillis();
        byte[] requestBody = buildMultipartBody(filePath, coords, boundary, fileExtension);

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(REST_API_URL))
                .header("Authorization", "Basic " + encodeCredentials(NEXUS_USERNAME, NEXUS_PASSWORD))
                .header("Content-Type", "multipart/form-data; boundary=" + boundary)
                .POST(HttpRequest.BodyPublishers.ofByteArray(requestBody))
                .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

        if (response.statusCode() != 204) {
            throw new IOException("上传失败,状态码: " + response.statusCode() + ", 响应: " + response.body());
        }
    }

    private static byte[] buildMultipartBody(Path filePath, MavenCoordinates coords, String boundary, String fileExtension) throws IOException {
        List<byte[]> parts = new ArrayList<>();
        String lineFeed = "\r\n";

        // 添加 metadata 部分
        String metadata = "--" + boundary + lineFeed +
                "Content-Disposition: form-data; name=\"maven2.groupId\"" + lineFeed +
                lineFeed +
                coords.groupId + lineFeed +
                "--" + boundary + lineFeed +
                "Content-Disposition: form-data; name=\"maven2.artifactId\"" + lineFeed +
                lineFeed +
                coords.artifactId + lineFeed +
                "--" + boundary + lineFeed +
                "Content-Disposition: form-data; name=\"maven2.version\"" + lineFeed +
                lineFeed +
                coords.version + lineFeed;

        // 确定 packaging 类型
        String packaging = fileExtension.replace(".", "");
        if ("pom".equalsIgnoreCase(packaging)) {
            metadata += lineFeed +
                    "--" + boundary + lineFeed +
                    "Content-Disposition: form-data; name=\"maven2.asset1.classifier\"" + lineFeed +
                    lineFeed +
                    "pom" + lineFeed;
        } else if ("jar".equalsIgnoreCase(packaging) || "war".equalsIgnoreCase(packaging) || "aar".equalsIgnoreCase(packaging)) {
            // 主 artifact
        } else {
            // 其他类型,添加 classifier
            metadata += lineFeed +
                    "--" + boundary + lineFeed +
                    "Content-Disposition: form-data; name=\"maven2.asset1.classifier\"" + lineFeed +
                    lineFeed +
                    packaging + lineFeed;
        }

        metadata += lineFeed +
                "--" + boundary + lineFeed +
                "Content-Disposition: form-data; name=\"maven2.asset1.extension\"" + lineFeed +
                lineFeed +
                fileExtension.substring(1) + lineFeed;  // 移除开头的点

        parts.add(metadata.getBytes());

        // 添加文件内容部分
        String filePartHeader = "--" + boundary + lineFeed +
                "Content-Disposition: form-data; name=\"maven2.asset1\"; filename=\"" +
                coords.artifactId + "-" + coords.version + fileExtension + "\"" + lineFeed +
                "Content-Type: application/octet-stream" + lineFeed +
                lineFeed;

        parts.add(filePartHeader.getBytes());
        parts.add(Files.readAllBytes(filePath));
        parts.add((lineFeed + "--" + boundary + "--" + lineFeed).getBytes());

        // 合并所有部分
        int totalLength = parts.stream().mapToInt(p -> p.length).sum();
        byte[] result = new byte[totalLength];
        int currentPosition = 0;

        for (byte[] part : parts) {
            System.arraycopy(part, 0, result, currentPosition, part.length);
            currentPosition += part.length;
        }

        return result;
    }

    private static String encodeCredentials(String username, String password) {
        return java.util.Base64.getEncoder().encodeToString((username + ":" + password).getBytes());
    }

    static class MavenCoordinates {
        String groupId;
        String artifactId;
        String version;

        public MavenCoordinates(String groupId, String artifactId, String version) {
            this.groupId = groupId;
            this.artifactId = artifactId;
            this.version = version;
        }
    }
}

这是Nexus3.8的Gradle上传到私服仓库的方法

plugins {
    id 'com.android.library'
    id 'maven-publish'
}

version = '0.0.01'
group = 'com.test.model'

// 定义版本、组、名称等属性
ext {
    version = version
    group = group
    artifactName = 'adapter'
    releaseFileName = "release.aar"

    remoteUrl = 'http://192.168.1.111/content/repositories/releases/'
    remoteName = 'admin'
    remotePassword = 'mypwd'
}

// 生成源码jar任务
tasks.register('sourcesJar', Jar) {
    from android.sourceSets.main.java.srcDirs
    archiveClassifier.set("sources")
}

// 发布配置(Gradle 9.0 兼容写法)
afterEvaluate {
    publishing {
        repositories {
            maven {
                name = "maven-releases"
                url = uri(project.remoteUrl)
                credentials {
                    username = project.remoteName
                    password = project.remotePassword
                }
                allowInsecureProtocol = true
            }
        }

        publications {
            release(MavenPublication) {
                groupId = project.group
                artifactId = project.artifactName
                version = project.version
//                // 使用组件1,(现代做法)无效
//                from components.findByName("release")
                // 使用组件2,添加aar
                artifact(file("${buildDir}/outputs/aar/${releaseFileName}"))
                // 添加源码JAR
                artifact(tasks["sourcesJar"])
                // 配置POM文件
                pom {
                    name = project.artifactName
                    packaging = 'aar'
                    // 自动生成依赖信息(更现代的方式)
                    withXml {
                        def dependenciesNode = asNode().appendNode('dependencies')
                        // 使用变体API获取依赖(Gradle 9.0推荐)
                        configurations.releaseRuntimeClasspath.resolvedConfiguration.firstLevelModuleDependencies.each { dep ->
                            def dependencyNode = dependenciesNode.appendNode('dependency')
                            dependencyNode.appendNode('groupId', dep.moduleGroup)
                            dependencyNode.appendNode('artifactId', dep.moduleName)
                            dependencyNode.appendNode('version', dep.moduleVersion)
                            // 设置依赖范围
                            def scope = 'runtime'
                            if (configurations.api.getDependencies().any { it.group == dep.moduleGroup && it.name == dep.moduleName }) {
                                scope = 'compile'
                            }
                            dependencyNode.appendNode('scope', scope)
                        }
                    }
                }
            }
        }
    }
    tasks.withType(PublishToMavenRepository).tap {
        configureEach {
            dependsOn bundleReleaseAar
        }
    }
}

android {
    compileSdk = 36

    defaultConfig {
        //14(4.0),16(4.1),17(4.2),18(4.3),19(4.4),21(5.0),23(6.0),24(7.0),26(8.0),28(9.0)
        //29(10),30(11),31,32(12),33(13),34(14),35(15)
        minSdk = 26
        //noinspection OldTargetApi
        targetSdk = 34

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles "consumer-rules.pro"
    }

    // 设置要打包的名称,可以是jar或aar
    android.libraryVariants.configureEach { variant ->
        variant.outputs.all {
            outputFileName = releaseFileName
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            //buildConfigField("String", "version", "\"v${version}\"")
            //buildConfigField("String", "group", "\"${group}\"")
            //buildConfigField("String", "artifact", "\"${artifactName}\"")
            //buildConfigField("String", "text", "\"${group}:${artifactName}:${version}\"")
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }
    buildFeatures {
        viewBinding = true
    }
    namespace = 'com.test.model'
}

dependencies {
    api group: 'androidx.recyclerview', name: 'recyclerview', version: '1.4.0'
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容