手写Maven的archetype项目脚手架

简介: 一、背景   maven是一个很好的代码构建工具,采用“约定优先于配置”的原则进行项目管理,相信很多的java开发者应该都了解maven并可能在工作当中都是通过maven来管理项目的,在创建的项目的时候,我们往往会使用maven内置的项目骨架也就是archetype来快速生成项目结构。

一、背景

  maven是一个很好的代码构建工具,采用“约定优先于配置”的原则进行项目管理,相信很多的java开发者应该都了解maven并可能在工作当中都是通过maven来管理项目的,在创建的项目的时候,我们往往会使用maven内置的项目骨架也就是archetype来快速生成项目结构。但是在一个团队做开发的过程中,可能仅仅依靠maven预先提供的archetyp可能是不够的,团队之间协作有自己的定义方式,每个人的结构定义风格也不尽相同,在这样的背景下我们有必要去定义一个统一的代码骨架供团队使用,这样做的好处是当团队需要开始一个新项目的时候,可以利用自定义的maven骨架一键生成项目。

  archetype是在maven-archetype-plugin插件执行generate目标的时候进行配置的,我们经常使用到maven的内嵌的骨架包括:maven-archetype-webapp、maven-archetype-quickstart。前者用来快速搭建一个web工程项目,后者用来快速搭建一个普通的java工程项目。

二、手写普通单模块项目的archetype

单模块项目的archetype脚手架项目的结构

  

上图中的各个文件详解:

  • 根目录beast-archetype下的pom.xml和一般的maven项目一样主要定义archetype项目的坐标等信息。
  • 所有的项目骨架内容都集中在src/main/resources/archetype-resources文件夹下。
  • archetype-resources中的pom.xml定义了待生成项目的pom文件的内容,/src/main/java、/src/test/java中分别定义了待生成项目中相应目录下的内容
  • /src/main/resources/META-INF/maven/archetype-metadata.xml中定义相关的元数据描述(其中该文件的位置固定为resources/META-INF/maven文件夹下,且名称固定为archetype-metadata.xml)。

1.beast-archetype/pom.xml内容如下

<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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.thebeastshop</groupId>
    <artifactId>beast-archetype</artifactId>
    <version>1.1</version>
    <packaging>jar</packaging>

    <name>beast-archetype</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <finalName>beast-archetype</finalName>
    </build>
</project>

2.src/main/resources/archetype-resources/pom.xml内容如下:

<?xml version="1.0"?>
<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">
    <modelVersion>4.0.0</modelVersion>
    <groupId>${groupId}</groupId>
    <artifactId>${artifactId}</artifactId>
    <version>${version}</version>
    <name>${artifactId}</name>
    
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
             <plugin> 
                 <artifactId>maven-deploy-plugin</artifactId> 
                 <configuration> 
                    <skip>true</skip> 
                 </configuration> 
             </plugin>
        </plugins>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-archetype-plugin</artifactId>
                    <version>2.2</version>
                    <configuration>
                        <source>1.7</source>
                        <target>1.7</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-source-plugin</artifactId>
                    <configuration>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

其中:上面${}标识的变量都是通过maven中的命令行传进来的,如:mvn archetype:generate -DgroupId=com.thebeastshop

3.src/main/resources/META-INF/maven/archetype-metadata.xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<archetype-descriptor  name="beast-archetype"
        xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
            http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0
            http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd">

    <requiredProperties>
        <requiredProperty key="package-name" />
    </requiredProperties>

    <fileSets>
        <fileSet filtered="true" packaged="true" encoding="UTF-8">
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.java</include>
            </includes>
        </fileSet>
        <fileSet filtered="true" encoding="UTF-8">
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.*</include>
            </includes>
        </fileSet>
        <fileSet filtered="true" packaged="true" encoding="UTF-8">
            <directory>src/test/java</directory>
            <includes>
                <include>**/*.java</include>
            </includes>
        </fileSet>
        <fileSet encoding="UTF-8">
            <directory>src/test/resources</directory>
            <includes>
                <include>**/*.*</include>
            </includes>
        </fileSet>
    </fileSets>
