本节内容:
- Maven的简介
- Maven的安装配置
- 入门程序
- 项目构建
- 依赖管理
一、Maven的简介
1. 什么是maven
是apache下的一个开源项目,是纯java开发,并且只是用来管理java项目的。它是要给项目管理工具,使用maven对java项目进行构建、依赖管理。
2. 什么是项目构建
项目构建是一个项目从编写源代码到编译、测试、运行、打包、部署、运行的过程。
(1)传统项目的构建过程
- 在Eclipse等IDE中创建一个java web工程
- 在工程中编写源代码及配置文件等
- 对源代码进行编译,java文件编译成class文件
- 执行Junit单元测试
- 将工程打成war包部署至tomcat或其他中间件中运行
(2)maven项目构建过程
maven将项目构建的过程进行标准化,每个阶段使用一个命令完成,下图展示了构建过程中的一些阶段:
上图中部分阶段对应命令如下:
- 清理阶段对应maven的命令是clean,清理已经输出的class文件
- 编译阶段对应maven的命令是compile,将java代码编译成class文件
- 打包阶段对应maven的命令是package,java工程可以打成jar包,web工程可以打成war包
运行一个maven工程(web工程)需要一个命令:tomcat:run
比如,有个基于maven管理的java项目:maven-helloworld,里面存放的都是java源代码。一条命令就可以跑起来了(即使你的电脑没有安装IDE工具,没有安装tomcat。maven可以去仓库里下载编译插件、tomcat插件):
3. maven的好处
- 一个命令完成构建、运行,方便便捷
- 一键构建,见上面的示例
- 应用于大型项目,可以提高效率
- 举个例子,比如京东商城,分为用户管理、订单管理、支付管理等等。对于我们看到的是同一个项目,但是在他们开发的时候是分成不同的项目来做的。一个开发人员只会属于一个项目,别的都接触不到,毕竟大公司,分工细。
- 项目和项目之间是没有关系的,但是订单管理和支付管理需要用到用户的信息,如何产生关联呢?把用户管理这个项目打成一个jar包,扔到订单管理这个项目里。
- 假如这几个项目放在同一个项目里,那么部署用户管理,订单管理和支付管理也是需要编译的,做用户管理的人只关注用户管理,还要编译订单管理和支付管理,浪费时间。如果以jar包的形式存在,就不需要浪费时间了,jar里面都是class文件。
- 这就是maven里的分模块开发。
- 补充:互联网项目和传统项目的分模块开发是不一样的。互联网项目按业务分模块开发;传统项目按层分:entity、dao、service、web
- maven项目体积小
对于上面的“maven项目体积小”,来做个对比:
普通的传统项目:
Maven项目:
maven项目为什么这么小?因为没有jar包。 需要jar吗?肯定需要。jar包没有存在于maven项目里面,jar包存在于哪?
比如,下面是本地的一个maven仓库。这个找的过程,是maven中的配置文件中写好了,不是我们自己找的。
当然,随着这个本地仓库越来越大,找起来也是需要一定的时间。maven仓库也有索引的概念,索引的目的就是提高查询速度。这样项目在本地仓库找jar包会非常快捷。
为什么要本地maven仓库?
本地可能有多个项目,比如项目一和项目二都用的ssh框架,那么它们用的jar就都是一样的。如果不用maven仓库,这些jar包得存在于两个项目里。有个本地仓库,就不需要在每个项目里拷贝一大堆jar包了。
4. 依赖管理
(1)什么是依赖管理
什么是依赖?一个java项目可能要使用一些第三方的jar包才可以运行,那么我们说这个java项目依赖了这些第三方的jar包。
比如一个crm系统,它的架构是SSH框架,该crm项目依赖SSH框架,具体它依赖的是Hibernate、Spring、Struts2。
什么是依赖管理?就是对项目所有依赖的jar进行规范化管理。
(2)传统项目的依赖管理
传统的项目工程要管理所依赖的jar包完全靠人工进行,程序员从网上下载jar包添加到项目工程中,如下图,程序员手工将Hibernate、Struts2、Spring的jar添加到工程的 WEB-INF/lib 目录下。
手工拷贝jar包添加到工程中的问题有:
- 没有对jar包的版本统一管理,容易导致版本冲突
- 从网上找jar包非常不方便,有些jar找不到
- jar包添加到工程中导致工程过大
(3)maven项目的依赖管理
maven项目管理依赖的jar不需要手动向工程里添加jar包,只需要在 pom.xml(maven工程的配置文件)添加jar包的坐标,自动从maven仓库中下载jar包、运行,如下图:
使用maven依赖管理添加jar的好处:
- 通过pom.xml文件对jar包的版本进行统一管理,可避免版本冲突
- maven团队维护了一个非常全的maven仓库,里面包括了的当前使用的jar包,maven工程可以自动从maven仓库下载jar包,非常方便
二、Maven的安装配置
1. 下载安装
(1)下载
下载地址:http://maven.apache.org/download.cgi
(2)解压
解压后目录如下:
- bin目录:mvn.bat/mvn.sh(以run方式运行项目)、mvDebug.bat/mvnDebug.sh(以debug方式运行项目)
- boot目录:maven运行需要类加载器
- conf目录:settings.xml是整个maven工具核心配置文件
- lib目录:maven运行依赖的jar包
2. maven环境变量配置
需要安装配置JDK7+。
以windows为例:
在系统变量添加环境变量的名称:MAVEN_HOME。变量值:就是maven软件解压的目录,比如F:\class32\apache-maven-3.3.9
将 %MAVEN_HOME%/bin 加入到环境变量Path
验证maven是否配置成功:
打开dos窗口 输入: mvn –v
3. maven仓库介绍及配置
maven的工作需要从仓库下载一些jar包,如下图所示,本地项目A和项目B等都会通过maven软件从远程仓库(可以理解为互联网上的仓库)下载jar包并存于本地仓库,本地仓库就是本地文件夹。当第二次需要此jar包时则不再需要从远程仓库下载,因为本地仓库已经存在了,可以将本地仓库理解为缓存,有了本地仓库就不用每次从远程仓库下载了。
- 本地仓库:用来存储从远程仓库或中央仓库下载的插件和jar包,项目使用一些插件或jar包,优先从本地仓库查找。--自己维护
- 默认本地仓库位置在${user.dir}/.m2/repository,下载的jar包都会放在这个目录。${user.dir}表示windows用户目录。
- 配置本地仓库只需要修改 ${MAVEN_HOME}/conf/settings.xml 文件就可以,如下图
- 远程仓库(私服):如果需要的插件或者jar包本地仓库没有,默认去远程仓库下载。远程仓库可以在互联网内,也可以在局域网内。 --公司维护
- 中央仓库:在maven软件中内置了一个远程仓库地址 http://repo1.maven.org/maven2,它是中央仓库,服务于整个互联网,它由Maven团队维护,里面存储了非常全的jar包,它包含了世界上大部分流行的开源项目构件,大概两个亿个jar包。
三种仓库的关系如下:
三、入门程序
(1)入门程序(以Mac上IDEA为例演示)
安装maven,配置好maven环境变量,配置 ${MAVEN_HOME}/conf/settings.xml 中的本地仓库位置。
打开IntellJ IDEA,先配置好JDK和Maven。点击File—>New—>Project,左侧菜单选择“Maven”。
填写GroupID和ArtifactID。
- GroupID是项目组织唯一的标识符,实际对应JAVA的包的结构,是main目录里java的目录结构。
- ArtifactID就是项目的唯一的标识符,实际对应项目的名称,就是项目根目录的名称。
- 一般GroupID就是填com.leafive.test这样子。
groupid和artifactId被统称为“坐标”是为了保证项目唯一性而提出的,如果你要把你项目弄到maven本地仓库去,你想要找到你的项目就必须根据这两个id去查找。
groupId一般分为多个段,这里我只说两段,第一段为域,第二段为公司名称。域又分为org、com、cn等等许多,其中org为非营利组织,com为商业组织。举个apache公司的tomcat项目例子:这个项目的groupId是org.apache,它的域是org(因为tomcat是非营利项目),公司名称是apache,artigactId是tomcat。
选择本地安装的maven软件,本地仓库等信息。
输入项目名称。
这就创建了一个基于Maven的web项目了。
创建Java程序目录。点击工具栏的“project structure”。
把java目录设置为Sources。选中java文件夹,点击上面的Make as:Sources,该文件夹就会变成蓝色,用以保存java代码,按OK。
编写java代码。新建一个包
package com.wisedu.demo; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * Created by jkzhao on 11/30/17. */ public class ServletTest extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.getRequestDispatcher("/jsp/test.jsp").forward(req, resp); } }
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <display-name>Archetype Created Web Application</display-name> <!-- 配置servlet --> <servlet> <servlet-name>servletTest</servlet-name> <servlet-class>com.wisedu.demo.ServletTest</servlet-class> </servlet> <servlet-mapping> <servlet-name>servletTest</servlet-name> <url-pattern>/test</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> </web-app>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!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=UTF-8"> <title>第一个maven工程</title> </head> <body> 第一个maven工程,运行了一个servlet </body> </html>
Mac上打开终端,进去这个项目目录下:
访问:http://localhost:8080/mvnDemo/test
(2)Maven项目工程目录约定
(3)Maven常用命令
- compile:compile是maven工程的编译命令,作用是将 src/main/java 下的文件编译为class文件输出到 target 目录下。windows上打开cmd(linux或Mac上打开xshell终端),输入命令:mvn compile。命令执行完,在 src 同级目录,可以看到 target 文件夹,里面都是编译好的class文件。
- test:test是maven工程的测试命令,会执行 src/test/java 下的单元测试类。windows上打开cmd(linux或Mac上打开xshell终端),输入命令:mvn test
- clean:clean是maven工程的清理命令,执行clean会删除 target 目录的内容。
- package:package是maven工程的打包命令,对于java工程执行 package 命令会打成jar包,对于web工程打成war包。
- install:install是maven工程的安装命令,执行install将maven打成jar包或war包发布到本地仓库。
(4)生命周期(了解)
三套生命周期:maven对项目构建过程分为三套相互独立的生命周期,注意这里说的是“三套”,而且“相互独立”,这三套生命周期分别是:
- Clean Lifecycle:在进行真正的构建之前进行一些清理工作;
- Default Lifecycle:构建的核心部分,编译、测试、打包、部署等等。
- Site Lifecycle:生成项目报告,站点,发布站点。
生命周期的阶段
每个生命周期都有很多阶段,每个阶段对应一个执行命令。
- 如下是clean生命周期的阶段:
- pre-clean:执行一些需要在clean之前完成的工作
- clean:移除所有上一次构建生成的文件
- post-clean:执行一些需要在clean之后立刻完成的工作
- 如下是default生命周期的阶段:
- 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-classes
- test 使用合适的单元测试框架进行测试。这些测试代码不会被打包或部署
- prepare-package
- package 接受编译好的代码,打包成可发布的格式,如JAR
- pre-integration-test
- integration-test
- post-integration-test
- verify
- install 将包安装至本地仓库,以让其它项目依赖
- deploy 将最终的包复制到远程的仓库,以让其它开发人员与项目共享
- 如下是site生命周期的阶段
- pre-site:执行一些需要在生成站点文档之前完成的工作
- site:生成项目的站点文档
- post-site:执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
- site-deploy:将生成的站点文档部署在特定的服务器上。
命令与生命周期的阶段:
每个maven命令对应生命周期的某个阶段,例如:mvn clean 命令对应clean生命周期的clean阶段,mvn test 命令对应default生命周期的test阶段。
执行命令会将该命令在的生命周期当中之前的阶段自动执行,比如:执行mvn clean 命令会自动执行 pre-clean 和 clean 两个阶段,执行mvn test命令会自动执行 validate、compile、test等阶段。
【注意】:执行某个生命周期的某个阶段不会影响其它的生命周期。
如果要同时执行多个生命周期的阶段可在命令行输入多个命令,中间以空格隔开,例如:mvn clean package,该命令执行clean生命周期的clean阶段和default生命周期的package阶段。
(5)maven的概念模型
Maven包含了一个项目对象模型(Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Management System),和用来运行定义在生命周期阶段(phase)中插件(plugin)目标(goal)的逻辑。
下图是maven的概念模型图:
- 项目对象模型(Project Object Model)
- 一个maven工程都有一个pom.xml文件,通过pom.xml文件定义项目的坐标、项目依赖、项目信息、插件目标等。
- 依赖管理系统(Dependency Management System)
- 通过maven的依赖管理对项目所依赖jar包进行统一管理。
- 比如:项目依赖junit 4.9,通过pom.xml中定义junit 4.9的依赖即使用junit 4.9,如下图所示是定义junit 4.9的依赖定义:
- 一个项目生命周期(Project Lifecycle)
- 使用maven完成项目的构建,项目构建包括:清理、编译、测试、部署等过程,maven将这些过程规范为一个生命周期,如下所示是生命周期的各个阶段
- maven通过执行一些简单的命令即可实现上边生命周期的各个过程。
- 一组标准集合
- maven将整个项目管理过程定义一组标准,比如:通过maven构建工程有标准的目录结构,有标准的生命周期阶段、依赖管理有标准的坐标定义等。
- 插件(plugin)目标(goal)
- maven管理项目生命周期过程都是基于插件完成的。
四、项目构建
1. m2e插件安装配置
使用命令行的方式使用maven工作效率不高,可以在eclipse开发工具中集成maven软件,eclipse是一个开发工具,maven是一个项目管理工具,maven有一套项目构建的规范,在eclipse中集成maven插件,最终通过eclipse创建maven工程。
我使用的eclipse自带maven插件,不用单独安装。点击File—>New—>Other,可以看到maven项目的创建项,表示maven插件已存在,如下图:
2. 指定maven安装目录
一些高版本的eclipse已经内置了maven的安装,下图是我使用的eclipse版本中已经内置了的 maven3.3.9 版本, 项目为了统一不会使用eclipse内置的maven版本,这里我们用的是maven 3.3.9
3. User Setting 配置
修改默认的本地仓库地址。
【注意】:如果修改了 setting.xml 文件需要点击上图中的“Update Settings”按钮对本地仓库重建索引,点击“Reindex”。
4. eclipse浏览仓库
maven配置完成后,需要测试在eclipse中是否可以浏览maven的本地仓库,如果可以正常浏览maven本地仓库则说明eclipse集成maven已经完成。
点击eclipse菜单栏的 windows—> Show View—>Other,输入maven:
找到 Local repository 本地仓库选项,点击 Rebuild index 重建索引。
重建索引完成后,点击前面的“+”图标,可查看本地仓库的内容,如下图:
5. 定义maven坐标
每个maven工程都需要定义本工程的坐标,坐标是maven对jar包的身份定义,比如
<!-- 项目名称:定义为组织名+项目名,类似包名 --> <groupId>com.wisedu</groupId> <!-- 模块名称 --> <artifactId>mvnDemo</artifactId> <!-- 当前项目版本号,snapshot为快照版本即非正式版本,release为正式发布版本 --> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <!-- 打包类型,jar:执行package命令会打成jar包; war:打成war包; pom:用户maven工程的继承,通常父工程设置为pom -->
6. 构建maven项目(以eclipse演示)
(1)File—>New—>Other,输入maven,选择“Maven Project”
了解下骨架界面:当我们不跳过骨架点击“next”会进入骨架选择界面,如果eclipse中配置本地仓库正确则显示出骨架
【注意】:使用骨架的问题是创建maven工程目录不完整,所以不推荐使用。
(2)定义坐标
(3)处理红色叉号
手动在webapp文件夹下创建一个WEB-INF文件夹,在里面放一个web.xml文件。但是项目还是红的。这是因为需要设置编译版本。
(4)设置编译版本
查看上边工程的“Libraries”,显示的是JDK1.5,这里我使用JDK1.7,需要设置编译版本为1.7,这里需要使用maven插件来设置。
在pom.xml中添加如下代码:
<build> <finalName>mvnDemo</finalName> <!-- 配置了很多插件 --> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.7</source> <target>1.7</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build>
选中项目“helloworld”,鼠标右键选择“Maven”—>"Update project"。然后点开“Libraries”,可以看到变为1.7了。
(5)编写Servlet
在 src/main/java 下创建package和Servlet
package com.wisedu.hello; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class ServletTest */ public class ServletTest extends HttpServlet { private static final long serialVersionUID = 1L; /** * Default constructor. */ public ServletTest() { // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.getWriter().append("Served at: ").append(request.getContextPath()); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }
但是你会发现里面报红很多,因为没有jar包。
还有web.xml也报错了,因为你创建Servlet的时候,它去修改了web.xml文件。
(6)添加jar包
添加jar包的方式不再是之前那样创建一个lib文件夹,把需要的jar包放进去。
在pom.xml中添加如下代码
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.9</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> </dependencies>
点击保存,然后你就会发现jar包已添加到项目中:
(7)启动项目
右击项目—>Run As—>Maven build…
浏览器访问:http://localhost:8080/helloworld/ServletTest
五、依赖管理
就是jar包的管理。
1. 添加依赖
在pom.xml中添加<dependency>标签,如下:
<dependency> <groupId></groupId> <artifactId></artifactId> <version></version> <scope></scope> </dependency>
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.9</version> <scope>test</scope> </dependency>
2. 查找坐标
添加依赖需要指定依赖jar包的坐标,但是很多情况我们是不知道jar包的坐标,可以通过如下方式查询:
(1)方式一:从互联网搜索
- http://search.maven.org/
- http://mvnrepository.com/
网站搜索示例:以http://mvnrepository.com/为例:
(2)方式二:使用maven插件的索引功能
如果在本地仓库有我们要的jar包,可以在pom.xml中直接添加依赖。
在Eclipse中,选中项目,右键选择“Maven”—>“Add Dependency”。
点击OK后,就可以看到pom.xml中加入了相应的代码。
3. 依赖范围
A依赖B,需要在A的pom.xml中添加B的坐标,添加坐标时需要指定依赖范围,依赖范围包括:
- compile:编译范围,指A在编译时依赖B,此范围为默认依赖范围。编译范围的依赖会用在编译、测试、运行,由于运行时需要所以编译范围内的依赖会被打包。
- provided:provided依赖只有在当JDK或者一个容器已经提供该依赖之后才使用,provided依赖在编译和测试时需要,在运行时不需要,所以打包时不需要。比如:servlet api被tomcat容器提供。
- runtime:runtime依赖在运行和测试系统的时候需要,但在编译的时候不需要,比如jdbc驱动包。由于运行时需要所以runtime范围的依赖会被打包
- test:test范围依赖 在编译和运行时都不需要(因为测试的代码都在 src/test/java/ 下面的代码,编译时编译的是 src/main/java/ 下的源代码),它们只有在测试编译和测试运行阶段可用,比如junit。由于运行时不需要,所以test范围依赖不会被打包。
- system:system范围依赖 与provided类似,但是你必须显式的提供一个对于本地系统中JAR文件的路径,需要指定systemPath磁盘路径,system依赖不推荐使用。
依赖范围由强到弱的顺序是:compile>provided>runtime>test
4. maven添加插件
这也是可以通过修改插件来修改的:(上面的是默认的tomcat插件,不会出现在pom.xml中,但是修改别的tomcat插件,该插件的配置需要存在于pom.xml中)
在Eclipse中,选中项目,右键选择“Maven”—>“Add Plugin”。
点击OK后,查看pom.xml,多了该插件的配置代码。
如果需要修改端口,需要添加如下的配置: