maven之插件打包详解_maven-assembly-plugin-CSDN博客

文章目录

maven打包到 lib中使用 build插件,要么使用 assmebly插件要么不用此插件

maven插件的命名约定:
maven插件有着自己的一套命名规范。官方插件命名的格式为maven-xxx-plugin,非官方的插件命名为 xxx-maven-plugin

maven打包方式有如下三种:

  • maven-jar-plugin,默认的打包插件,用来打普通的project JAR包;
  • maven-shade-plugin,用来打可执行JAR包,也就是所谓的fat JAR包;
  • maven-assembly-plugin,支持自定义的打包结构,也可以定制依赖项等

另外还有spring-boot-maven-plugin 插件打包

1 assmebly

1.1 assmebly简介

Maven-assembly-pluginmaven中针对打包任务而提供的标准插件,可以实现自定义打包。
主要提供如下功能:

  • 提供一个把工程依赖元素、模块、网站文档等其他文件存放到单个归档文件里
  • 打包成指定格式分发包,支持各种主流的格式如ziptar.gzjarwar等,具体打包哪些文件是高度可控的
  • 能够自定义包含/排除指定的目录或文件

在普通 Maven 工程打包时默认仅会编译工程中新建的 java 文件并存储其 .class 文件,对于 POM 文件中引用的第三方依赖并不会一同打包。
如新建一个 Maven 工程并在依赖中导入 Jackson 依赖库并进行打包编译,可以看到下图编译后的 JAR 文件中只有工程中新建的 MyTest.class 文件,项目中所导入的依赖并没有被一起打包。
在这里插入图片描述
而通过 assembly 插件即可将 POM 配置中的所有依赖一同打包编译至 JAR 文件中。
在这里插入图片描述

assmebly 是从官网下载:http://maven.apache.org/plugins/maven-assembly-plugin/download.cgi

1.2 自定义assmebly配置

assembly 插件中,descriptorsdescriptorRefs 是两个用于定义打包配置的不同标签。它们的主要作用是指定如何定义和使用 assembly 描述文件。下面是这两个标签的详细区别和使用方法:

  • descriptorRefs
    功能:descriptorRefs 标签用于引用预定义的、常用的 assembly 描述符。这些预定义的描述符由 maven-assembly-plugin 提供,通常用于常见的打包需求,如创建包含所有依赖的 JAR 文件、创建 ZIP 文件等。
    常用描述符:

    • jar-with-dependencies:创建一个包含所有项目依赖的 JAR 文件。
    • bin:创建一个包含项目的二进制文件的压缩包。
    • src:创建一个包含源代码的压缩包。
  • descriptors
    功能:descriptors 标签用于指定自定义的 assembly 描述符文件。这些描述符文件是 XML 文件,定义了如何将项目的文件和依赖打包到最终的分发包中。
    在项目的 src/assembly 目录下创建自定义的 XML 描述符文件,来指定如何打包项目文件、依赖文件和其他资源。

1.2.1 maven中配置

maven<build>标签中配置

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>${maven-assembly-plugin.version}<version>
            <configuration>
                <!-- 打出包最终名字 -->
                <finalName>test-${project.version}</finalName>
                <!--用于控制在生成的归档文件(如 ZIP、JAR)中是否包含组件的构建 ID(assemblyId)-->
                <!--如果组件构建ID是assembly那么生成的归档文件名将会是 artifactId-version-assembly.zip -->
                <!--若为fasle则artifactId-version.zip-->
                <appendAssemblyId>false</appendAssemblyId>
                 <!-- 配置描述符文件 指定文件位置 -->
                 <descriptors>
                    <descriptor>assembly/assembly.xml</descriptor>
                   </descriptors>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <!-- 绑定到package生命周期 -->
                    <phase>package</phase>
                    <goals>
                        <!-- 只运行一次 -->
                        <goal>single</goal>
                    </goals>
                 </execution>
             </executions>
         </plugin>
     </plugins>
</build>

1.2.2 maven标签

1.2.2.1 configuration标签说明

descriptor标签中的assembly.xml就是指定的配置文件位置
在这里插入图片描述

1.2.3 assembly.xml配置