</archetype-descriptor>

说明:

  • packaged="true"标识src/main/resources/archetype-resources/src/main/java中对应的内容是否要放入到package中,比如package为com.thebeastshop,那么如果该属性为true,则对应的java文件会放到com/thebeastshop文件夹下,也就是包路径下。
  • filtered="true"标识下面提到的${}是否要进行替换

4.src/main/resources/archetype-resources/src/main/java/Demo.java内容如下:

package ${package};

public class Demo{
    public static void main( String[] args )
    {
        System.out.println( "Hello My Archetype!" );
    }
}

5.这样我们就手写好了一个自定义的maven的archetype骨架项目,我们只需要通过mvn clean install 命令把该jar包安装到本地仓库,然后通过本地仓库中的该jar包来生成一个项目看看效果,使用如下命令:

 mvn archetype:generate 
  -DgroupId=comthebeastshop
  -DartifactId=beast-test
  -Dpackage="com.thebeastshop.test"
  -DarchetypeGroupId=com.thebeastshop
  -DarchetypeArtifactId=beast-archetype -DarchetypeVersion=1.1 -X -DarchetypeCatalog=local

三、手写maven多module的项目骨架archetype

1.多模块骨架项目的项目结构

这跟单模块项目区别不大,但是有几个概念需要说明:

  • “__rootArtifactId__”占位符会被parent项目的artifactId替换
  • ${rootArtifactId}也会被parent项目的artifactId替换
  • src/main/resources/archetype-resources里必须要有一个顶级pom文件(如果是单工程就是工程pom文件),同时子文件夹代表了模块定义

2.模板工程定义描述文件:META-INF/maven/archetype-metadata.xml

<?xml version="1.0" encoding="UTF-8"?>
<archetype-descriptor  name="beast-archetype"
        xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
            http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0
            http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd">

    <requiredProperties>
        <requiredProperty key="groupId">
            <defaultValue>com.thebeastshop</defaultValue>
        </requiredProperty>
        <requiredProperty key="artifactId">
            <defaultValue>test</defaultValue>
        </requiredProperty>
        <requiredProperty key="package">
            <defaultValue>com.thebeastshop.test</defaultValue>
        </requiredProperty>
    </requiredProperties>

    <modules>
        <module id="${rootArtifactId}-api" name="${rootArtifactId}-api" dir="__rootArtifactId__-api">
            <fileSets>
                <fileSet filtered="true" encoding="UTF-8" packaged="true">
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet filtered="true" encoding="UTF-8" packaged="true">
                    <directory>src/test/java</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet encoding="UTF-8">
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet encoding="UTF-8">
                    <directory>src/test/resources</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
            </fileSets>
        </module>
        <module id="${rootArtifactId}-core" name="${rootArtifactId}-core" dir="__rootArtifactId__-core">
            <fileSets>
                <fileSet filtered="true" encoding="UTF-8" packaged="true">
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet filtered="true" encoding="UTF-8" packaged="true">
                    <directory>src/test/java</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet filtered="true" encoding="UTF-8">
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet encoding="UTF-8">
                    <directory>src/test/resources</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
            </fileSets>
        </module>
        <module id="${rootArtifactId}-dao" name="${rootArtifactId}-dao" dir="__rootArtifactId__-dao">
            <fileSets>
                <fileSet filtered="true" encoding="UTF-8" packaged="true">
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet filtered="true" encoding="UTF-8" packaged="true">
                    <directory>src/test/java</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet filtered="true" encoding="UTF-8">
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*.*</include>
                        <include>mapper</include>
                    </includes>
                </fileSet>
                <fileSet encoding="UTF-8">
                    <directory>src/test/resources</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
            </fileSets>
        </module>
        <module id="${rootArtifactId}-main" name="${rootArtifactId}-main" dir="__rootArtifactId__-main">
            <fileSets>
                <fileSet filtered="true" encoding="UTF-8" packaged="true">
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet filtered="true" encoding="UTF-8" packaged="true">
                    <directory>src/test/java</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet filtered="true" encoding="UTF-8">
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet encoding="UTF-8">
                    <directory>src/test/resources</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet encoding="UTF-8">
                    <directory>src/main/assembly</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet encoding="UTF-8">
                    <directory>src/main/bin</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
            </fileSets>
        </module>
        <module id="${rootArtifactId}-mybatisGen" name="${rootArtifactId}-mybatisGen" dir="__rootArtifactId__-mybatisGen">
            <fileSets>
                <fileSet filtered="true" encoding="UTF-8" packaged="true">
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet filtered="true" encoding="UTF-8" packaged="true">
                    <directory>src/test/java</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet encoding="UTF-8">
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
                <fileSet encoding="UTF-8">
                    <directory>src/test/resources</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </fileSet>
            </fileSets>
        </module>
    </modules>
