Maven课程目标
了解maven的基本简介
掌握maven的下载、安装流程
理解maven的基本概念(重点)
动手完成第一个maven项目(重点)
理解依赖管理(重点)
理解生命周期与插件
一、Maven基础
1.1 maven简介
1.1.1传统项目管理状态分析
前面我们通过 Web 阶段项目,要能够将项目运行起来,就必须将该项目所依赖的一些 jar 包添加到 工程中,否则项目就不能运行。试想如果具有相同架构的项目有十个,那么我们就需要将这一份 jar 包复制到十个不同的工程中。我们一起来看一个 CRM项目的工程大小。 使用传统 Web 项目构建的 CRM 项目如下:
此外还有一些其他的问题,比如jar包繁多,容易导致jar包版本不统一,引起jar包冲突的问题。
1.1.2 什么是Maven
Maven 的正确发音是[ˈmevən]。Maven 在美国是一个口语化的词语,代表专家、内行的意思。 一个对 Maven 比较正式的定义是这么说的:Maven 是一个项目管理工具,它包含了一个项目对象模型 (POM:Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Management System),和用来运行定义在生命周期阶段(phase)中插件(plugin)目标 (goal)的逻辑。
1.1.3 Maven的作用
-
我们需要引用各种 jar 包,尤其是比较大的工程,引用的 jar 包往往有几十个乃至上百个, 每用到一种 jar 包,都需要手动引入工程目录,而且经常遇到各种让人抓狂的 jar 包冲突,版本冲突。
-
世界上没有不存在 bug 的代码,计算机喜欢 bug 就和人们总是喜欢美女帅哥一样。为了追求美为了减少 bug,因此写完了代码,我们还要写一些单元测试,然后一个个的运行来检验代码质量。
-
再优雅的代码也是要出来卖的。我们后面还需要把代码与各种配置文件、资源整合到一起,定型打包,如果是 web 项目,还需要将之发布到服务器,供人蹂躏。试想,如果现在有一种工具,可以把你从上面的繁琐工作中解放出来,能帮你构建工程,管理 jar 包,编译代码,还能帮你自动运行单元测试,打包,生成报表,甚至能帮你部署项目,生成 Web 站点,你会心动吗? Maven 就可以解决上面所提到的这些问题
4.统一开发结构,提供标准了、统一的项目结构
1.2 Maven的下载和安装
官网:http://maven.apache.org/http://maven.apache.org/
下载地址:http://maven.apache.org/download.cgihttp://maven.apache.org/download.cgi
为了使用 Maven 管理工具,我们首先要到官网去下载它的安装软件。通过百度搜索“Maven“如下:
进入官网,点击 Download 链接,就可以直接进入到 Maven 软件的下载页面
点击Download,进入选择对应的下载版本:
注意:不同的MAVEN版本,跟IDEA之间也存在适配问题,所以大家在选择maven版本的时候,应该根据自己IDEA的版本选择对应的适配版本,适配版本如下:
IDEA 2022 兼容maven 3.8.1及之前的所用版本
IDEA 2021 兼容maven 3.8.1及之前的所用版本
IDEA 2020 兼容Maven 3.6.3及之前所有版本
IDEA 2018 兼容Maven3.6.1及之前所有版本
1.2.2 Maven的安装
Maven下载后,将 Maven 解压到一个没有中文没有空格的路径下,比如 D:\software\maven 下面。 解压后目录结构如下:
在这里简单介绍一下各个文件的作用:
bin:存放了 maven 的命令,比如我们前面用到的 mvn tomcat:run
boot:存放了一些 maven 本身的引导程序,如类加载器等
conf:存放了 maven 的一些配置文件,如 setting.xml 文件
lib:存放了 maven 本身运行所需的一些 jar 包 至此我们的 maven 软件就可以使用了,前提是你的电脑上之前已经安装并配置好了 JDK。
1.2.2.1 maven及JDK的配置
我们所使用工具软件的统一,JDK 使用 JDK8版本。
- JDK1.8版本安装之后,JDK配置JAVA_HOME
- 配置 MAVEN_HOME ,变量值就是你的 maven 安装 的路径(bin 目录之前一级目录)
- 在环境变量的path目录里面还需要配置:
- Maven 软件版本测试
通过 mvn -v命令检查 maven 是否安装成功,看到 maven 的版本为 3.5.2 及 java 版本为 1.8 即为安装 成功。 找开 cmd 命令,输入 mvn –v命令,如下图:
我们发现 maven 的版本,及 jdk 的版本符合要求,这样我们的 maven 软件安装就成功了。
1.2.3 maven的基本概念
1.2.3.1 仓库
maven 的工作需要从仓库下载一些 jar 包,如下图所示,本地的项目 A、项目 B 等都会通过 maven 软件从远程仓库(可以理解为互联网上的仓库)下载 jar 包并存在本地仓库,本地仓库就是本地文件夹,当第二次需要此 jar 包时则不再从远程仓库下载,因为本地仓库已经存在了,可以将本地仓库理解为缓存,有了本地仓库就不用每次从远程仓库下载了。
下图描述了maven仓库的类型:
- 本地仓库 :用来存储从远程仓库或中央仓库下载的插件和 jar 包,项目使用一些插件或 jar 包,manen项目优先从本地仓库查找 默认本地仓库位置在 ,{user.dir}表示 windows 用户目录。
- 远程仓库(私服):如果本地需要插件或者 jar 包,本地仓库没有,默认去远程仓库下载。远程仓库可以在互联网内也可以在局域网内。
- 中央仓库 :在 maven 软件中内置一个远程仓库地址,http://repo1.maven.org/maven2http://repo1.maven.org/maven2它是中央仓库,服务于整个互联网,它是由 Maven 团队自己维护,里面存储了非常全的 jar 包,它包含了世界上大部分流行的开源项目构件。
注意:默认本地仓库在系统磁盘中,比较浪费系统盘空间,所以我们可以修改本地仓库的默认存放位置。这里我们准备了一个本地仓库,解压之后,放入任意盘符下面即可(不能包含中文路径)。解压之后的本地仓库名字(maven_repository)目录如下:
在 MAVE_HOME/conf/settings.xml 文件中配置本地仓库位置(maven 的安装目录下):
打开 settings.xml文件,配置如下:
1.2.3.2 坐标
maven中的坐标用于描述仓库中资源的位置。https://mvnrepository.comhttps://mvnrepository.com
-
Maven坐标的主要构成
-
groupId 定义当前maven项目隶属组织名称(通常是域名反写,例如org.mybatis)
-
artifactId 定义当前maven项目名称(通常是模块名称)
-
version 定义当前项目版本号
-
packaging 定义该项目的打包方式
-
-
Maven坐标的作用
使用唯一标识,用来定位资源。通过该标识可以将资源的识别与下载交给机器完成。
1.2.3.3 镜像仓库
在中央仓库直接下载通常会比较慢,所以我们在setting.xml文件中配置国内镜像仓库,来解决中央仓库资源下载慢的问题!
- 在settings.xml配置文件中,配置阿里云镜像仓库
<mirror>
<!-- mirror -->
<id>nexus-aliyun</id>
<!-- -->
<mirrorOf>central</mirrorOf>
<!-- -->
<name>Nexus aliyun</name>
<!-- URL -->
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
1.3 构建第一个maven项目(手动制作)
1.3.1 maven项目的目录结构及常用命令
1.3.1.1 maven的项目结构
src/main/java —— 存放项目的.java 文件
src/main/resources —— 存放项目资源文件,如 spring, hibernate 配置文件
src/test/java —— 存放所有单元测试.java 文件,如 JUnit 测试类
src/test/resources —— 测试资源文件 target —— 项目输出位置,编译后的 class 文件会输出到此目录
pom.xml——maven 项目核心配置文件 注意:如果是普通的 java 项目,那么就没有 webapp 目录。
1.3.1.2 maven的常用命令
- mvn compile
compile 是 maven 工程的编译命令,作用是将 src/main/java 下的文件编译为 class 文件输出到 target 目录下。
- mvn clean
clean 是 maven 工程的清理命令,执行 clean 会删除 target 目录及内容。
- mvn test
test 是 maven 工程的清理命令,将测试代码和正式代码全部编译
- mvn package
package 是 maven 工程的打包命令,同时编译正式代码和测试代码。对于 java 工程执行 package 打成 jar 包,对于 web 工程打成 war 包。
- mvn install
install 是 maven 工程的安装命令,执行 install 将 maven 打成 jar 包或 war 包发布到本地仓库。 从运行结果中,可以看出: 当后面的命令执行时,前面的操作过程也都会自动执行。
1.3.2 手动创建maven工程
1.3.2.1 创建目录结构
1.3.2.2 编写源程序
- 主程序
- 测试代码
1.3.2.3 编写POM文件
在src的同级目录下面,编写pom.xml文件。
1.3.2.4 运行maven工程
在pom.xml的同级目录下面,执行cmd命令
- 编译 mvn compile
- 清空 mvn clean
注意: 执行mvn clean之后,之前mvn compile编译的文件也会消失
- 测试 mvn test :
生成的测试报告如下:
- 打包 mvn package
- 安装 mvn install
打开本地仓库
一般常用下面这种方式构建Maven项目
1.3.3 使用idea构建maven工程
1.3.3.1 在maven中创建一个工程(不使用骨架)
- 创建一个空工程
- 选择下一步,设置工程名称和工程目录
- 设置sdk版本
- 设置maven环境
右键settings,选择maven选项。
设置maven客户端的、settings文件以及本地仓库的路径。
具体设置如下:
- 创建modules
- 选择maven
- 点击next,设置组织名称和工程名称
- 设置模块名称
- 点击完成,并且完善工程目录
- 设置编译环境
File –> project Structureàmodules
Settings-->javaCompiler
- 填充代码(和手动创建的代码一样,这里省略)
当然我们还可以设置这些命令的快捷方式
具体设置如下:
设置完成之后的效果如下:
其他命令类似这样的设置。
1.3.3.2 使用maven骨架创建java普通工程
- 选择骨架
- 创建完成
完善resources目录
1.3.3.3.使用maven骨架创建web工程
- 使用web工程的骨架创建
- 创建完成之后的工程目录结构如下:
工程目录并不完整,我们需要补齐工程目录。
-
配置tomcat插件来启动tomcat
在远程仓库搜索tomcat—maven-plugin, 选择2.1版本,点击进入
<build>
<!--定义插件的集合-->
<plugins>
<!--具体的插件-->
<plugin>
<!--插件组织id-->
<groupId>org.apache.tomcat.maven</groupId>
<!-- 插件名称 -->
<artifactId>tomcat7-maven-plugin</artifactId>
<!--插件版本-->
<version>2.1</version>
<configuration>
<!--配置tomcat端口号-->
<port>8088</port>
<!--配置虚拟路径-->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
- 刷新之后,就可以看见tomcat7插件了
如何启动?
也可以配置快捷启动方式:
启动之后。控制台效果如下:
这时启动成功了!!!
1.4依赖管理
1.4.1 依赖配置与依赖传递
依赖指的是当前项目运行所需要的jar,一个项目可以有很多个依赖。
格式:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
依赖传递
依赖具有传递性:
直接依赖:在当前项目中,通过依赖配置建立的依赖关系。
间接依赖:被依赖的资源,如果还依赖其他资源,那么当前项目间接依赖其他资源。
1.4.2 解决依赖冲突的问题
依赖冲突是指项目依赖的某一个jar包,有多个不同的版本,因而造成类包版本冲突。
如下所示:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>
通过查看依赖,我们发现spring-aop和spring-context都依赖了一个叫spring-core的依赖。此时spring-core的版本有两个。这样就产生了依赖冲突
解决依赖冲突:
1、使用第一声明优先的原则
谁先定义的就用谁的传递依赖,即在pom.xml文件自上而下,先声明的jar坐标,就先引用该jar的传递依赖。因此我们如果要使用5.2.0版本的spring-core包,我们可以改成如下声明:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
2、路径近优先原则—直接依赖高于间接依赖
即直接依赖级别高于传递依赖。因此我们可以在最先的pom.xml添加如下内容
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>
3、排除依赖原则
在不影响项目运行的情况下,如果依赖冲突,可以把被冲突的依赖排除掉,注意排除的依赖不需要添加依赖的版本号。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
<exclusions>
<exclusion>
<artifactId>spring-core</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
4、版本锁定
使用dependencyManagement 进行版本锁定,dependencyManagement可以统一管理项目的版本号,确保应用的各个项目的依赖和版本一致。
如果我们项目中只想使用spring core 5.2.0的包,pom.xml可以改为如下
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>
1.4.3 依赖范围
1、什么是依赖范围?
依赖的jar包在默认情况下可以在任何范围内使用,可以通过scope标签来控制其作用范围。
作用范围:
主程序范围有效(main文件夹)
测试程序范围有效(test文件夹)
是否参与打包(package指令范围之内)
举例:在demo3的pom.xml里面引入一个依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
此时在main文件夹和test文件夹里面的java程序里面都可以用到SqlNode这个类(mybatis提供的一个类)。但是如果把mybatis的作用域换成test。如下:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
<scope>test</scope>
</dependency>
在main目录的程序里面:
public class Demo1 {
public void sayHello(){
SqlNode node = new TextSqlNode("");//报错
}
}
但是在test目录的程序里面:
@Test
public void test(){
SqlNode node = new TextSqlNode("");
}
1.5 生命周期与插件
1、生命周期
Maven对项目周期的构建分为3套
clean: 清理工作阶段
default:核心工作阶段。比如编译、测试、打包、部署等
site: 产生报告,发布站点等
-
clean生命周期
-
pre-clean 执行一些需要在clean之前完成的工作
-
clean 移除所有上一次构建生成的文件
-
post-clean 执行一些需要在clean之后立刻完成的工作
-
-
default生命周期
-
site生命周期
-
pre-site 执行一些需要在生成站点文档之前完成的工作
-
site 生成项目的站点文档
-
post-site 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
-
site-deploy 将生成的站点文档部署到特定的服务器
-
2、插件
插件与生命周期内的阶段绑定,在执行到对应生命周期时,执行对应的插件功能。
默认maven在各个生命周期阶段上绑定有预设功能
通过插件可以自定义其他功能
这个插件就是 在生成测试代码的时候,给主程序源代码打包、同时给测试源代码打包。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
<goal>test-jar</goal>
</goals>
<phase>generate-test-resources</phase>
</execution>
</executions>
</plugin>
二、Maven高级
-
分模块开发与设计(重点)
-
聚合(重点)
-
继承(重点)
-
属性(重点)
-
版本管理
-
资源配置
-
多环境开发配置
-
私服(重点)
2.1 maven分模块开发与设计
2.1.1 创建父工程
使用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包start -->
<!-- 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>
<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>
2.1.2 maven-pojo拆分
public class User {
private Integer id;
private String name;
private String gender;
private Integer age;
private String address;
private String email;
private String qq;
private String username;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getQq() {
return qq;
}
public void setQq(String qq) {
this.qq = qq;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
", address='" + address + '\'' +
", email='" + email + '\'' +
", qq='" + qq + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
创建后的目录结构:
2.1.3 maven-utils模块拆分
在父工程上,右键,新建模块(使用maven构建,不使用骨架创建)。然后创建工具类和配置文件:
/**
* 连接数据库的工具类
*/
public class DataSourceConfig {
//根据c3p0-config.xml初始化一个数据源,我们可以从数据源里面获取连接对象(此时已经自动加载了c3p0-config.xml配置文件)
static ComboPooledDataSource dataSource = new ComboPooledDataSource();
/**
* 获取数据源的方法
* @return
*/
public static DataSource getDataSource() {
return dataSource;
}
/**
* 获取连接对象
* @return
* @throws Exception
*/
public static Connection getConnection() throws Exception{
return dataSource.getConnection();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://192.168.10.137:3306/user</property>
<property name="user">root</property>
<property name="password">Admin123!</property>
<!--
初始化的连接数量 在连接池里面初始化10个连接对象
-->
<property name="initialPoolSize">10</property>
<!--
最大空闲时间
某一个连接对象空闲时长最多是30s,超过了30s,该连接对象会被自动回收
-->
<property name="maxIdleTime">30</property>
<!--
最大连接数量
在连接池里面存在最多的连接数量
-->
<property name="maxPoolSize">100</property>
<!--
最小连接数量
-->
<property name="minPoolSize">10</property>
</default-config>
</c3p0-config>
创建后的目录结构如下:
2.1.4 maven-dao模块拆分
在父工程上,右键,新建模块(使用maven构建,不使用骨架创建)。然后创建接口以及实现类。
-
pom文件
由于这个模块需要用到实体类,操作数据库也需要用到工具类。所以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>
- 代码部分
public interface UserDao {
//查询所有用户信息
public List<User> findAll();
}
public class UserDaoImpl implements UserDao {
//DbUtils组件里面的一个核心类 主要是用来进行各种增删改查
QueryRunner runner = new QueryRunner(DataSourceConfig.getDataSource());
/**
* 查询所有用户信息
* @return
*/
public List<User> findAll() {
String sql = "select * from user";
try {
/**
* 参数1 要执行的sql语句
* 参数2 我们从数据库服务器里面查询出来的是一条条sql语句,我们在java后台肯定不能接收一条条sql语句
* 怎么办? 把这一条条sql语句封装到List集合里面
* 怎么封装? 使用一个DbUtils给我们提供的处理器来实现 BeanListHandler
* User.class 就是告诉BeanListHandler将一条条sql语句转换成List集合的时候,封装什么类型的数据
* 放在list集合里面
*/
List<User> list = runner.query(sql, new BeanListHandler<User>(User.class));
return list;
} catch (SQLException e) {
throw new RuntimeException();
}
}
}
最后目录结构如下:
2.1.5 maven-service模块拆分
在父工程上,右键,新建模块(使用maven构建,不使用骨架创建)。然后创建业务接口以及实现类。
-
pom文件
由于service模块需要调用dao模块里面的数据。所以service模块依赖dao模块。
<dependencies>
<dependency>
<groupId>com.xq.dao</groupId>
<artifactId>maven-dao</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
- 代码部分
public interface UserService {
//查询所有用户信息
public List<User> findUser();
}
public class UserServiceImpl implements UserService {
UserDao userDao = new UserDaoImpl();
//查询所有用户信息
public List<User> findUser() {
return userDao.findAll();
}
}
2.1.6 maven-servlet模块拆分
在父工程上,右键,新建模块(使用maven构建,使用骨架创建)。然后创建servlet
-
pom文件
由于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>
- 代码部分
@WebServlet("/showUserList")
public class UserServlet extends HttpServlet {
UserService userService = new UserServiceImpl();
/**
* 查询用户的所有信息
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
List<User> list = userService.findUser();
//将list存入到request作用域
request.setAttribute("list",list);
//转发到list.jsp页面
request.getRequestDispatcher("/list.jsp").forward(request,response);
}
}
前台jsp页面参照素材。
2.2 聚合与继承
2.2.1 聚合
我们思考一个问题
上面的各个模块是分开独立开发的,彼此互相独立,互补影响。假设如果现在maven-dao模块更新升级了,那么其他模块是如何感知dao模块发生了变化的?
解决方案:
会不会有一个工程,专门对这些模块进行管理。对这些模块进行统一的编译,测试,打包等操作。一旦一个模块发生了变化,会同时对其他模块也进行编译、测试、打包。
此时就需要用到聚合的思想。
聚合的作用:用于快速构建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>
在本案例中,我们的maven-user就是一个父工程,专门用来管理其他的子模块。
此时我们测试一下。
在父工程上,使用compile命令:
此时所有的模块都会进行编译。
问题:编译的顺序是怎么样的?
参与聚合操作的模块最终执行顺序与模块的依赖关系有关系。跟配置顺序没有关系。
-
各个模块的打包方式
父工程打pom
Web工程打war包
其他工程 打jar包(如果没有任何打包配置,默认就是打jar包)
2.2.2 继承
通过继承可以实现在父工程中的配置,让子模块沿用思考。类似于java中的继承关系。
实现:
在子模块中,使用parent标签引入父工程,这样子工程和父工程就有了继承关系了
<parent>
<artifactId>maven-user</artifactId>
<groupId>com.xq</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
测试观察效果:
在maven-dao的pom文件里面没有配置任何依赖资源。
但是maven-dao却是继承了maven-user父工程的所有依赖资源
其他子模块一样,都继承了父工程的资源。
思考:这样的做法有没有问题?
答案:有,并不是子模块都需要所有父工程的资源。以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包start -->
<!-- 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>
此外插件也可以用类似的方法进行管理。在父工程的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>
配置之后效果如下,插件依然可以正常引入
总结:
聚合和继承的关系
-
作用:
-
聚合用于快速构建项目
-
继承用于快速配置
-
-
相同点:
-
聚合与继承的pom.xml文件打包方式均为pom。可以将两种关系定义在同一个pom文件中。
-
聚合和继承均属于设计系模块,并无实际的模块内容
-
-
不同点
-
聚合是在当前模块中配置关系,聚合可以感知到参与聚合的模块都有哪些
-
继承是在子模块中配置关系,父模块无法感知哪些子模块继承了自己
-
2.3 属性与版本管理&多资源配置
2.3.1 属性
在定义依赖的版本的时候,我们可以使用属性来描述,方便维护管理。
定义格式:
调用格式:
改造我们的父工程:
<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我们如下定义:
2.3.2 版本管理
我们的模块开发完成之后,并不是一成不变的。后续肯定会进行更新升级,那么这样会形成多个版本,那么如何来区分这些版本呢?
测试:
我们在maven-pojo上面自定义版本
然后打包
观察本地仓库
工程版本号约定:
2.3.3 在配置文件引入pom属性
我们可以在任意配置文件中加载POM 属性
格式: ${usr.name}
在maven-dao中定义属性:
在maven-dao的user.properties中加载这些属性值
在maven-dao的pom中定义如下配置
<build>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
到本地仓库,查看打包的jar包,解压并查看
2.4 多环境配置
在实际开发中,生产环境的配置和开发环境的配置是不一样的。比如生产环境使用的数据库和开发环境的数据库就不一样。那么在项目由开发环境切换到生产环境的时候,配置应该如何更改?
实例:
在maven-dao中我们定义不同的数据库连接信息
<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>
在properties文件中指定:
jdbc.url=${jdbc.url}
那么如何根据指定的开发环境进行运行呢?
格式: 指令 –P 环境名称
运行打包之后,我们在本地仓库看看配置信息
2.5 私服
我们的项目都是协同开发的,并不是一个人开发所有的模块。如果每个人开发不同的模块,当我们需要别人的模块时,怎么获取?用硬盘拷贝吗?很显然不可取。
应该怎么办?
可不可以把大家开发的模块都放在一个公共的服务器上,大家需要别人的模块时,只需要从这个公共的服务器去获取就可以。
2.5.1 搭建私服
-
Nexus是SonaType公司的一款maven私服产品
-
下载地址: Downloadhttps://help.sonatype.com/repomanager3/download
我们已经给大家准备好了安装包
- 解压之后的目录结构
- 启动命令
-
启动服务 nexus.exe /run nexus
-
在bin目录打开cmd 输入启动命令: nexus.exe /run nexus
-
访问服务器,默认端口8081 http://localhost:8081
-
修改基础配置信息
-
在etc目录下面的nexus-default.properties文件中保存nexus的基础配置信息。比如默认访问端口
-
-
修改服务器运行配置信息
-
在bin目录中的nexus.vmoptions文件保存有nexus服务器运行的配置信息。比如内存分配的信息等
-
2.5.2 私服资源获取
仓库的分类:
2.5.2.1 登录私服
点击 sign in
按照指定的密码登录之后
我们需要设置新的密码:
设置密码之后,sign out,重新登录
2.5.2.2 创建仓库
点击创建仓库:
选择maven2(hosted),点击进入仓库
点击创建,创建之后
将创建的仓库加入到仓库组里面来(添加到maven-public这个组)
点击maven-public这个组,进入到添加页面
添加之后的效果,点击save保存
2.5.2.3 向仓库上传资源
点击上传组件:
最后点击upload按钮
2.5.2.4 IDEA环境中资源上传与下载
- 配置maven客户端的settings配置文件
<!--配置访问krisswen-release的仓库名称、用户名、密码-->
<server>
<id>krisswen-release</id>
<username>admin</username>
<password>admin</password>
</server>
<!--配置访问krisswen-snapshots的仓库名称、用户名、密码-->
<server>
<id>krisswen-snapshots</id>
<username>admin</username>
<password>admin</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
查看控制台效果:
最后在私服上面查看是否上传成功:
2.5.3 nexus代理阿里云仓库
为了提高资源的下载速度,我们也可以在nexus官方仓库中添加国内阿里云maven仓库。具体操作如下:
-
第一步:点击repositories
- 点击 create repository,选中maven(proxy)
-
设置阿里云
- 将创建的仓库添加到仓库组maven-public
- 把阿里云代理仓库设置为第一位
移动之后的效果:
- 设置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的全部内容了,希望对读者有帮助!!