<assembly>
    <id>assembly</id>
    <formats>
        <format>tar.gz</format>
    </formats>
    <includeBaseDirectory>true</includeBaseDirectory>
    <fileSets>
        <fileSet>
            <!--  启动信息 -->
            <directory>src/main/bin</directory>
            <includes>
                <include>*.sh</include>
            </includes>
            <outputDirectory>bin</outputDirectory>
            <fileMode>0755</fileMode>
        </fileSet>
        <fileSet>
            <!--  配置信息 -->
            <directory>src/main/conf</directory>
            <outputDirectory>conf</outputDirectory>
        </fileSet>
        <fileSet>
            <directory>src/main/sql</directory>
            <includes>
                <include>*.sql</include>
            </includes>
            <outputDirectory>sql</outputDirectory>
        </fileSet>
        <fileSet>
            <directory>target/classes/</directory>
            <includes>
                <include>*.properties</include>
                <include>*.xml</include>
                <include>*.txt</include>
            </includes>
            <outputDirectory>conf</outputDirectory>
        </fileSet>
    </fileSets>
    <files>
        <file>
            <source>target/${project.artifactId}-${project.version}.jar</source>
            <outputDirectory>.</outputDirectory>
        </file>
    </files>
    <dependencySets>
        <!-- 打包到lib目录下 -->
        <dependencySet>
            <unpack>false</unpack>
            <scope>runtime</scope>
            <outputDirectory>/lib</outputDirectory>
        </dependencySet>
        <!-- 如果是需要启动jar单独和其他隔离开,可以这样指定启动jar在根目录 -->
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <unpack>false</unpack>
            <scope>runtime</scope>
            <includes>
                <include>cn.test:main:jar</include>
            </includes>
        </dependencySet>
    </dependencySets>
</assembly>

1.2.4 assembly标签

1.2.4.1 id标签

id标识符,添加到生成文件名称的后缀符。如果指定 id 的话,目标文件则是 ${artifactId}-${id}.tar.gz

1.2.4.2 formats标签

formatsassembly插件支持的打包格式有zip、tar、tar.gz (or tgz)、tar.bz2 (or tbz2)、jar、dir、war,可以同时指定多个打包格式

<formats> 
     <format>tar.gz</format> 
     <format>dir</format>
 </formats>
1.2.4.3 includeBaseDirectory标签

includeBaseDirectory标签指定打的包是否包含打包层目录(比如finalNameterminal-dispatch,当值为true,所有文件被放在包内的terminal-dispatch目录下,否则直接放在包的根目录下)
在这里插入图片描述

1.2.4.4 dependencySets标签

用来定制工程依赖 jar 包的打包方式,核心元素如下表所示:

  • outputDirectory: 指定包依赖目录,该目录是相对于根目录
  • includes/include*:包含依赖
  • excludes/exclude*:排除依赖
  • useProjectArtifact:指定打包时是否包含工程自身生成的jar
  • unpack:布尔值,false表示将依赖以原来的JAR形式打包,true则表示将依赖解成*.class文件的目录结构打包
  • scope:表示符合哪个作用范围的依赖会被打包进去。compileprovided都不用管,一般是写runtime
1.2.4.5 fileSets标签

fileSets标签用来设置一组文件在打包时的属性:

  • directory:源目录的路径。
  • includes/excludes:设定包含或排除哪些文件,支持通配符。
  • fileMode:指定该目录下的文件权限,采用Unix八进制描述法,(User Group Other)所属属性默认值是0644Read = 4,Write = 2和Execute = 1
  • outputDirectory:指定文件集合的输出目录,生成目录的路径,该目录是相对于根目录
1.2.4.6 files标签

files标签可以指定目的文件名到指定目录,其他和 fileSets 相同,核心元素如下表所示:

  • source:源文件,相对路径或绝对路径
  • outputDirectory:输出目录
  • destName: 目标文件名
  • fileMode:文件权限

1.3 预定义assembly

<descriptorRef> 用于引用 Maven 官方或自定义预定义的组装描述符。这些预定义的描述符通常已经内置在插件中,无需自己提供 assembly.xml 文件。

常用的预定义描述符包括:

  • jar-with-dependencies:将所有依赖打包到一个可运行的 JAR 文件中。
  • bin:构建一个二进制分发包。
  • src:构建一个源码分发包。
