Maven高级
本篇在继承Maven初级知识的基础上,继续探讨了
分模块开发与设计 、聚合、继承、属性、版本管理 、资源配置 、多环境开发配置
以及私服这些知识点,进一步完善了maven的知识体系。
maven分模块开发与设计
传统的项目我们用包来区分每个部分的职责和功能,但在maven,我们要考虑聚合思想了。
要创建一个聚合的maven工程,我们首先使用maven创建一个父工程。在POM里面导入相关依赖。
<dependencies>
<!-- servlet依赖的jar包start -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- servlet依赖的jar包end -->
<!-- jsp依赖jar包start -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<!-- jsp依赖jar包end -->
<!--jstl标签依赖的jar包start -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- JSTL实现包 -->
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.5</version>
</dependency>
<!--jstl标签依赖的jar包end -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!--beanUtils的依赖-->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.3</version>
</dependency>
<!--dbutils组件 封装了原生的jdbc-->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
<!--logging-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>8088</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
接下来依次创建子工程,右键父工程,新建模块(使用maven构建,不使用骨架创建)。然后创建实体类
maven-pojo
下辖class User实体类(JavaBean+toString)
maven-utils
下辖一个连接数据库的工具类包括一个获取数据源的方法和一个获取连接对象的方法
maven-dao
由于这个模块需要用到实体类,操作数据库也需要用到工具类。所以dao模块需要依 赖pojo和utils模块。
<dependencies>
<dependency>
<groupId>com.xq.pojo</groupId>
<artifactId>maven-pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xq.utils</groupId>
<artifactId>maven-utils</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
包括一个UserDao的接口和一个impl包中的UserDao实现类UserDaoImpl
maven-service
由于service模块需要调用dao模块里面的数据。所以service模块依赖dao模块。
<dependencies>
<dependency>
<groupId>com.xq.dao</groupId>
<artifactId>maven-dao</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
包括一个UserService的接口和一个impl包中的UserService实现类UserServiceImpl
maven-servlet
由于servlet模块需要调用service模块里面的数据,需要在servlet模块里面引入 service依赖。
<dependencies>
<dependency>
<groupId>com.xq.service</groupId>
<artifactId>maven-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
代码部分编写了一个UserServlet如下:
@WebServlet("/showUserList")
public class UserServlet extends HttpServlet {
UserService userService = new UserServiceImpl(); // 创建 UserService 的实现类实例/**
* 查询用户的所有信息
* @param request HttpServletRequest 对象
* @param response HttpServletResponse 对象
* @throws ServletException 可能抛出的 Servlet 异常
* @throws IOException 可能抛出的 IO 异常
*/
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
response.setContentType("text/html;charset=utf-8"); // 设置响应内容类型和字符编码
List<User> list = userService.findUser(); // 调用 UserService 查找所有用户信息
// 将用户列表存入到 request 作用域
request.setAttribute("list", list);
// 转发请求到 list.jsp 页面
request.getRequestDispatcher("/list.jsp").forward(request, response);
}
}
聚合与继承
聚合
聚合是什么
想象一下,你有一个大型的项目,它由很多小的模块组成,就像一个由多个房间组成的大房子。每个模块都有自己的功能,但它们又相互关联。
如果没有好的管理方式,每次修改一个模块,你可能需要手动去编译、测试和打包每一个相关的模块,这会非常麻烦。
Maven 的聚合思想就好像是给这些模块找了一个“大管家”。它会把所有的模块都集中管理起来。它就像一个指挥中心,可以统一指挥对所有模块的编译、测试和打包操作。一旦某个模块发生变化,这个“大管家”就会自动触发对相关模块的重新编译、测试和打包,而不需要你手动去操作每一个模块。这样大大提高了开发效率,也让整个项目的构建过程更加自动化和高效。
聚合的作用:用于快速构建maven工程,一次性管理多个模块。
如何创建聚合性质的工程
创建一个maven工程,定义打包方式为pom
<packaging>pom</packaging>
定义当前模块管理的其他模块的名称
<modules>
<!--具体模块的名称-->
<module>maven-pojo</module>
<module>maven-dao</module>
<module>maven-service</module>
<module>maven-servlet</module>
<module>maven-utils</module>
</modules>
在子模块里面引入父工程
<parent>
<artifactId>maven-user</artifactId>
<groupId>com.xq</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
PS:不出意外的话,其实你的pom.xml默认就是这样,除非你没按刚才的流程创建父子工程。
在本案例中,我们的maven-user就是一个父工程,专门用来管理其他的子模块。
此时我们测试一下。 在父工程上,使用compile命令:
于是发现所有子项目模块都会成功编译。
编译的顺序是怎么样的?
参与聚合操作的模块最终执行顺序与模块的依赖关系有关系。跟配置顺序没有关系。
各个模块的打包方式(package)
父工程打pom
Web工程打war包
其他工程 打jar包(如果没有任何打包配置,默认就是打jar包)
继承
通过继承可以实现在父工程中的配置,让子模块沿用思考。类似于java中的继承关系。
在子模块中,使用parent标签引入父工程,这样子工程和父工程就有了继承关系了
此时我们点击右侧maven检查,子模块没有任何依赖的注入,但仍然可以使用父工程的所有插件和依赖资源
<parent>
<artifactId>maven-user</artifactId>
<groupId>com.xq</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
上面写过对吗?没事,知识点不一样啦
继承的配置
子项目继承父项目的大部分配置,包括
构建插件( <build> 部分)
依赖管理( <dependencyManagement> 部分)
项目信息(如 groupId 、 artifactId 和 version )
其他配置(如 repositories 、 reporting 等)
覆盖和扩展
子项目可以覆盖父项目的配置,例如指定不同的插件版本或添加新的插件。
子项目也可以扩展父项目的配置,例如添加新的依赖或修改依赖的版本。
多级继承
Maven 支持多级继承,即一个父项目本身也可以是一个子项目,继承另一个项目的配置。
不必要的继承解决办法
不过并不是所有的子模块都需要父模块的资源,。以maven-dao为例,这个子模块并不需要tomcat插件,也不需要servlet jsp相关的依赖。如果全部资源都继承下来就会导致资源的浪费和效率的降低。
此时我们可以使用dependencyManagement标签帮我们管理依赖
具体操作如下
在父工程的pom文件里面定义
<dependencyManagement>
<dependencies>
<!--管理自己的依赖-->
<dependency>
<groupId>com.xq.service</groupId>
<artifactId>maven-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xq.dao</groupId>
<artifactId>maven-dao</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xq.pojo</groupId>
<artifactId>maven-pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xq.utils</groupId>
<artifactId>maven-utils</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xq.servlet</groupId>
<artifactId>maven-servlet</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- servlet依赖的jar包start -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<!-- <scope>provided</scope>-->
</dependency>
<!-- servlet依赖的jar包end -->
<!-- jsp依赖jar包start -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<!-- <scope>provided</scope>-->
</dependency>
<!-- jsp依赖jar包end -->
<!--jstl标签依赖的jar包start -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<!--<scope>provided</scope>-->
</dependency>
<!-- JSTL实现包 -->
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.5</version>
</dependency>
<!--jstl标签依赖的jar包end -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!--beanUtils的依赖-->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.3</version>
</dependency>
<!--dbutils组件 封装了原生的jdbc-->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
<!--logging-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
</dependency>
</dependencies>
</dependencyManagement>
在子模块中按照自己的需求,引入对应的依赖,此时不需要加依赖的版本号了, 因为在父工程里面已经给我们定义好了。
以maven-utils为例
<dependencies>
<!--dbutils组件 封装了原生的jdbc-->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
</dependency>
<!--logging-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--c3p0-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
</dependency>
</dependencies>
除了依赖,插件也是类似的方法来解决---pluginManagement
在父工程的pom中:
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>8088</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
在maven-servlet里面 我们引入tomcat插件,此时不用定义插件的版本号了。
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<!-- <version>2.1</version> -->
<!--
<configuration>
<port>8088</port>
<path>/</path>
</configuration>
-->
</plugin>
</plugins>
</build>
接下来就检查插件在maven-servlet中是否能正常使用,你知道在哪检查的对吧?
总结
聚合和继承的关系
作用:
聚合用于快速构建项目
继承用于快速配置
相同点:
聚合与继承都通过 pom.xml 文件定义
可以在同一个文件中结合使用。
通常,聚合关系用于组织模块,而继承关系用于共享配置。
聚合和继承均属于设计系模块,并无实际的模块内容
不同点:
聚合是在当前模块中配置关系,聚合可以感知到参与聚合的模块都有哪些
继承是在子模块中配置关系,父模块无法感知哪些子模块继承了自己
属性与版本管理&多资源配置
属性(properties)
在定义依赖的版本的时候,我们可以使用属性来描述,方便维护管理。
定义格式:
<!--定义自定义属性-->
<properties>
<spring.version>5.1.9.RELEASE</spring.version>
<junit.version>4.12</junit.version>
</properties>
调用格式:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
改造我们的父工程pom.xml:
<properties>
<javax.servlet-api>3.1.0</javax.servlet-api>
<javax.servlet.jsp-api>2.3.1</javax.servlet.jsp-api>
<jstl>1.2</jstl>
<taglibs-standard-impl>1.2.5</taglibs-standard-impl>
<c3p0>0.9.1.2</c3p0>
<commons-beanutils>1.8.3</commons-beanutils>
<commons-dbutils>1.6</commons-dbutils>
<commons-logging>1.1.1</commons-logging>
<mysql>5.1.18</mysql>
</properties>
是的,将版本统一管理
在pom.xml的依赖部分我们如下定义:
版本管理
但是,当我们的模块开发完成之后,还会有修改,各种更新和升级,那么这会形成多个版本,我们如何区分这些版本呢。
工程版本
SNAPSHOT(快照版本)
项目开发过程中,为方便团队成员合作,解决模块间相互依赖和时时更新的问题,开发者对每个模块进行构建的时候,输出的临时性版本叫快照版本(测试阶段版本)。
快照版本会随着开发的进展不断更新。
RELEASE(发布版本)
项目开发到进入阶段里程碑后,向团队外部发布较为稳定的版本,这种版本所对应的构件文件是稳定的,即便进行功能的后续开发,也不会改变当前发布版本内容,这种版本称为发布版本。
示例:
我们在maven-pojo上面自定义版本:
然后打包(放太多图了,这里就不放图了,你知道怎么打包的对吧?install)
观察本地仓库
出现了一个新版本
工程版本号约定
约定规范:
- <主版本>.<次版本>.<增量版本>.<里程碑版本>
- 主版本:表示项目重大架构的变更,如:spring5相较于spring4的迭代
- 次版本:表示有较大的功能增加和变化,或者全面系统地修复漏洞
- 增量版本:表示有重大漏洞的修复
- 里程碑版本:表明一个版本的里程碑(版本内部)。这样的版本同下一个正式版本相比,相对来说不是很稳定,有待更多的测试
范例: ◆ 5.1.9.RELEASE
在配置文件引入pom属性
我们可以在任意配置文件中加载POM 属性
格式: ${usr.name}
在maven-dao的pom.xml中定义属性:
<properties>
<user.name>eric</user.name>
<user.age>18</user.age>
<user.address>USA</user.address>
</properties>
在maven-dao的user.properties中加载这些属性值
它在maven-dao主程序的resources中
在maven-dao的pom中定义如下配置
然后到本地仓库,查看刚刚打包的jar,解压,你可以看到刚才的数据
多环境配置
在实际开发中,生产环境的配置和开发环境的配置是不一样的。比如生产环境使用的数据库和开发环境的数据库就不一样。
那么在项目由开发环境切换到生产环境的时 候,配置应该如何更改?
示例:
在maven-dao中我们定义不同的数据库连接信息
注意这个jdbc的地址我是瞎写的噢,按自己的地址来
<profiles>
<!-- 生成环境的数据库信息 -->
<profile>
<!-- 环境名称,自定义 -->
<id>pro-env</id>
<properties>
<jdbc.url>jdbc:mysql://127.1.1.1:3306/ssm_db</jdbc.url>
</properties>
</profile>
<!-- 开发环境的数据库信息 -->
<profile>
<id>dev-env</id>
<properties>
<jdbc.url>jdbc:mysql://127.1.1.1:3308/ssm_db</jdbc.url>
</properties>
</profile>
</profiles>
<profiles> :这是一个Maven配置块,用于定义多个不同的构建环境配置,每个环境可以有不同的配置参数。
<profile> :定义一个具体的构建环境配置。每个 <profile> 元素代表一个环境配置。
<id> :为每个环境配置指定一个唯一的标识符(ID)。
在这里, pro-env 代表生产环境, dev-env 代表开发环境。
<properties> :定义该环境配置中的具体属性。这些属性可以在构建过程中被引用。
在properties文件中指定:
jdbc.url=${jdbc.url}
如何根据指定的开发环境进行运行呢?
格式: 指令 –P 环境名称
运行打包之后,我们在本地仓库看看配置信息
私服
我们的项目都是协同开发的,并不是一个人开发所有的模块。如果每个人开发不同的模块,当我们需要别人的模块时,怎么获取?用硬盘拷贝吗?很显然不可取。
那可不可以把大家开发的模块都放在一个公共的服务器上,大家需要别人的模块时, 只需要从这个公共的服务器去获取就可以。
那就搭建一个自己的私服吧
搭建私服
Nexus是SonaType公司的一款maven私服产品
下载地址: https://help.sonatype.com/repomanager3/download
下载解压过后点击bin目录,别着急点exe文件,
在目录栏cmd进入控制台,输入nexus.exe /run nexus
访问服务器,默认端口8081 http://localhost:8081
然后我们就看到以下界面
你可以修改基础配置信息(有需要的话)
修改基础配置信息
在etc目录下面的nexus-default.properties文件中保存nexus的基础配置信息。
比如默认访问端口
修改服务器运行配置信息
在bin目录中的nexus.vmoptions文件保存有nexus服务器运行的配置信息。
比如内存分配的信息等
私服资源获取
仓库的分类:
宿主仓库(hosted)
- 保存无法从中央仓库获取的资源
- 自主研发,它相当于一个私有的仓库
- 第三方非开源项目
代理仓库(proxy)
- 代理远程仓库,通过nexus访问其他公共仓库,例如中央仓库
- 它的主要作用是缓存远程仓库中的资源。
- 代理仓库可以加速构建过程,同时也可以作为内部网络和外部网络之间的桥梁。
仓库组(group)
- 将若干个仓库组成一个群组,简化配置
- 仓库组不能保存资源,属于设计型仓库
登录私服
点击 sign in
去文件夹找就可以找到初始密码,登录成功之后会让你修改密码
设置新密码之后,sign out,重新登录(这里就不放图片了)
主界面介绍
创建仓库
点击创建仓库
选择maven2(hosted),点击进入仓库
点击创建,创建之后
将创建的仓库加入到仓库组里面来(添加到maven-public这个组)
点击maven-public这个组,进入到添加页面
添加之后按save保存即可
向仓库上传资源
点击上传组件之后,填写这些空行
填写完毕之后,点击upload上传成功
IDEA环境中资源上传与下载
配置maven客户端的settings配置文件
<!-- 配置访问你的仓库名称、用户名、密码 -->
<server>
<id>你的仓库</id>
<username>用户名</username>
<password>密码</password>
</server>
配置私服的地址
<mirror>
<id>nexus-krisswen</id>
<mirrorOf>*</mirrorOf>
<url>http://localhost:8081/repository/maven-public/</url>
</mirror>
配置当前项目访问私服上传资源保存的位置
在父工程里面的POM文件配置
<distributionManagement>
<repository>
<id>krisswen-release</id>
<url>http://localhost:8081/repository/krisswen-release/</url>
</repository>
<snapshotRepository>
<id>krisswen-snapshots</id>
<url>http://localhost:8081/repository/krisswen-snapshots/</url>
</snapshotRepository>
</distributionManagement>
发布资源到私服的命令 mvn deploy,在右侧maven的生命周期中,点击后查看控制台效果。
然后去私服Browse检查。
nexus代理阿里云仓库
为了提高资源的下载速度,我们也可以在nexus官方仓库中添加国内阿里云maven仓 库。具体操作如下:
点击 create repository,选中maven(proxy)
设置阿里云:阿里云仓库url:http://maven.aliyun.com/nexus/content/groups/public
将创建的仓库添加到仓库组maven-public,具体步骤与上面一样。
在Available把阿里云代理仓库设置为第一位
设置maven的setting.xml文件
<!-- 使用nexus 配置镜像 -->
<mirror>
<id>nexus-central</id>
<mirrorOf>*</mirrorOf>
<name>Nexus Central</name>
<url>http://localhost:8081/nexus/repository/maven-public/</url>
</mirror>
或者在项目的pom.xml里面指定仓库路径:
<repositories>
<repository>
<id>nexus-central</id>
<name>nexus-central</name>
<url>http://localhost:8081/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
至此,Maven的全部知识点都总结完毕