写在前面

开发新项目就需要搭建新工程,但是搭建新工程的这个过程是非常繁琐浪费时间的,并且不可避免的需要踩坑。更可怕的是,如果是在一个团队中,每新起一个项目都由不同的开发人员去自定义的搭建工程结构,那么对后续的统一管理,监控,运维简直是灾难。基于以上几点,团队内部其实是非常有必要搭建一个统一的脚手架来供统一使用

制作一个脚手架

下面我们就来详细的介绍如何搭建一个maven工程的脚手架

要搭建脚手架,首先我们需要一个模板工程,这个模板工程一般来说会集成一些工具类,底层中间件,通用配置,并且要有良好的分层结构等。需要能够达到开箱即用的程度。

以下是一个模板工程的目录结构,也是目前我们团队内部的标准化结构

.
├── example-client
│   ├── pom.xml
│   └── src
├── example-core
│   ├── pom.xml
│   └── src
├── example-server
│   ├── pom.xml
│   └── src
├── example-test
│   ├── pom.xml
│   └── src
├── Jenkinsfile
├── README.md
├── .gitignore
└── pom.xml

完成模板工程的搭建后,需要在模板工程的最外层 pom 文件加入以下配置

<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-archetype-plugin</artifactId>
<version>3.0.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>

完成之后在根目录下执行

mvn archetype:create-from-project

刷新项目后,会发现在 ./target/generated-sources/archetype目录下生成了脚手架工程,生成的脚手架工程可以当成是一个独立的项目,目录结构如下图

.
├── pom.xml
├── src
│   ├── main
│   │   └── resources
│   │   ├── META-INF
│   │   │   └── maven
│   │   │   └── archetype-metadata.xml
│   │   └── archetype-resources
│   │   ├── Jenkinsfile
│   │   ├── README.md
│   │   ├── __artifactId__.iml
│   │   ├── __rootArtifactId__-client
│   │   │   ├── __parentArtifactId__-client.iml
│   │   │   ├── pom.xml
│   │   │   └── src
│   │   ├── __rootArtifactId__-core
│   │   │   ├── __parentArtifactId__-core.iml
│   │   │   ├── pom.xml
│   │   │   └── src
│   │   ├── __rootArtifactId__-server
│   │   │   ├── __parentArtifactId__-server.iml
│   │   │   ├── pom.xml
│   │   │   └── src
│   │   ├── __rootArtifactId__-test
│   │   │   ├── __parentArtifactId__-test.iml
│   │   │   ├── pom.xml
│   │   │   └── src
│   │   └── pom.xml
│   └── test
│   └── resources
│   └── projects
│   └── basic
│   ├── archetype.properties
│   └── goal.txt

在脚手架工程目录下执行 mvn install 就完成了脚手架的本地安装,安装完成之后,这个脚手架在本地就可以使用了

可以执行以下脚本来通过此脚手架创建项目

mvn archetype:generate -DgroupId=com.xxx.example -DartifactId=xxxx -Dpackage=com.xxx.example -DarchetypeGroupId=com.demo.archetype -DarchetypeArtifactId=demo-archetype -DarchetypeVersion=1.0.0-SNAPSHOT -DinteractiveMode=false

扫坑

不过如果我们直接这样使用的话,会发现生成了很多我们并不想要它出现的文件,比如 .idea .iml 文件等等,并且 .gitignore 文件也诡异的消失了(不知为何会忽略这个文件??)... 这显然不是成熟的脚手架了。那么就需要对它做一些额外的配置了

有两种方式可以解决上面出现的问题

  1. .gitignore文件重命名为 __gitignore__,然后在模板工程根目录下新建 archetype.properties 文件,并填入以下内容
## generate for archetype-metadata.xml
excludePatterns=archetype.properties,*.iml,.idea/,.idea/libraries,logs/,build.sh
## generate .gitignore file
gitignore=.gitignore

