为什么要使用 Maven Archetype
每次我们要使用框架写一个网站时,比如 SSM,我们总是需要手写 applicationContenxt.xml,mybatis-config.xml 和 jdbc.properties 这些配置文件,每一次写的时候都会发现它们是大同小异的,于是聪明的我们学会了建立一份模板,每次要使用时就复制粘贴。同样的还有 controller,service,dao 这些目录,我们干脆建立一个网站模板,每次使用的时候就从这个模板复制出来一份,然后进行微调就可以使用了。这种方法一般来说是高效的(相比较从头开始写),但却有许多繁琐的问题。
一,包与代码的结构
比如我们建立了如下的模板结构,controller 这些包一般是要包含在一个父包中的,比如 com.tree.controller 之类的,而不是直接 controller。很容易,给它添加几层目录就可以了,如下:
你创建的模板 | 创建项目后添加包 |
java |_ controller |_ service |_ dao |_ model |_ Main.java | java |_ com |_ tree |_ controller |_ service |_ dao |_ domain |_ Main.java |
package com.tree; // 为 Main.java 添加 package
public class Main{
public static void main(String args[]){
System.out.println("hello world");
}
}
但是如果模板中的类不只一个呢,这种情况下你难道要为每个类都手动修改 package 字段吗,Are you kidding?
二,代码中的某些属性值
比如我们在 main/resources 下有一个 jdbc.properties,其中是关于数据源的配置,如下:
# jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///demo?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
你在复制粘贴之后一样要手动修改这些值,最起码 jdbc.url 这个值是必须改的。
也许你是一个很小心的人,你觉得这种问题对你来说不大,但你有没有想过,就只有我刚才说的那些吗?比如:
<!-- spring 寻找注解的路径配置 -->
<context:component-scan base-package="com.tree.*"/>
<!-- mybatis 生成 mapper 的路径配置 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"
p:basePackage="com.tree.mapper"/>
...
...
...
需要你修改的东西太多了,就算你够细心,但这也失去了意义,这已经和我们要的方便想去甚远了。
恩,总结来说,我们使用上述类型的模板,我们不仅需要给它添加父包,还要修改代码中 N 多的属性值,真是想想都心累。当然了,如果你不嫌麻烦,你完全可以自己写一个类,根据实际需要动态加工你的模板,这样你就不用手动修改那么多东西了,这也是不难的。不过现在有一个通用的解决方案存在,建议还是不要造重复的轮子好。
现在开始进入正题了,大家第一次使用 Maven 建立项目的时候应该使用过 maven-archetype-quickstart 或者是 maven-achetype-wepapp,Maven 提供了一个插件,让我们可以建立自己的 archetype(原型,模板),其支持自定义变量设置,完全可以解决上面说的那些问题。那么下面先来讲解 maven 模板的结构
创建 Archetype
一,添加插件依赖
<!-- 创建模板的插件 -->
<plugin>
<artifactId>maven-archetype-plugin</artifactId>
<version>3.0.1</version>
</plugin>
<!-- 识别空目录 -->
<!-- 不然如果你的模板里含有空目录,在编译成 Archetype 的时候就会被忽略掉 -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<includeEmptyDirs>true</includeEmptyDirs>
</configuration>
</plugin>
二,Archetype 的结构
对象 | 含义 |
---|---|
pom.xml | 建立模板的 pom,每个 Maven 项目都有的东西 |
src/main/resources/archetype-resources | 模板的内容 |
src/main/resources/META-INF/maven/archetype-metadata.xml | 模板的描述,变量等东西的配置 |
archetype-resources 用来存放模板的内容,里面和一般的 Maven 工程是一样的结构,我们可以根据自己的需求在里面建立我们的模板。
archetype-metadata.xml 用来描述模板的变量,默认提供以下变量
${groupId},${artifactId},${version},${package}
前面三个变量是模板内容中 pom.xml 的坐标,当使用模板时我们输入的坐标信息会注入到项目中。
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<version>${version}</version>
第四个变量,也就是 ${package},很好理解的,只要我们将其放在类的 package 字段中,初始化项目的时候,会被注入进去,其值默认和 ${groupId} 一样。
package ${package}.dao;
public class BaseDao{
public static void main(String args[]){
System.out.println("hello world");
}
}
除了上述变量外,我们还可以自定义变量,如 database,username,password 等,只需要使用 ${ } 括起来就行,如下:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///${database}?characterEncoding=utf-8
jdbc.username=${username}
jdbc.password=${password}
这样只要我们建立项目之后设置这些字段,我们就不用再手动去修改这些属性了。
${ } 这个符号我们也常用,你可能会担心冲突问题。但请放心,这是不会的,因为 Archetype 插件只会对 被过滤的 并且 定义过的 变量进行修改。这是什么意思呢?一切的答案都在 archetype-metadata.xml 这个文件中,先来看看其结构。
archetype-descriptor (name)
|_ fileSets
|_ fileSet (filtered,packaged) -- 被过滤的
|_ directory
|_ includes
|_ include
|_ excludes
|_ exclude
|_ requiredProperties
|_ requiredPropery (key) -- 定义过的
|_ defaultValue
我们先来讲讲 <requiredProperties>,这个就是我们自定义变量的关键,我们自定义的所有变量都要在这里面声明。每个变量就是一个 <requiredProperties>,key 就是变量的名称,defaultValue 就是变量的默认值,使用上面的 jdbc.properties 为例。
<requiredProperties>
<requiredProperty key="database">
<defaultValue>demo</defaultValue>
</requiredProperty>
<requiredProperty key="username">
<defaultValue>root</defaultValue>
</requiredProperty>
<requiredProperty key="password">
<defaultValue>root</defaultValue>
</requiredProperty>
</requiredProperties>
# 模板中的数据
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/${database}?characterEncoding=utf-8
jdbc.username=${username}
jdbc.password=${password}
# 使用模板创建项目后
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/demo?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
接下来我们来看看 <fileSets> 这个标记,简单来说就是用来过滤文件的,模板在初始化时会将 <fileSets> 中定义的文件复制到要生成的项目中,同时将变量设为我们需要的值。如果我们的 <fileSets> 为空,那么当我们初始化项目的时候将会变成只含有一个 pom.xml 的项目。
一般 <fileSets> 配置需要包括以下结构
src
|_ main
|_ java
|_ resources
|_ webapp
|_ test
|_ java
|_ resources
相应的配置如下:
<fileSets>
<fileSet>
<directory>src/main/java</directory>
<includes>
<include>**/*.java</include>
</includes>
</fileSet>
<!-- 其他目录配置同上,省略 -->
</fileSets>
上面是一个最基本的写法,但是这样只是将简单地模板复制项目中而已,我们之前在 <requiredProperties> 中定义的变量将不会起作用,我们需要使用它的一个属性 filtered,当这个属性为 true 时,我们设置的变量才会被捕捉到,并注入我们需要的数据。
<fileSet filtered=“true”>
恩,讲到这里其实已经差不多了,现在就剩最后一个问题了,也就是我们最开始提到过的 包与代码的结构 这个问题,这个问题相比较其他的属性设置问题已经算简单得不得了了可以通过 <fileSet> 的 packaged 属性来建立。
模板 | 应用到项目的模板 |
java |_ controller |_ service |_ dao |_ domain |_ Main.java | java |_ com |_ tree |_ controller |_ service |_ dao |_ domain |_ Main.java |
以这张表为例,要达到图二的效果我们只需要这么配置,如下
<fileSet packaged=“true”>
最后变成这个样子
<fileSets>
<fileSet filtered="true" packaged="true">
<directory>src/main/java</directory>
<includes>
<include>**/*.java</include>
</includes>
</fileSet>
</fileSets>
总结
步骤
- 通过上面讲的建立一个模板
- 在模板项目目录下打开终端输入 mvn install
- 在终端使用 mvn archetype:crawl 生成 archetype-catalog.xml
或 mvn archetype:update-local-catalog 更新本地模板索引
使用
- 在终端中输入 mvn archetype:generate -DarchetypeCatalog=local
- 在 eclipse 创建 Maven 项目那里点击添加本地目录文件,就是步骤 8 说的 archetype-catalog.xml(默认位于 .m2 目录下)
- 在 IDEA 创建 Maven 项目那个页面点击添加,然后输入模板的坐标(groupId,artifactId,version)
这里有一个现成的 Maven Archetype 可供参考:简单的 SSM 集成