</archetype-descriptor>
  • 属性变量定义
  • <requiredProperties>
        <requiredProperty key="groupId">
            <defaultValue>com.thebeastshop</defaultValue>
        </requiredProperty>
        <requiredProperty key="artifactId">
            <defaultValue>test</defaultValue>
        </requiredProperty>
        <requiredProperty key="package">
            <defaultValue>com.thebeastshop.test</defaultValue>
        </requiredProperty>
    </requiredProperties>

    这些属性可以在资源元文件里的任意一个文件里通过${var}来引用,所以的元文件最终都可以选择通过velocity引擎来执行替换后生成。
    默认的属性有:groupId,artifactId,packeage,version等

  • 项目子模块定义
    <modules>
        <module id="${rootArtifactId}-api" name="${rootArtifactId}-api" dir="__rootArtifactId__-api">
            ...
        </module>
        <module id="${rootArtifactId}-core" name="${rootArtifactId}-core" dir="__rootArtifactId__-core">
            ...
        </module>
        <module id="${rootArtifactId}-dao" name="${rootArtifactId}-dao" dir="__rootArtifactId__-dao">
            ...
        </module>
        <module id="${rootArtifactId}-main" name="${rootArtifactId}-main" dir="__rootArtifactId__-main">
            ...
        </module>
        <module id="${rootArtifactId}-mybatisGen" name="${rootArtifactId}-mybatisGen" dir="__rootArtifactId__-mybatisGen">
            ...
        </module>
    </modules>

    module有三个属性,解释如下:
    id     :定义子模块工程的artifactId.
    dir    :子模块工程源文件在archetype-resources里对应的directory.
    name   :子模块的名字.

3.子模块pom.xml定义如下(以core模块为例):

<?xml version="1.0"?>
<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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.thebeastshop</groupId>
        <artifactId>${rootArtifactId}</artifactId>
        <version>${version}</version>
    </parent>

    <artifactId>${artifactId}</artifactId>
    <name>${artifactId}</name>
    
    <dependencies>
        <dependency>
            <groupId>com.thebeastshop</groupId>
            <artifactId>${rootArtifactId}-api</artifactId>
            <version>${api.version}</version>
        </dependency>
        <dependency>
            <groupId>com.thebeastshop</groupId>
            <artifactId>${rootArtifactId}-dao</artifactId>
            <version>${project.parent.version}</version>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
             <plugin> 
                 <artifactId>maven-deploy-plugin</artifactId> 
                 <configuration> 
                    <skip>true</skip> 
                 </configuration> 
             </plugin>
        </plugins>
    </build>
</project>

其中${rootArtifactId}就代表父项目的artifactId.

4.我们和单模块脚手架工程一样,通过mvn clean install命令把该脚手架项目安装到本地maven仓库,然后就可以使用该项目来快速生成新项目结构了,生成命令如下:

mvn archetype:generate 
  -DgroupId=com.thebeastshop
  -DartifactId=ddd
  -Dversion=1.0.0-SNAPSHOT
  -DarchetypeGroupId=com.thebeastshop
  -DarchetypeArtifactId=beast-archetype
  -DarchetypeVersion=1.3-SNAPSHOT -X -DarchetypeCatalog=local

我们就会看到生成好的项目结构如下:

多模块项目脚手架源码:https://github.com/hafizzhang/beast-archetype

四、总结

  在工作中,我们通常要有“偷懒”意识,通过摸索来开发出类似项目脚手架一样的工具来提升自己工作的效率。不能整天都是浑浑噩噩的过去,而且表面上看上去很难的东西实际上并不见得一定就如想象中的难。程序猿还是要有所追求,哈哈~

相关文章
|
15天前
|
XML Java 测试技术
从零开始学 Maven:简化 Java 项目的构建与管理
Maven 是一个由 Apache 软件基金会开发的项目管理和构建自动化工具。它主要用在 Java 项目中,但也可以用于其他类型的项目。
30 1
从零开始学 Maven:简化 Java 项目的构建与管理
|
29天前
|
Java Maven
maven项目的pom.xml文件常用标签使用介绍
第四届人文,智慧教育与服务管理国际学术会议(HWESM 2025) 2025 4th International Conference on Humanities, Wisdom Education and Service Management
89 8
|
27天前
|
Java 应用服务中间件 Maven
Maven的三种项目打包方式——pom,jar,war的区别
Maven 提供了多种打包方式,分别适用于不同类型的项目。pom 用于父项目或聚合项目,便于项目的结构和依赖管理;jar 用于Java类库或可执行的Java应用程序;war 则专用于Java Web应用程序的部署。理解这些打包方式的用途和特点,可以帮助开发者更好地配置和管理Maven项目,确保构建和部署过程的顺利进行。无论是单模块项目还是多模块项目,选择合适的打包方式对于项目的成功至关重要。
66 3
|
2月前
|
Java 关系型数据库 MySQL
Maven——创建 Spring Boot项目
Maven 是一个项目管理工具,通过配置 `pom.xml` 文件自动获取所需的 jar 包,简化了项目的构建和管理过程。其核心功能包括项目构建和依赖管理,支持创建、编译、测试、打包和发布项目。Maven 仓库分为本地仓库和远程仓库,远程仓库包括中央仓库、私服和其他公共库。此外,文档还介绍了如何创建第一个 SpringBoot 项目并实现简单的 HTTP 请求响应。
142 1
Maven——创建 Spring Boot项目
|
2月前
|
Java 关系型数据库 MySQL
如何使用 maven 创建一个 Spring Boot项目
Maven 是一个强大的项目管理工具,通过配置 `pom.xml` 文件自动获取所需的 jar 包,提高开发效率。其核心功能包括项目构建和依赖管理。项目构建支持编译、测试、打包和发布等流程,而依赖管理则通过中央仓库、本地仓库和私有服务器获取和管理项目依赖。示例中展示了如何创建第一个 SpringBoot 项目并实现简单接口。
40 1
如何使用 maven 创建一个 Spring Boot项目
|
2月前
|
Java Maven Android开发
eclipse创建maven项目
本文介绍了在Eclipse中创建Maven项目的步骤,包括打开Eclipse、选择Java项目、完成项目创建以及自动下载插件的过程。
103 2
eclipse创建maven项目
|
2月前
|
缓存 IDE Java
idea的maven项目打包时没有source下的文件
【10月更文挑战第21天】idea的maven项目打包时没有source下的文件
64 1
|
2月前
|
Java API Apache
除了 Maven,还有哪些工具可以管理项目的依赖和版本冲突
除了Maven,常用的项目依赖管理和版本冲突解决工具有Gradle、Ivy、Ant+Ivy、SBT等。这些工具各有特点,适用于不同的开发环境和需求。
126 2
|
2月前
|
Java 应用服务中间件 Maven
【终极解决方案】IDEA maven 项目修改代码不生效。
【终极解决方案】IDEA maven 项目修改代码不生效。
420 1
|
2月前
|
Java 应用服务中间件 Maven
SpringBoot Maven 项目打包的艺术--主清单属性缺失与NoClassDefFoundError的优雅解决方案
SpringBoot Maven 项目打包的艺术--主清单属性缺失与NoClassDefFoundError的优雅解决方案
344 0