<plugin>  
    <groupId>org.apache.maven.plugins</groupId>  
    <artifactId>maven-assembly-plugin</artifactId>  
    <version>3.1.0</version>  
    <configuration>  
        <descriptorRefs>  
            <descriptorRef>jar-with-dependencies</descriptorRef>  
        </descriptorRefs>  
        <!-- Set jar file name -->
        <finalName>${project.artifactId}-${project.version}-all</finalName>  
        <appendAssemblyId>false</appendAssemblyId>  
        <attach>false</attach>  
        <archive>  
            <manifest>  
                <mainClass>fully.qualified.MainClass</mainClass> 
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries> 
            </manifest>   
        </archive>  
    </configuration>  
    <executions>  
        <execution>  
         <!-- Set effect phase -->
            <id>make-assembly</id>  
            <phase>package</phase>  
            <goals>  
                <goal>single</goal>  
            </goals>  
        </execution>  
    </executions>  
</plugin>

2 Maven直接打包

这种方式就不用配置assmebly文件,直接打包就可以了

2.1 build 自带标签

2.1.1 maven-resources-plugin 标签

maven-resources-plugin 主要负责复制和过滤项目中的资源文件(如 .properties.xml.yml 等),默认处理的资源目录:src/main/resources(生产环境的资源)和src/test/resources(测试环境的资源)
主要功能:

  • 将资源文件复制到构建目录,例如 target/classes
  • 支持过滤操作(动态替换文件中的变量,如 ${}),此处配置是 全局过滤配置
  • 可以通过配置指定资源文件的目标路径。

示例文件:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-resources-plugin</artifactId>
  <version>3.3.0</version>
  <configuration>
    <encoding>UTF-8</encoding>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>
  </configuration>
  <executions>
      <execution>
          <id>copy-dependencies</id>
          <phase>package</phase>
          <goals>
             <goal>copy-resources</goal>
          </goals>
            <configuration>
            <!--配置文件打包成config目录下 -->
            <outputDirectory>${project.build.directory}/twin-web/config</outputDirectory>
           <resources>
              <resource>
              <directory>src/main/resources</directory>
              </resource>
      </resources>
     </configuration>
  </execution>
</executions>
</plugin>

2.1.2 resources标签

在 Maven 项目中,<resources> 标签用于配置资源文件的处理逻辑,如果项目中没有显式配置 <resources>Maven 默认会将 src/main/resources 目录下的所有文件(不进行过滤)复制到 target/classes 目录。这些文件在打包时会自动被包含到最终的 JAR/WAR 包中。

简单示例:

<resources>
  <resource>
      <directory>src/main/resources</directory>
       <!--filerting设置为true,则打包过程中会对这些文件进行过滤处理,此处是 具体配置 -->
       <!-- 在打包时动态替换资源文件中的占位符(如 ${} 变量),就需要为true -->
       <filtering>true</filtering>
       <!--指定目标路径为config-->
      <targetPath>${project.build.directory}/config</targetPath>
      <includes>
      <!--使用通配符-->
         <include>**/*.properties</include>
         <include>**/*.yml</include>
         <include>**/*.xml</include>
          <include>mapper/*.xml</include>
         <!-- 这里可以根据你实际想要包含的配置文件类型来添加更多的include配置 -->
   </includes>
  </resource>
</resources>

2.1.3 maven-surefire-plugin 标签

maven-surefire-plugin 测试执行插件,负责运行项目中的单元测试或集成测试。
默认执行 src/test/java 下的测试代码(基于 JUnit、TestNG 等框架)。
测试执行命令:mvn test
功能:

  • 执行测试用例并生成测试报告。
  • 支持配置测试框架(如 JUnit 4/5、TestNG)。
  • 提供参数化测试、并行测试支持。

示例文件

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>3.0.0</version>
  <configuration>
    <testFailureIgnore>true</testFailureIgnore>
    <includes>
      <include>**/*Test.java</include>
    </includes>
  </configuration>
</plugin>

2.1.4 maven-dependency-plugin 标签

maven-dependency-plugin 依赖管理插件,主要用于处理项目的依赖,提供下载、分析、复制、解压和报告依赖的功能。
功能:

  • 下载项目依赖的 JAR 包到本地仓库
  • 分析项目依赖(包括依赖冲突)。
  • 将特定的依赖文件复制到指定目录。
  • 解压依赖包以供项目使用。

常用目标(Goals):

  • dependency:copy:将依赖复制到指定目录。
  • dependency:unpack:解压指定的依赖文件。
  • dependency:tree:显示项目的依赖树结构。
  • dependency:analyze:分析未使用或缺失的依赖。

示例文件

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>
                    ${project.build.directory}/lib
                </outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>

2.1.5 maven-jar-plugin 标签

