构建Maven多模块项目
JavaWeb开发一般都会进行分层开发,通常分为
- model,模型层
- dao,数据访问层
- service,业务逻辑层
- web,表现层
分层后,各层职责明确,后期维护起来也会容易一些。接下来我们就是使用Maven来构建以上各层,即构建一个Maven多模块项目,项目目录结构如下所示。 
创建父模块
执行命令:mvn -B archetype:generate -DgroupId=com.jepcc.app -DartifactId=demo -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 ,得到一个新项目。  接下来作如下处理:
- 删除src文件夹
- 修改demo/pom.xml文件
<packaging> 标签在没有指明的情况下默认是jar ,这里将其修改为pom ,表示模块是一个可以被继承的模块。 
创建子模块:model层
进入demo目录,执行命令:mvn -B archetype:generate -DgroupId=com.jepcc.app -DartifactId=model -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 ,在demo目录下生成了model目录,model目录里包含了src目录和pom.xml文件。  且demo/pom.xml里自动新增了以下内容,
<modules>
<module>model</module>
</modules>
接下来做如下处理: 修改model/pom.xml文件
- 删除
<groupId>com.jepcc.app</groupId> 和<version>1.0-SNAPSHOT</version> 因为groupId和version会继承自父模块的groupId和version。 - 增加
<packaging>jar</packaging> 将打包方式设置为jar。

创建子模块:dao模块
在demo目录下,执行命令:mvn -B archetype:generate -DgroupId=com.jepcc.app -DartifactId=dao -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 ,在demo目录下生成了dao目录,dao目录里包含了src目录和pom.xml。  且demo/pom.xml里自动新增了内容,如下,
<modules>
<module>model</module>
<module>dao</module>
</modules>
接下来做如下处理:
- 修改 dao/pom.xml
- 删除
<groupId>com.jepcc.app</groupId> 和<version>1.0-SNAPSHOT</version> 因为groupId和version会继承自父模块的groupId和version。 - 增加
<packaging>jar</packaging> 将打包方式设置为jar。 - 增加依赖
增加对model模块的依赖
<dependency>
<groupId>com.jepcc.app</groupId>
<artifactId>model</artifactId>
<version>${project.version}</version>
</dependency>

创建子模块:service层
在demo目录下,执行命令:mvn -B archetype:generate -DgroupId=com.jepcc.app -DartifactId=service -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 ,在demo目录下生成service目录,service目录里包含src目录和pom.xml文件。  且demo/pom.xml文件自动新增内容,如下,
<modules>
<module>model</module>
<module>dao</module>
<module>service</module>
</modules>
接下来作如下处理:
- 修改 service/pom.xml
- 删除
<groupId>com.jepcc.app</groupId> 和<version>1.0-SNAPSHOT</version> 因为groupId和version会继承自父模块的groupId和version。 - 增加
<packaging>jar</packaging> 将打包方式设置为jar。 - 增加依赖
service 层依赖dao层和model层,但我们只需要添加dao层,因为dao模块中已经添加了对model模块的依赖。
<dependency>
<groupId>com.jepcc.app</groupId>
<artifactId>dao</artifactId>
<version>${project.version}</version>
</dependency>
创建子模块:web层
在demo目录下执行命令:mvn -B archetype:generate -DgroupId=com.jepcc.app -DartifactId=web -DarchetypeArtifactId=maven-archetype-webapp -DarchetypeVersion=1.4 ,在demo目录下生成web目录,web目录包含src目录和pom.xml。web/src/main/webapp/WEB-INF目录下生成了web.xml。 web/src/main/webapp目录下生成了简单的index.jsp,如下,
<html>
<body>
<h2>Hello World!</h2>
</body>
</html>
 且demo/pom.xml自动新增内容,如下,
<modules>
<module>model</module>
<module>dao</module>
<module>service</module>
<module>web</module>
</modules>
接下来作如下处理:
- 修改 web/pom.xml
- 删除
<groupId>com.jepcc.app</groupId> 和<version>1.0-SNAPSHOT</version> 因为groupId和version会继承自父模块的groupId和version。 - 增加依赖
service 层依赖dao层和model层,但我们只需要添加dao层,因为dao模块中已经添加了对model模块的依赖。
<dependency>
<groupId>com.jepcc.app</groupId>
<artifactId>service</artifactId>
<version>${project.version}</version>
</dependency>
注意哈,web层的打包方式是war !!!
编译运行项目
- web模块添加jetty插件
经过以上过程,相关模块全部创建完成,怎么运行起来呢?由于最终运行的是web模块,所以我们对该模块添加jetty支持,方便测试运行,修改web模块的pom.xml,
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>demo</artifactId>
<groupId>com.jepcc.app</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>web</artifactId>
<packaging>war</packaging>
<name>web Maven Webapp</name>
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jepcc.app</groupId>
<artifactId>service</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<finalName>web</finalName>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
- 进入demo目录,执行命令
mvn clean install ,完成模块构建。  构建完成后,web目录下多出了target目录,里面包含web.war 。  - 进入web目录,执行命令:
mvn jetty:run ,启动jetty。  - 打开浏览器访问网址:http://localhost:8080/web/

Maven相关特性
每个子模块都有自己的pom.xml文件,这就意味着每个子模块都有可以添加自己的依赖,这就可能造成一个相同的依赖每个模块都要添加一次,而且添加的版本可能不一致,这会造成项目混乱、导致运行时的各种问题。 所以,就应该有个父模块去统一管理所有的jar包,其他子模块去引用父模块就好了,子模块就不需要重复去定义依赖。
父模块的配置
父模块有两个特点:
- 父模块中没有代码,只有pom.xml文件,用来管理所有依赖及共同配置
- 父模块pom.xml中的
<packaging> 标签必须设置为pom
<groupId>com.jepcc.app</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
父模块聚合子模块
父模块在pom.xml中通过<modules> 和<module> 声明需要聚合的子模块。
<modules>
<module>model</module>
<module>dao</module>
<module>service</module>
<module>web</module>
</modules>
父模块统一管理依赖包
父模块的pom.xml通过<dependencyManagement> 来统一管理所有jar包及其版本,这样子模块要引用一个依赖时,就不需要在自己的pom.xml里显式列出版本号。因为Maven会沿着父子层次往上走,直到找到拥有dependencyManagement 标签的模块,最终确定依赖包对应的版本,并完成加载。 使用<dependencyManagement> 来统一管理依赖的版本号,可以确保各个依赖的版本是一致的。 关于<dependencyManagement> 和<dependencies> ,二者有如下区别:
- 对于
<dependencyManagement> ,只是在父模块中声明依赖,而不实现引入,因此子模块需要显式声明所需要的依赖,否则子模块是不会从父模块中继承下来的。 当子模块显式声明依赖且没有指定版本,子模块会从父模块中继承依赖;当子模块显式声明依赖且指定版本号,Maven会使用子模块中的指定版本。 - 对于
<dependencies> ,即使子模块中不写依赖,子模块依然会从父模块中继承所有依赖。
子模块在pom.xml中声明父模块
子模块在自己的pom.xml中通过<parent> 声明父模块。
<parent>
<artifactId>demo</artifactId>
<groupId>com.jepcc.app</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
参考文章
使用Maven构建多模块项目
|