生产过程中需要Maven吗?
- maven真的需要吗?
Maven 是干什么用的?这是很多同学在刚开始接触 Maven 时最大的问题。之所以会提出这个问题, 是因为即使不使用 Maven 我们仍然可以进行 B/S 结构项目的开发。从表述层、业务逻辑层到持久化层 再到数据库都有成熟的解决方案——不使用 Maven 我们一样可以开发项目啊?
Maven 并不是直接用来辅助编码的,它战斗的岗位并不是以上各层。所 以我们有必要通过企业开发中的实际需求来看一看哪些方面是我们现有技术的不足。
生产环境下开发对Maven的需求
- 目前技术在开发中存在的问题
-
一个项目就是一个工程
- 如果一个项目非常庞大,就不适合继续使用package划分模块,最好是每一个模块对应一个工程,利于分工协作,
- 一个项目可以借助于Maven将一个项目拆分成多个工程
-
项目中需要的jar包必须手动"复制","粘贴"到WEB-INF/lib目录下
- 带来的问题是:同样的jar包文件重复出现在不同的项目工程中.一方面浪费存储空间,另外也让工程比较臃肿
- 借助于maven,可以将jar包仅仅保存在"仓库中",有需要使用的工程引用这个文件接口,并不需要真正复制这个jar包.
-
jar包需要别人替我们提供好,或者去官网下载
- 不同技术的官网提供jar包下载的形式是五法八门的.
- 有些技术的官网就是通过Maven或SVN等专门的工具来提供下载的.
- 如果以非正式的方式下载的jar包,那么其中的内容可能也是不正规的.
- 借助于Maven可以以一种规范的方式下载jar包,因为所有知名框架或第三方工具的jar包以及按照统一的规范放在了Maven的中央仓库之中.
- 以规范的方式下载jar包,内容也是可靠的
统一的规范,不仅是对IT开发领域非常重要,对于整个人类社会都是非常重要的
- 项目kar包依赖其他的jar包需要自己手动加到项目中
- 例如:FIleUpload组件–>commons-fileipload1.3.jar依赖于commons-io-2.0.jar
- 如果所有的jar包之间的依赖关系都需要程序员自己非常清楚的了解,那么就会极大的增加学习成本.
- Maven会自动将被依赖的jar包导入进来.
构建的概念
-
maven是一款服务于java平台的自动化构建工具.
- Make–Ant–Maven–Gradle
-
概念:
以java源文件,框架配置文件,JSP,HTML,图片等资源为原材料,去生产一个可以运行的项目的过程
-
构建可以分为以下三步
- 编译
- 部署
- 搭建
-
编译
- java源文件–>编译—>Class字节码文件,—>交给JVM区执行
-
部署
- 一个BS项目最终运行的并不是动态web工程本身,而是这个动态web工程"编译结果"
- 动态Web工程—>编译,部署–>编译结果
运行时环境
所谓的运行其实是一组jar包的引用并没有把jar包本身复制到工程之中,并不是目录
- 在Eclipse中创建项目时,往往会发现以下的结构
- 其实libraries中的内容保存的就是运行项目时所需的基本开发包,编写java项目就要求有JDK开发包,运行tomcat项目就需要有运行tomcat所需的开发包,我们编写java程序类或者编写Servlet和JSP都需要有这些基本开发包,这就称之为运行时环境
- 如果没有这些开发包的支持,那么也将无法编写java程序.
工程目录和编译结果
- 观察变异结果和工程目录的区别
-
一个动态web项目运行在的时候是不需要java源文件的,所以在工程中编写的*.java文件不会被保留到编译结果中,而是保留*.java文件编译后的*.class文件,所有的*.class文件都会保留到WEB-INF中.
-
因此在编写路径的时候尽量用绝对路径,而不要使用相对路径.
-
观察绝对路径和相对路径的区别
-
在Chiken工程中的WebContent目录中编写index.jsp,该页面提供一个超链接,该超链接跳转到/WebContent/good/welcome.jsp页面中
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<a href="good/welcome.jsp">go to</a>
</body>
</html>
- 编写/WebContent/good/welcome.jsp页面,该页面使用相对路径跳转到上一级中的index.jsp页面
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<a href="../index.jsp">back of</a>
</body>
</html>
- 编写一个TargetServelet.java程序,改程序会跳转到good/welcome.jsp页面中
package mao.shu.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/TargetServlet")
public class TargetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getRequestDispatcher("/good/welcome.jsp").forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
- 在index.jsp中添加一个超链接,该超链接跳转执行TargetServlet
<a href="good/welcome.jsp">go to</a><br/>
<a href="TargetServlet">go to Servlet</a>
-
运行Tomcat,将Chiken项目发布到Tomcat中,
-
发现访问index.jsp的时候,两个链接都能够跳转到/good/welcome.jsp中
- 但是如果是通过TargetServlet跳转到welcom.jsp中,再点击back of 无法跳转到 index.jsp页面中
- 这是因为项目运行时,*.class文件都在WEB-IFO/classes中,而welcom.jsp使用的是相对路径"…/index.jsp","…/"表示返回上一层目录,而编译后的TargetServlet 所在的目录返回上一层目录后并没有 "/good/welcome.jsp"目录,所以也就会出现 404 错误.
自动化构建和构建环节
-
构建过程中的各个环节
- 清理:将以前编译得到的就得class字节码文件删除,为下一次编译做准备
- 编译:将java源程序编译成class字节码文件
- 测试:自动测试,自动调用junit程序
- 报告:测试程序执行的结果
- 打包:动态web工程打war包,java工程打jar包
- 安装:Maven特定的概念----将打包得到的文件复制到""仓库"中的指定位置
- 部署将动态web工程生成的war包复制到Servlet容器的指定目录下,使其可以运行.
-
自动化构建
-
在IDE工具还不是很智能的年底啊,以上的工作都需要程序员自己手工完成,这就导致了大量的重复工作,而Maven将这些步骤都封装了起来,不再需要程序员手工处理了,这也就大大的提高了工作效率和生产速度.
部署Maven核心程序
- 安装maven核心程序
- 检查JAVA_HOME环境变量,maven也是java编写的程序,所以运行是也需要java的虚拟机
2. 解压Maven核心程序建议解压到一个非中文没有空格的目录下.
- 配置Maven 相关的环境变量
1. 配置MAVEN_HOME或者是M2_HOME(以前Maven的版本配置的变量为M2_HOME,为了向下兼容低版本,所以可以配置为M2_HOME,而且配置M2_HOME可以防止一些奇怪的错误)
- 添加M2_HOME 环境变量(不包含bin目录)
- 添加PATH的环境变量(包含bin目录)
- 在CMD中输入 “mvn -v”,测试环境是否配置正确
约定的目录结构说明
-
maven的核心概念
- 约定的目录结构
- pom
- 坐标
- 仓库
- 生命周期/插件/目标
- 继承
- 聚合
-
创建第一个Maven工程
- 创建约定的目录结构
- 根目录:工程名
- src:源码
- pom.xml文件:Maven工程的核心配置文件
- main目录:存放主程序
- test目录:存放测试程序
- java目录:存放java源文件
- resource目录:存放框架配置文件或其他工具的配置文件
- 创建约定的目录结构
- 为什么要遵守约定的目录结构?
- maven要负责我们这个项目的自动化构建:以编译为例,maven要想进行自动编译,那么他要知道java源文件保存在哪里.
- 如果我们自定义的东西要想让框架或工具知道,有两种方式
- 以配置的方式明确告诉框架
- 遵守框架内部已存在的约定.
在开发中本着能用约定解决的问题就不用配置解决,能用配置解决的就不去编写代码
- 约定>配置>编码
第一个Maven工程目录结构和文件内容
- 在E盘中创建一个Hello文件夹,Hello表示为工程名称
- 在Hello目录下创建src目录和一个pom.xml文件夹
- pom.xml文件中的内容如下,其中
- <project>标签为pom.xml文件的根标签
- modelVersion是maven固定的写法格式
- <groupId>,<artifactId>,<version>这三个标签表示项目当前的坐标
- <dependencies>标签中存放项目开发包的依赖关系
<?xml version="1.0" ?>
<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>
<groupId>mao.shu</groupId>
<artifactId>Hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Hello</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
- 进入到src目录中,分别创建一个main和一个test目录
- 进入到main目录中,创建一个java目录 和一个resources目录
- 回到 test目录中,同样创建 一个java和一个resource目录
- 接着回到main目录中,在main/java下创建一个程序类,包名就是目录名称,例如
- mao.shu.Hello.java
- Hello.java文件的内容为
package mao.shu;
public class Hello {
public String sayHello(String name){
return "Hello "+name+"!";
}
}
- 接着在test/java目录下,创建一个测试程序,测试程序的包名于被测试程序的包名称相同
- 例如 mao.shu.HelloTest.java
- HelloTest.java内容如下
package mao.shu;
import org.junit.Test;
import static junit.framework.Assert.*;
public class HelloTest {
@Test
public void testHello(){
Hello hello = new Hello();
String results = hello.sayHello("litingwei");
assertEquals("Hello litingwei!",results);
}
}
联网问题
注意:执行于构建过程相关的maven命令,必须进入pom.xml目录
- 例如:编译,测试,打包
-
maven常用的命令
- mvn clean:清理
- mvn compile:编译
- mvn test-compile:编译测试程序
- mvn test:执行测试
- mvn package:打包
-
Maven的核心程序中仅仅定义了抽象的生命周期,但是具体的工作必须由特定插件来完成,而插件本身并不在Maven的核心程序中
-
当我们执行Maven命令是需要用到某些插件时,Maven核心程序首先到本地仓库中查找.
-
本地仓库的目录位置:系统当前用户的家目录/.m2/repository
-
Maven核心程序如果在本地中找不到需要的插件,那么会自动到中央仓库中下载.
-
如果此时无法连接外网,则构建失败.
-
修改默认本地仓库位置,可Maven核心程序到事先准备好的目录下查找插件
- 查找maven的安装目录/conf/settings.xml文件
- 在setting.xml文件中找到localrepsitory标签.
- 将localrepository标签取消注释,
- 将localrepository标签中的内容修改为自定义的本地仓库目录
-
修改maven本地仓库地址
- 使用cmd进入到创建好的Hello项目中
- 使用mvn compile命令编译项目
- 使用 mvn package 命令打包项目
- 打包成功之后会在项目的target目录下得到项目打包好的jar文件
几个常用的Maven命令
- 当我们执行 mvn compile 命令进行项目编译时,会在项目的target目录下得到 classes 目录
- 该目录会保存项目源代码*.java文件编译后得到的 *.class文件
- 当我们执行 mvn test 命令的时候,会在项目中得到如下结果
- surefire-reports:为执行测试程序的结果
- test-classes:为测试程序源代码编译后的字节码文件
- 当我们执行 mvn package 命令的时候 ,会自动执行程序源代码和测试程序源代码的编译,并执行测试程序,并且将项目的字节码文件打包为*.jar文件
- 当我们执行 mvn clean 命令的时候会清除掉 target 目录下的所有内容
POM
Project Object Model:项目对象模型。将 Java 工程的相关信息封装为对象作为便于操作和管理的模型。 Maven 工程的核心配置。可以说学习 Maven 就是学习 pom.xml 文件中的配置
- 这个概念于DOM(Document Object Model)文档对象模型概念相似
- pom.xml对于Maven工程是核心配置文件,于构建过程相关的一切配置都在这个文件进行配置.
- 重要程度相当于web.xml对于动态Web工程的重要性.
坐标
- 坐标实际上是来自数学中的概念.
在平面上,使用x,y两个向量可以唯一的定位平面中的任何一个点
在空间中,使用x,y,z三个向量可以唯一的定位空间中的任何一个点
- maven的坐标
- maven中使用sange向量在仓库中唯一定位一个Maven工程
- groupId:公司或组织域名倒序+项目名称
<groupId>mao.shu.Hello</groupId>
- artifactId:模块名称
<artifactId>addUser</artifactId>
- version:版本
<version>1.0</version>
Maven项目坐标于仓库中的路径的对应关系
此时电脑中maven的本地仓库为:E:\DevRepository\MavenRepository
- 如果一个项目的坐标如下
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.5.RELEASE</version>
- 那么这个项目的jar包所在位置为
- 仓库目录+groupId+artifactiId+version
groupId中的"."小数点需要换位目录分隔符 “”,而artifactiId中的小数点不需要更换
- 所以此时该项的jar的目录就位于:
- E:\DevRepository\MavenRepository\org\springframework\spring-aop\4.2.5.RELEASE
jar包名称由 artifactId +"-" + version + “.jar” 组成
仓库
- 仓库的分类
- 本地仓库
- 远程仓库
- 私服:搭建在据预防环境中:为局域网范围内所有工程服务
- 中央仓库:假设在Internet上,为全世界所有的Maven工程服务.
- 中央仓库镜像:为分担中央仓库的流量,提升用户访问速度.
- 仓库中保存的内容
- Maven自身所需要的插件
- 第三方框架或工具的jiar包
- 我们自己开发的Maven工程.
第二个Maven工程目录结构和文件内容
- 第二个Maven工程项目的结构于第一个maven的结构相同
\HelloFriend
\src
\mian
\java
\mao
\shu
\HelloFriend.java
\resources
\test
\java
\mao
\shu
\TestHelloFriend.java
\resources
\pom.xml
- 编写HelloFriend.java中的内容
- 包名如果自定义的话,需要更换
package mao.shu;
import mao.shu.Hello;
public class HelloFriend {
public String sayHelloToFriend(String name){
Hello hello = new Hello();
String str = hello.sayHello(name)+" I am "+this.getMyName();
System.out.println(str);
return str;
}
public String getMyName(){
return "John";
}
}
- 编写TesetFriendHello.java
package mao.shu;
import static junit.framework.Assert.assertEquals;
import org.junit.Test;
import mao.shu.Hello;
public class HelloFriendTest {
@Test
public void testHelloFriend(){
HelloFriend helloFriend = new HelloFriend();
String results = helloFriend.sayHelloToFriend("litingwei");
assertEquals("Hello litingwei! I am John",results);
}
}
- HelloFriend项目中的pom.xml文件为
第二个dependency 标签中要加入Hello工程项目的坐标,这样在HelloFriend项目中才可以使用Hello项目的程序类
<?xml version="1.0" ?>
<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>
<groupId>mao.shu</groupId>
<artifactId>HelloFriend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>HelloFriend</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mao.shu</groupId>
<artifactId>Hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
依赖的基本操作
- 使用命令行进入到 HelloFriend项目中,进行编译
- 此时编译出现了错误,提示无法找到mao.shu.Hello这个工程,这是因为此时的本地仓库中并没有mao.shu.Hello这个工程的jia包,
- Maven解析依赖信息时会到本地仓库查找本地依赖的jar包
- 对于我们自己开发的Maven工程,使用install命令安装后就可以进入仓库
- 进入到Hello工程中,执行以下命令,将工程引入到仓库中
mvn install
- 再次回到 HelloFriend 项目中, 执行编译命令
mvn compile
- 如果出现 Build Success 就表示构建成功
依赖的范围初步介绍
-
以来的范围常用的取值
- compile:
- 对主程序是否有效:有效
- 对测试程序是否有效:有效
- 是否参与打包:参与
- test
- 对主程序是否有效:无效
- 对测试程序是否有效:有效
- 是否参与打包:不参与
- 典型例子:junit
- provided
- 对主程序是否有效:有效
- 对测试程序是否有效:有效
- 是否参与打包:不参与
- 典型例子:servlet-api
- compile:
-
compile范围
- Test依赖范围
- provided范围
生命周期&插件&目标
各个构建环节执行的顺序:不能打乱顺序,必须按照既定的正确顺序执行.
Maven的核心程序定义了抽象的生命周期,生命周期中各个阶段的具体的任务是有插件完成的
Maven核心程序为了更好的实现自动化构建,按照这样的特点执行生命周期的各个阶段:无论现在要执行生命周期的哪一个阶段,都是从生命周期最初的位置开始执行.
- Maven有三套相互独立的生命周期,分别是
①Clean Lifecycle在进行真正的构建之前进行一些清理工作。
②Default Lifecycle构建的核心部分,编译,测试,打包,安装,部署等等。
③Site Lifecycle生成项目报告,站点,发布站点。
它们是相互独立的,你可以仅仅调用clean来清理工作目录,仅仅调用site来生成站点。当然你也可以直接运行mvn clean install site 运行所有这三套生命周期
- Clean生命周期Clean生命周期一共包含了三个阶段:
①pre-clean 执行一些需要在clean之前完成的工作
②clean 移除所有上一次构建生成的文件
③post-clean 执行一些需要在clean之后立刻
- Site生命周期
①pre-site 执行一些需要在生成站点文档之前完成的工作
②site 生成项目的站点文档
③post-site 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
④site-deploy 将生成的站点文档部署到特定的服务器上这里经常用到的是site阶段和site-deploy阶段,用以生成和发布Maven站点,这可是Maven相当强大的功能,Manager比较喜欢,文档及统计数据自动生成,很好看。
- Default生命周期
Default生命周期是Maven生命周期中最重要的一个,绝大部分工作都发生在这个生命周期中。这里,只解释一些比较重要和常用的阶段:
- validate
- generate-sources
- process-sources`
- generate-resources
- process-resources 复制并处理资源文件,至目标目录,准备打包。
- compile 编译项目的源代码。
- process-classes
- generate-test-sources
- process-test-sources
- generate-test-resources
- process-test-resources 复制并处理资源文件,至目标测试目录。
- test-compile 编译测试源代码。
- process-test-classestest 使用合适的单元测试框架运行测试。这些测试代码不会被打包或部署。
- prepare-package
- package 接受编译好的代码,打包成可发布的格式,如JAR。
- pre-integration-test
- integration-test
- post-integration-test
- verify
- install 将包安装至本地仓库,以让其它项目依赖。
- deploy将最终的包复制到远程的仓库,以让其它开发人员与项目共享或部署到服务器上运行。
- 示例:执行编译的命令
mvn compile
- compile命令一共执行了两个阶段
- resources
- compile
- 执行测试命令
mvn test
- test命令一共执行6个阶段
- resources
- compile
- testResources
- testCompile
- test
- 打印测试报告
- 执行打包命令
mvn package
- 改命令一共执行了6个阶段
- resources
- compile
- testResources
- testCompile
- test
- 打印测试报告
- 可以发现的是 无论从default生命周期的哪一个阶段开始,都会从default生命周期的开始"resources"阶段开始执行.
这就是Maven为什么能够自动执行构建过程的各个环节的原因。此外,Maven的插件机制是完全依赖Maven的生命周期的
插件和目标
- 生命周期的各个阶段仅仅定义了要执行的任务是什么,具体的任务是有对应的插件完成的
- 各个阶段的插件和目标是对应的
- Maven的生命周期与插件目标相互绑定,以完成某个具体的构建任务。
生命周期阶段 | 插件目标 | 插件 |
---|---|---|
compile | compile | maven-compiler-plugin |
testCompile | testCompile | maven-compiler-plugin |
Eclipse的Maven插件设置
eclipse比较高的版本中已经内置了Maven插件,只需要配置两个选项即可
- installation:指定Maven核心程序默认位置,不建议使用插件自带的Maven程序,建议使用自己解压的Maven核心程序
- user settings:指定conf/settings.xml文件的位置.目的是为了找到本地仓库的位置
- 在Eclipse中选择 [windows]—>[preferences]
-
选择[Maven]—>[installation]
-
在右边窗口选择[add]
-
点击Directory 选择本地的maven安装跟路径
-
在新增的maven左边打上勾,然后选择 apply 应用
- 接着设置 user settings
- global settings 为全局设置:该电脑的所有用户都使用这个设置
- User settings 为用户设置:只对当前用户设置,当前用户设置会覆盖掉全局用户设置
- 选择 browse 选择本地安装的 Maven/conf/settings.xml文件
- local Repository 会根据你settings.xml文件中的配置而改变位置
- 然后点击 apply 应用会提示更新用户设置,点击确定即可
创建Maven版java项目
-
此时电脑中安装的Maven程序为"maven-3.2.2"版本,那这个版本最高支持JDK1.7,如果JDK是更高的版本,可能识别不了,所以如果要使用更高版本的JDK,需要区Maven官网下载更高版本的Maven.
-
在创建Maven项目之前,最好先修改下Maven安装目录下的 settings.xml文件,设置JDK指定版本.
-
否则eclipse创建的maven项目默认会是JDK1.5的版本
-
打开Maven/conf/settings.xml文件,找到 <profiles> 标签
-
<profiles>标签中有注释说明,该如何使用该标签指定JDK版本
-
如果要指定JDK版本为1.7则在<profiles>标签中添加以下内容
<profile>
<id>jdk-1.7</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.7</jdk>
</activation>
<properties>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<maven.compiler.compilerVersion>1.7</maven.compiler.compilerVersion>
</properties>
</profile>
- 接着打开Eclipse中 选择 [File]—>[new]–>[Outher]
- 然后搜索 maven
- 选择创建 Maven project
- 这次选择将 [create a simple project(skip archetype selection)] 的"√" 打上勾 ,表示跳过选择maven创建项目插件
这是因为如果创建的只是一个普通的java项目,使用这个选项的目录会更加完整,而如果选择 [maven—quickstart] 的插件创建简单java项目的目录反而不完整
-
接着填写Group Id :公司的域名(没有可以随意取)
-
Artifact Id :产品的名称(随意取)
-
点击finish 完成创建,之后会发现创建出来的项目默认的jdk环境就是1.7
在Eclipse中执行Maven命令
- 在Eclipse中创建好的Maven项目中鼠标选择右键,—>[Run As]
- 这里会列出一下常用的Maven命令,如果要执行其他Maven命令可以选择[Maven build]
- 然后再[Goals]中输入你要执行的命令
- 然后点击[Run] 按钮就会执行maven命令了
在Eclipse中创建Maven的Web工程
-
选择[file]–>[new]—>[Maven Project]
-
此时同样选择简单创建
- 但是此时[packing] 选项 要选择 war 类型,Eclipse依靠这个来区分web工程和普通java工程
-
但此时创建出来的web项目还没有 WEB-INF 目录 和web.xml文件,需要设置一些配置
-
选择项目右键 选择—>[properties]
-
选择 project Facets
- 请按照如下步骤进行
- 现将 Dynamic web module 前面的 “√” 去掉
- 点击 apply
- 选择你要的web module 版本,而后前面选上 “√”
- 接着会出现 “further configuration available” 的超链接, 点击这个超链接
- 修改 content directory 目录为 “src/main/webapp” 用这个目录代替原先的 “WebContent”,并且勾选"create web.xml deployment discriptor",表示创建 web.xml文件.
- 点击 “ok”–>“apply” 完成 web工程的创建
- 最后得到完整的web工程目录结构
通过servlet-api进一步理解依赖范围
- 在新建好的web项目中添加一个index.jsp文件,会发现以下的错误
- 这个错误告诉我们无法找到HttpServlet这个类,这是因为我们没有导入 servlet-api.jar这个开发包
- 在Maven中要导入开发包只需要在pom.xml文件中添加所需开发包的坐标即可
- 修改pom.xml文件,在pom.xml文件中的<dependencies>标签中添加以下的内容,这表示的是servlet-api.jar包的坐标,添加之后,maven会自动在仓库中寻找,如果仓库中没有回去中央仓库下载
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
- 为了观察"provided"范围和"test"范围以及"compile"范围的jar包的区别,再添加一个junit的jar包坐标和一个spring-context包的坐标
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.0.4.RELEASE</version>
</dependency>
- 接着将web项目进行打包,在得到的war文件中,用压缩文件打开这个war文件
- 在WEB-INF/lib目录下就会看到打包好的开发包文件
- 从中可以看出,servlet-api没有被部署到项目之中,这是因为,servlet-api的范围是 provided 他会有Tomcat运行时提供,所以部署的时候不会被打包.
- 而junit的开发包也没有被打包进来,这是因为 junit的开发包范围是"test" 只有在测试项目的时候有效,而不参与部署
通过servlet-api体验jar包之间的冲突
- 现在项目中导入jsp-api.jar包的坐标,此时的jar包范围为provided,表示不会参与部署,这样没有什么问题,但是如果将scope标签内容改为compile,那么这个jar包就会与Tomcat中自带的jsp-api.jar包发生冲突
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
-
这是因为在Tomcat中已经自带了jsp-api的jar包,而如果将添加的jar包添加到项目部署,那么在项目运行的时候,就会出现jar包冲突,系统不知道要找哪一个jsp-api.jar包
-
所以在配置依赖关系的时候,最好不要随意修改jar包的作用范围
导入Maven工程
- 在之前手工创建过的两个maven项目"Hello"和"HelloFriend",由于这两个手工创建的,所以文件夹中并没有".settings"文件夹,无法被eclipse所识别,所以需要将这两个目录拷贝到Eclipse的工作目录中.
- 随后打开Eclipse,选择[File]–>[import]
- 选择导入Existing Maven Projects(已存在的Maven项目)
- 选择eclipse的工作区,选择带有pom.xml文件的Maven项目
- 而后点击finish 完成
- 而后这两个项目就会出现在工作目录之中
- 并且Eclipse会自动将这项目中进行初始化,加入.settings文件夹
- 如果本身项目中带有 .settings文件夹,则表示已经是Eclipse的项目,所以可以直接用普通项目的导入方式导入即可,不需要单独使用Maven项目导入
第三个Maven工程
- 在Eclipse中创建第三个maven工程 MakeFriends
-
添加两个 java程序类(mao.shu为类所在的包名称,可以自定义)
- src/main/java/mao.shu.MakeFriends
- 测试类:src/test/java/mao.shu.MakeFriendsTest
-
MakeFriends类内容如下,因为该类需要 HelloFriend 项目的支持,现在还没有设置依赖关系,所以会出现错误
package mao.shu;
public class MakeFriends {
public String makeFriends(String name){
HelloFriend friend = new HelloFriend();
friend.sayHelloToFriend("litingwei");
String str = "Hey,"+friend.getMyName()+" make a friend please.";
System.out.println(str);
return str;
}
}
- MakeFriendsTest 类中的内容,该类需要junit开发包的支持,现在还未导入junit开发包,所以可能会出现错误
package mao.shu;
import static junit.framework.Assert.assertEquals;
import org.junit.Test;
public class MakeFriendsTest {
@Test
public void testMakeFriends(){
MakeFriends makeFriend = new MakeFriends();
String str = makeFriend.makeFriends("litingwei");
assertEquals("Hey,John make a friend please.",str);
}
}
- 在MakeFriends 项目中的pom.xml文件,添加依赖关系
<dependencies>
<dependency>
<groupId>mao.shu</groupId>
<artifactId>HelloFriend</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
- 因为此时HelloFriend 项目还未被导入到仓库中,所以如果此时对MakeFriends 项目进行编译会出现 编译错误,无法早到 HelloFriend 类.
- 但是在添加过依赖关系之后会发现Eclipse中不会出现错误提示,这是因为,此时两个项目都在Eclipse的工作空间中,所以Eclipse可以识别出已存在的项目,但是在真正打包编译的时候,一定要确保项目都已存在仓库之中了
依赖的传递性
-
现在的工作区中有这样三个项目
- Hello
- HelloFriends
- MakeFriends
-
他们之间的此时的关系为
- 那么此时在Hello项目中添加一个开发包的依赖关系
- 在Hello项目中添加一个spring开发包的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
- 此时观察HelloFriend 项目中的Maven Repository
- 查看 MakeFriends 项目中的 Maven Repository
-
可以发现,虽然没有在HelloFriend和MakeFirends项目中添加 spring的开发包依赖,但是会自动添加该开发包的依赖.
-
这是因为他们的 父项目 Hello中有spring开发包的依赖,所以子项目中会自动传递这个依赖
-
依赖传递的好处为:不必在每一个模块工程中重复声明.
-
非compile范围的依赖不能传递,所以在各个模块中如果需要需要重复声明
-
Eclipse中可以查看当前项目的依赖情况,打开项目的pom.xml文件
-
可以看到,最外层的HelloFriend 项目是属于直接依赖,里面的Hello 和spring的开发包是属于间接依赖.
依赖的排除
当一个项目中从父项目中传递过来了一个开发包,但是此时该项目不需要使用这个传递过来的jar包,那么这个时候就需要进行依赖包的排除
- 例如:此时MakeFriends 项目中的依赖关系为如下的关系
- 那么如果此时不希望在MakeFriends项目中依赖spring-context 开发包
- 从关系图中可以看到,MakeFriends项目中的spring开发包的依赖传递来自于HelloFriend 开发包,那么我们就需要在配置HelloFriend 依赖关系的<dependcy> 标签中,配置以下的信息
- groupId:输入要排除的开发包的groupId
- artifactId:输入要排除的开发包的artifactId
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
- 在Eclipse中查看一个开发包的坐标可以使用以下的方式
- 保存pom.xml文件之后, 再次查看MakeFriends 项目的依赖关系
- 此时MakeFriends项目中就不会有spring相关的依赖包了,
- 如果MakeFriends项目还有被其他项目所依赖,那么其他项目此时也无法得到spring开发包的依赖了
依赖原则说明
依赖的原则是为了解决模块工程之间的jar包冲突问题
- maven中依赖有两个原则
- 就近原则:使用路径最短的依赖包
- 先声明者优先,当两个依赖包来自两个路径相同距离相同的地方,那么maven会以最先使用dependency标签声明出的那个开发包
- 就近原则场景
- 一个MakeFriend 项目依赖了一个HelloFriend项目,而HelloFriend项目有依赖了 Hello项目.
- 而此时的Hello项目依赖了一个 spring-context5.0版本的jar包
- 但是HelloFriend 项目依赖了一个 spring-context4.0的jar包
- 那么此时就近原则 MakeFriend项目会使用 距离他路径比较近的 HelloFriend项目中的 spring-context4.0版本的jar包
- 路径相同,先声明者优先
统一管理依赖版本号
- 如果此时项目中依赖了一系列spring的开发jar包,
- 如果需要统一升级为4.1.1该怎么办?如果手动修改每个开发包的版本号,可能更改错误,而且不好管理
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
- 于是Maven使用了一种统一管理版本好的方式
- 在pom.xml文件中使用<properties>定义开发包的版本号
<properties>
<spring.version>4.1.1.RELEASE</spring.version>
</properties>
- 而在需要统一版本的位置,使用 ${} 的方式引用声明的版本号
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
- 修改之后,项目中的jar包就会被统一的管理
- 除了声明依赖版本号之外 <properties>标签,只要是需要统一声明后再引用的场合都可以使用
继承
-
此时有三个maven项目 :
- Hello:使用4.0版本的junit
- HelloFriend:使用4.0版本的junit
- MakeFriends:使用4.9版本的junit
-
由于junit是test范围的开发包,所以无法依赖不会被传递,那么就会分散在各个项目模块中,这就可能导致版本不统一的问题.
解决的思路:将junit一来版本统一提到"父"版本中,在子工程中不指定版本.以父工程中统一设定版本为准,同时也便于修改.
- 创建一个Maven工程作为父工程.打包的方式为pom.
- 父工程的坐标
<groupId>mao.shu</groupId>
<artifactId>Parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
- 在子工程中对父工程的引用
<parent>
<!-- 父项目的坐标 -->
<groupId>mao.shu</groupId>
<artifactId>Parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 以当前项目为准的 父项目所在的相对路径-->
<relativePath>../Parent/pom.xml</relativePath>
</parent>
- 将子工程的坐标于父工程坐标中重复的内容删除
子项目的坐标为
<groupId>mao.shu</groupId> <artifactId>Hello</artifactId> <version>0.0.1-SNAPSHOT</version>
而父项目的坐标为:
<groupId>mao.shu</groupId> <artifactId>Parent</artifactId> <version>0.0.1-SNAPSHOT</version>
此时子项目和父项目的groupId和version坐标是一样的,所以可以删除掉重复的坐标
4. 在父工程中统一声明junit的依赖
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
- 在子工程中删除junit的版本
- 此时只需要修改 父项目的 junit 版本,其他子项目junit依赖版本也会跟着修改
依赖原则测试
-
就近原则测试
-
建立三个项目 关系如下
- 查看MakeFriends项目中 依赖的是哪个版本的log4j的开发包
- 此时MakeFriends项目使用的是log4j.2.0版本
- 测试相同距离的两个项目依赖传递
- 创建三个项目,此时的关系如下
- 此时的OverProject 项目中的pom.xml文件中对 HelloFriend项目和 对 MakeFriends项目的依赖位置如下
- 此时是HelloFriend 项目的坐标写在了前面
- 所以此时 OverProject 项目中使用的log4j的jar包为来自HelloFriend项目中依赖传递而来的
- 如果此时 OverProject 中的pom.xml文件 的依赖关系如下
- 此时的MakeFriends项目的坐标被写在了前面
- 所以此时OverProject 项目中使用的log4j开发包是来自MakeFriend项目中的依赖传递
聚合
- 配置继承之后执行安装命令时要先安装父工程,否则会出现安装 的错误,那么如果每个都需要一个一个的安装,会非常的麻烦.
聚合的作用就是一键安装各个模块工程
- 一般情况下会在父工程中定义聚合
- 在 Parent项目中定义聚合
<!-- 定义聚合-->
<modules>
<!-- 描述模块项目的 相对位置-->
<module>../Hello</module>
<module>../HelloFriend</module>
<module>../MakeFriends</module>
</modules>
- 在定义聚合工程中进行maven安装命令
- 此时maven会根据项目的继承关系,依次安装模块项目
Web工程的自动部署
- maven中提供有这样一个命令"deploy" ,使用该命令可以实现web项目的自动化部署.
- 在没有自动化部署的时候,如果要运行一个动态web项目.操作的步骤为:
- 将项目打成 war 包,
- 如果使用的是tomcat容器,则要将war包放到 Tomcat_HOME/webapps 目录下 ,然后开启Tomcat服务
-
以上的步骤可以使用Maven的一个插件来自动完成
-
在项目中的pom.xml文件中配置如下的插件
<build>
<finalName>AtguiguWeb</finalName>
<plugins>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.2.3</version>
<!-- 针对插件进行配置-->
<configuration>
<!-- 配置当前系统中容器的位置-->
<container>
<containerId>tomcat6x</containerId>
<home>D:\DevInstall\apache-tomcat-6.0.39</home>
</container>
<configuration>
<type>existing</type>
<home>D:\DevInstall\apache-tomcat-6.0.39</home>
<!-- 如果Tomcat端口为默认值8080则不必设置该属性 -->
<properties>
<cargo.servlet.port>8989</cargo.servlet.port>
</properties>
</configuration>
</configuration>
<!-- 配置插件在什么情况下执行-->
<executions>
<execution>
<id>cargo-run</id>
<!-- 生命周期的阶段-->
<phase>install</phase>
<goals>
<!-- 插件目标-->
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
- 而后执行"mvn deploy" 命令,如果在Eclipse中执行改名了不需要添加"mvn"字样
查找依赖信息的网站
-
查找Maven依赖信息的网址为:https://mvnrepository.com/
-
登录该网址,通过搜索框搜索你想要的开发包,大部分主流的开发包都能够在这里找到.
- 例如你要查找 spring类型的开发包
- 在搜索框输入"spring"单词,网页会将所有关于spring相关的开发包都列出来
- 点开其中一个开发包链接,例如 Spring Context
- 网页会将该开发包所有的版本都列出来,选取其中一个版本
-
网页中会出现Maven工具的依赖坐标,并且还可以选择其他jar包管理工具的引用方式
-
复制maven的开发包坐标,将其复制到项目中的pom.xml文件中
-
当保存pom.xml文件之后,maven会自动到仓库中下载开发包,并且将于这个开发包所依赖的其他开发包都导入