maven-jar-plugin 打包插件,主要用于将项目的编译产物打包成 JAR 文件,默认打包输出路径为 target/${project.artifactId}-${project.version}.jar
功能:

  • 自定义 JAR 文件的结构。
  • 支持将额外的资源文件或依赖包添加到 JAR 包中。
  • 可以配置主类(Main-Class),生成可执行 JAR。

简单示例

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <!-- <version>2.4</version>-->
    <!-- 对要打的jar包进行配置 -->
    <configuration>
        <outputDirectory>
              <!--输入打包可执行的jar到twin-web\libs\下-->
              ${project.build.directory}/twin-web/
         </outputDirectory>
        <!-- Configuration of the archiver -->
        <archive>
            <!--生成的jar中,不要包含pom.xml和pom.properties这两个文件-->
            <addMavenDescriptor>false</addMavenDescriptor>
            <!-- Manifest specific configuration -->
            <manifest>
                <!-- 指定运行类 -->
                <mainClass>
                    cn.test.App
                </mainClass>
                <!--是否要把第三方jar放到manifest的classpath中-->
                <addClasspath>true</addClasspath>
                <!-- 生成的manifest中classpath的前缀-->
                <!-- 因为要把第三方jar放到lib目录下, 所以classpath的前缀是lib/ -->
                <classpathPrefix>lib/</classpathPrefix>
            </manifest>
            <manifestEntries>
                   <!-- 增加配置文件的classpath-->
                   <Class-Path>./config/</Class-Path>
            </manifestEntries>
        </archive>
        <!--过滤掉不希望包含在jar中的文件-->
        <excludes>
            <!-- 排除不需要的文件夹(路径是jar包内部的路径) -->
            <exclude>**/assembly/</exclude>
        </excludes>
    </configuration>
</plugin>

2.2 详细配置示例文件

<build>
     <plugins>  
         <!-- maven依赖打包配置 -->
         <!--  引入上面的 maven-dependency-plugin示例 -->
        <!-- maven主文件打包 -->
         <!-- 引入上面的 maven-jar-plugin 示例 -->
     </plugins>
 </build>

3 使用SpringBoot插件打包

3.1 简介

spring-boot-maven-pluginspring boot提供的 maven打包插件。可打直接可运行的 jar包war包
如果使用 2.2.1.RELEASE 版本,则需要maven版本在2.0及以上,JDK在1.8及以上

该插件是spring boot官方提供的一个打包插件,主要用来打出fat jar,并且提供了支持java -jar xxx.jar方式启动。官网地址:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/

3.2 pom示例

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.6.11</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>jar</packaging>
    <artifactId>mine</artifactId>

    <dependencies>
        ···
    </dependencies>

    <build>
        <!-- mavne打包动态修改替换配置文件中的占位符 -->
        <resources>
            <resource>
                <directory>${basedir}/src/main/resources</directory>
                <!-- 处理其中的可替换参数(@..@符合标注的变量) -->
                <filtering>true</filtering>
            </resource>
            <!-- 可以配置引入哪些配置文件includes或排除哪些文件excludes -->
        </resources>

        <plugins>
            <!-- 跳过单元测试的 插件-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.19.1</version>
                <configuration>
                     <!-- 默认关掉单元测试,不用手动关闭了 -->
                    <skipTests>true</skipTests>
                </configuration>
            </plugin>
            <!-- 配置文件处理插件  -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <encoding>utf-8</encoding>
                    <!-- 是否使用默认占位符@@ -->
                    <useDefaultDelimiters>true</useDefaultDelimiters>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!-- 指定该 Main Class 为全局的唯一入口 -->
                    <mainClass>cn.test.App</mainClass>
                    <layout>ZIP</layout>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                        <!-- 将依赖到的包都放进去 -->
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

3.3 插件详解

插件提供了6个maven goal

  • build-info:生成项目的构建信息文件 build-info.properties
  • help:用于展示spring-boot-maven-plugin的帮助信息。使用命令行mvn spring-boot:help -Ddetail=true -Dgoal=<goal-name>可展示goal的参数描述信息。
  • repackage:可生成可执行的jar包或war包。插件的核心goal。
  • run:运行 Spring Boot 应用
  • start:在集成测试阶段,控制生命周期
  • stop:在集成测试阶段,控制生命周期

3.3.1 打包 repackage