完成上述配置后,重新执行 mvn archetype:create-from-project 生成脚手架工程。再完成本地安装,上面出现的问题就会解决

  1. 第二种方式本质上和第一种方式是一样的,只是第二种方式是直接修改脚手架工程的配置文件。第一种方式相当于是执行  mvn archetype:create-from-project 时读取了 archetype.properties 帮我们做了配置文件的修改。

maven的脚手架工程下有两个重要的配置文件

  • ./src/test/resources/projects/basic/archetype.properties

    • 这里可以加入自定义变量,如  gitignore 变量
  • ./src/main/resources/META-INF/maven/archetype-metadata.xml

下面是一个典型的archetype-metadata.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<archetype-descriptor 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" name="example"
xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<requiredProperties>
<requiredProperty key="gitignore">
<defaultValue>.gitignore</defaultValue>
</requiredProperty>
<requiredProperty key="port">
<defaultValue>8888</defaultValue>
</requiredProperty>
</requiredProperties>
<fileSets>
<fileSet encoding="UTF-8" filtered="true">
<directory></directory>
<includes>
<include>__gitignore__</include>
<include>README.md</include>
<include>Jenkinsfile</include>
<include>pom.xml</include>
</includes>
</fileSet>
</fileSets>
<modules>
<module id="${rootArtifactId}-client" dir="__rootArtifactId__-client" name="${rootArtifactId}-client">
<fileSets>
<fileSet filtered="true" packaged="true" encoding="UTF-8">
<directory>src/main/java</directory>
<includes>
<include>**/*.java</include>
</includes>
</fileSet>
</fileSets>
</module>
<module id="${rootArtifactId}-core" dir="__rootArtifactId__-core" name="${rootArtifactId}-core">
<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>**/*.xml</include>
</includes>
</fileSet>
</fileSets>
</module>
<module id="${rootArtifactId}-server" dir="__rootArtifactId__-server" name="${rootArtifactId}-server">
<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>**/*.xml</include>
</includes>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory>src/main/resources/META-INF/dubbo</directory>
<includes>
<include>*</include>
</includes>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory>src/main/resources</directory>
<includes>
<include>**/*.yml</include>
</includes>
</fileSet>
</fileSets>
</module>
<module id="${rootArtifactId}-test" dir="__rootArtifactId__-test" name="${rootArtifactId}-test">
<fileSets>
</fileSets>
</module>
</modules>
</archetype-descriptor>

archetype-metadata.xml 结构

简单介绍archetype-metadata.xml文件的基本结构

  • <requiredProperties>是属性变量定义层,在这里定义的变量可以在archetype工程文件中通过 ${xxx} 来进行引用,文件名则可以通过 __xxx__来引用变量(这就是为什么要把.gitignore重命名为__gitignore__)。变量在执行 mvn archetype:generate时才录入真正内容
  • 再往下其实就是定义将要生成的工程目录结构,首先是一个 fileSets (包含多个 fileSet标签)标签定义了根目录需要生成哪些文件,再通过多个 modules 标签来定义多个子模块(如果是多模块工程的话)。这其中比较重要的其实还是 fileSet标签,fileSet有两个重要的属性
    • filtered = true 如果为true,则该 fileSet包含的文件中的 ${} 占位符会被替换成相应的变量
    • packaged = true 如果为true,则 src/main/java 下得文件内容会被加入 指定包路径下

总结

一个优秀少坑的脚手架还是能极大的提升生产力的,毕竟这种重复且无价值的劳动我们还是交给工具吧