spring-boot-maven-plugin 引入pom,执行 mvn package 命令,即可打jar包(插件默认打jar包),target文件夹里的 *.jar 即为可执行jar包。
打包主要使用的是 repackage goal,它是 spring-boot-starter-parent为插件设置的默认goal。这个 goal绑定在mavenpackage 生命周期上,完整命令为 mvn package spring-boot:repackage。在 mvn package 执行打包之后,repackage 再次打包生成可执行的 jar包或war包。
默认情况下,repackage生成包的名称与 mvn package 生成的原始包名称相同,而原始包被重命名为 *.origin

repackage 命令生成的包,默认会包含项目引入的所有依赖,包括scopeprovied的依赖
若项目引入了spring-boot-devtools,默认spring-boot-devtools 会被打在包里,若想排除,应设置 repackageexcludeDevtools参数为true。在打war包时,还应将spring-boot-devtools 的optinal设置为true或将scope设置为provided。

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <id>repackage</id>
                    <configuration>
                        <excludeDevtools>true</excludeDevtools>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

repackage 会在Manifest文件中写入Main-Class and Start-Class属性。当默认值不能使程序正常运行时,可以通过插件配置。Manifest文件位于的META-INF文件夹中

打可执行jar包时,示例如下:

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: beauty
Start-Class: com.demo.beauty.BeautyApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Version: 2.2.1.RELEASE
Created-By: Apache Maven 3.6.3
Build-Jdk: 1.8.0_251
Main-Class: org.springframework.boot.loader.JarLauncher

对应的plugin

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <mainClass>com.demo.beauty.BeautyApplication</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>

可以看出,打可执行jar包时,spring-boot-maven-pluginmainClass 参数对应的是 Manifest 文件中的 Start-Class 属性,即项目的启动类。

3.3.2 layout标签

Manifest 文件中的 Main-Class 属性由插件的 layout 决定。layout 属性值默认为jar/war。layout种类有:

  • JAR,即通常的可执行jar。Main-Class : org.springframework.boot.loader.JarLauncher
  • WAR,即通常的可执行war。Main-Class : org.springframework.boot.loader.warLauncher。为避免将war包部署在容器中运行时可能的冲突问题,provided 类型的依赖都被放置在可执行 war 包的 WEB-INF/lib-provided 文件夹中,包括直接运行war需要的内置容器。
  • ZIP,亦可作DIR,类似于JARMain-Class : org.springframework.boot.loader.PropertiesLauncher
    当启动时需要用 -Dloader.path=lib/指定额外的类加载路径

    • -Dloader.pathSpring Boot 应用程序的特性,用于指定额外的类加载路径
      Spring Boot 应用程序中,通常使用 -Dloader.path 来指定外部库和配置文件的路径。
    • -classpathJava 应用程序的标准参数,用于指定类加载器在运行时搜索类和资源文件的路径。
      在普通 Java 应用程序中,使用 -classpath 参数来指定类加载路径
  • NONE,打包所有依赖库和项目资源,但是不打包任何启动器。可以看到在 layoutNONE时,打出的包中的org文件夹没有了,Manifest 文件中没有Start-Class属性,Main-Class属性值为项目的启动类。
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: beauty
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Version: 2.2.1.RELEASE
Created-By: Apache Maven 3.6.3
Build-Jdk: 1.8.0_251
Main-Class: com.demo.beauty.BeautyApplication

3.4 启动方式解析

springboot插件打出的包是启动的入口,实际上在这个包里面springboot会自动打入一个引导类org.springframework.boot.loader.Launcher,它是 Spring Boot 可执行 jar 的主要入口点,它是 Spring Boot jar 文件中的实际 Main-Class,用于设置适当的 URLClassLoader 并最终调用 Spring Boot项目中定义的 main()方法。

Launcher有三个子类(JarLauncher、WarLauncher 和 PropertiesLauncher),如果我们打包插件的layout配置的是ZIP的方式,它会使用PropertiesLauncher

PropertiesLauncher机制说明:

  • 默认情况下,PropertiesLauncherBOOT-INF/lib/ 中加载,我们可以通过设置loader.properties中的loader.pathLOADER_PATH 环境变量来增加其它的加载位置。
  • loader.path:配置逗号分隔的 Classpath 类路径,例如 lib,${HOME}/app/lib,前面的路径优先,类似于 javac 命令中的 -classpath。
  • loader.home:用于解析 loader.path 配置的相对路径,默认是${user.dir}

原网址: 访问
创建于: 2025-01-14 10:42:23
目录: default
标签: 无

请先后发表评论
  • 最新评论
  • 总共0条评论