开发一个maven脚手架的更多相关文章

  1. 开发一个 Parcel-vue 脚手架工具

    前言 像我们熟悉的 vue-cli,create-react-app 等脚手架,只需要输入简单的命令 vue init webpack project,即可快速帮我们生成一个初始项目.在实际工作中,我 ...

  2. 如何开发一个maven插件

    maven是当下最流行的项目管理工具,其丰富的插件为我们的工作带来了很大的便利. 但是在一些情况下,开源的插件并不能完全满足我们的需求,我们需要自己创建插件,本文就从0开始带大家一起创建自己的插件. ...

  3. 基于IDEA Plugin插件开发,撸一个DDD脚手架

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 最近很感兴趣结合 IDEA Plugin 开发能力,扩展各项功能.也基于此使用不同的案例,探索 ...

  4. spring-boot+spring-cloud+maven-module 一个 maven多模块的微服务架构模版

    spring-boot-cloud-module spring-boot+spring-cloud+maven-module 一个 maven多模块的微服务架构模版. 新手上路的绝佳模版,只有必要的配 ...

  5. MAVEN学习-第一个Maven项目的构建

    MAVEN安装成功之后就可以进行项目的构建和管理了: 为什么要用maven进行项目的构建和管理? 对于初学者来说一个最直接的也是最容易里的优点在于JAR包的管理,相对于以前开发一个项目的时候我们需要用 ...

  6. Eclipse中一个Maven工程的目录结构

    在之前的javaSE开发中,没有很关注Eclipse工程目录下的环境,总是看见一个src就点进去新建一个包再写一个class.以后的日子中也没有机会注意到一个工程到底是怎么组织的这种问题,跟不要说自己 ...

  7. 【niubi-job——一个分布式的任务调度框架】----如何开发一个niubi-job的定时任务

    引言 上篇文章LZ主要讲解了niubi-job如何安装,如果看过上一篇文章的话,大家应该知道,niubi-job执行的任务是需要用户自己上传jar包的. 那么问题来了,这个jar包如何产生?有没有要求 ...

  8. web项目环境搭建(1):建立一个maven项目

    一.maven简介以及常用概念 1.Maven是一个项目管理和整合的工具.Maven为开发者提供了一套完整的构建生命周期框架.开发团队基本不用花多少时间就能自动完成工程的基础构建配置,因为Maven使 ...

  9. JavaEE开发使用Maven管理的SpringMVC工程

    前几篇博客已经陆陆续续的聊了一些Spring的东西,今天博客我们就来聊一下SpringMVC.SpringMVC目前在JavaEE开发中可谓占据一席之地,用起来也是比较顺手的.低耦合,高内聚,利用一些 ...

随机推荐

  1. Scrapy模拟登录信息

    携带cookie模拟登录 需要在爬虫里面自定义一个start_requests()的函数 里面的内容: def start_requests(self): cookies = '真实有效的cookie ...

  2. typeahead自动补全插件的limit参数问题

    遇到的问题很诡异: 后台返回的数据都正确就是显示不正常(有时多有时少),后来发现是typeahead的问题,在1.11版本之后,limit参数从option选项里改到了setdata选项: limit ...

  3. 【Leetcode】104. 二叉树的最大深度

    题目 给定一个二叉树,找出其最大深度. 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数. 说明: 叶子节点是指没有子节点的节点. 示例:给定二叉树 [3,9,20,null,null,15,7 ...

  4. L3.二.return

    # 函数的返回值 def get_max(a,b,c): max_num=a if b > max_num: max_num = b if c > max_num: max_num = c ...

  5. Spring PropertyPlaceholderConfigurer类载入外部配置

    2019独角兽企业重金招聘Python工程师标准>>> 通常在Spring项目中如果用到配置文件时,常常会使用org.springframework.beans.factory.co ...

  6. django源码分析——本地runserver分析

    本文环境python3.5.2,django1.10.x系列 1.根据上一篇文章分析了,django-admin startproject与startapp的分析流程后,根据django的官方实例此时 ...

  7. redis-py中的坑

    今天发现,使用redis-py从redis中获取的数据竟然是加密的. conn = redis.Redis(host='redis_serverip', port=6379, password='re ...

  8. ssrf爆破mysql

    php ssrf 代码<?php $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $_GET['url']); #curl_setopt($ch ...

  9. P1666前缀单词

    题目传送门点我传送 Ⅰ.字典树+树型DP 非常奇妙的一种解法 第一部分:构建树 先对来的单词读入,插入字典树 然后对于一颗字典树,其实是有很多无用边的,所以我们需要删去一些边 删去非单词节点和非单词节 ...

  10. java基础 之 从Class.forName()跟.class的区别看类的初始化

    代码如下: public class Test { public static void main(String[] args) throws Exception { System.out.print ...