《Maven实战》
《Maven实战》是国内第一本公开出版的Maven专著。它内容新颖,基于最新发布的Maven 3.0,不仅详尽讲解了Maven 3.0的所有新功能和新特性,而且还将这些新功能和新特性与Maven 2.x版本进行了对比,以便于正在使用Maven 2.x版本的用户能更好地理解。本书它内容全面,以从专家的角度阐释Maven的价值开篇,全面介绍了Maven的安装、配置和基本使用方法,以便于初学者参考;详细讲解了坐标和依赖、Maven仓库、生命周期和插件、聚合与继承等Maven的核心概念,建议所有读者仔细阅读;系统性地阐述了使用Nexus建立私服、使用Maven进行测试、使用Hudson进行持续集成、使用Maven构建Web应用、Maven的版本管理、Maven的灵活构建、生成项目站点和Maven的m2eclipse插件等实用性较强的高级知识,读者可有选择性的阅读;扩展性地讲解了如何Maven和Archetype插件,这部分内容对需要编写插件扩展Maven或需要编写Archetype维护自己的项目骨架以更便于团队开发的读者来说尤为有帮助。它实战性强,不仅绝大部分知识点都有相应的案例,而且本书还在第4章设计了一个背景案例,后面的很多章节都是围绕这个案例展开的,可操作性极强。
本书适合所有Java程序员阅读,无论你是从未使用过Maven,亦或是已经使用Maven很长一段时间了,相信你都能从本书中获得有价值的参考。本书也适合所有项目经理阅读,它能帮助你更规范、更高效地管理Java项目。
</modelVersion>
最后一个name元素声明了一个对于用户更为友好的项目名称,虽然这不是必须的,但我还是推荐为每个POM声明name,以方便信息交流。
没有任何实际的Java代码,我们就能够定义一个Maven项目的POM,这体现了Maven的一大优点,它能让项目对象模型最大程度地与实际代码相独立,我们可以称之为解耦,或者正交性,这在很大程度上避免了Java代码和POM代码的相互影响。比如当项目需要升级版本时,只需要修改POM,而不需要更改Java代码;而在POM稳定之后,日常的Java代码开发工作基本不涉及POM的修改。
3.2 编写主代码
项目主代码和测试代码不同,项目的主代码会被打包到最终的构件中(比如jar),而测试代码只在运行测试时用到,不会被打包。默认情况下,Maven假设项目主代码位于src/main/java目录,我们遵循Maven的约定,创建该目录,然后在该目录下创建文件com/juvenxu/mvnbook/helloworld/HelloWorld.java,其内容如代码清单3-2:
代码清单3-2:Hello World的主代码
- <span style="font-size: small;"> source file to D: \code\hello-world\target\classes
- [INFO] ------------------------------------------------------------------------
- [INFO] BUILD SUCCESSFUL
- [INFO] ------------------------------------------------------------------------
- [INFO] Total time: second
- [INFO] Finished at: Fri Oct :: CST
- [INFO] Final Memory: 9M/16M
- [INFO] ------------------------------------------------------------------------
- </span>
clean告诉Maven清理输出目录target/,compile告诉Maven编译项目主代码,从输出中我们看到Maven首先执行了clean:clean任务,删除target/目录,默认情况下Maven构建的所有输出都在target/目录中;接着执行resources:resources任务(未定义项目资源,暂且略过);最后执行compiler:compile任务,将项目主代码编译至target/classes目录(编译好的类为com/juvenxu/mvnbook/helloworld/HelloWorld.Class)。
上文提到的clean:clean、resources:resources,以及compiler:compile对应了一些Maven插件及插件目标,比如clean:clean是clean插件的clean目标,compiler:compile是compiler插件的compile目标,后文会详细讲述Maven插件及其编写方法。
至此,Maven在没有任何额外的配置的情况下就执行了项目的清理和编译任务,接下来,我们编写一些单元测试代码并让Maven执行自动化测试。
3.3 编写测试代码
为了使项目结构保持清晰,主代码与测试代码应该分别位于独立的目录中。3.2节讲过Maven项目中默认的主代码目录是src/main/java,对应地,Maven项目中默认的测试代码目录是src/test/java。因此,在编写测试用例之前,我们先创建该目录。
在Java世界中,由Kent Beck和Erich Gamma建立的JUnit是事实上的单元测试标准。要使用JUnit,我们首先需要为Hello World项目添加一个JUnit依赖,修改项目的POM如代码清单3-3:
代码清单3-3:为Hello World的POM添加依赖
- <?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/maven-v4_0_0.xsd">
- <modelVersion></modelVersion>
- <groupId>com.juvenxu.mvnbook</groupId>
- <artifactId>hello-world</artifactId>
- <version> source file to D: \code\hello-world\target\classes
- [INFO] [resources:testResources {execution: source file to D:\ code\hello-world\target\test-classes
- [INFO] ------------------------------------------------------------------------
- [ERROR] BUILD FAILURE
- [INFO] ------------------------------------------------------------------------
- [INFO] Compilation failure
- D:\code\hello-world\src\test\java\com\juvenxu\mvnbook\helloworld\HelloWorldTest.java:[,] -source 或更高版本以启用注释)
- source file to D: \code\hello-world\target\test-classes
- [INFO] [surefire:test {execution: , Failures: , Errors: , Skipped: , Time elapsed: , Failures: , Errors: , Skipped:
- [INFO] ------------------------------------------------------------------------
- [INFO] BUILD SUCCESSFUL
- [INFO] ------------------------------------------------------------------------
- …
我们看到compiler:testCompile任务执行成功了,测试代码通过编译之后在target/test-classes下生成了二进制文件,紧接着surefire:test任务运行测试,surefire是Maven世界中负责执行测试的插件,这里它运行测试用例HelloWorldTest,并且输出测试报告,显示一共运行了多少测试,失败了多少,出错了多少,跳过了多少。显然,我们的测试通过了——BUILD SUCCESSFUL。
3.4 打包和运行
将项目进行编译、测试之后,下一个重要步骤就是打包(package)。Hello World的POM中没有指定打包类型,使用默认打包类型jar,我们可以简单地执行命令 mvn clean package 进行打包,可以看到如下输出:
- …
- Tests run: , Failures: , Errors: , Skipped:
- [INFO] [jar:jar {execution: </version>
- <executions>
- <execution>
- <phase>package</phase>
- <goals>
- <goal>shade</goal>
- </goals>
- <configuration>
- <transformers>
- <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.juvenxu.mvnbook.helloworld.HelloWorld</mainClass>
- </transformer>
- </transformers>
- </configuration>
- </execution>
- </executions>
- </plugin>
plugin元素在POM中的相对位置应该在<project><build><plugins>下面。我们配置了mainClass为com.juvenxu.mvnbook.helloworld.HelloWorld,项目在打包时会将该信息放到MANIFEST中。现在执行 mvn clean install ,待构建完成之后打开target/目录,我们可以看到hello-world-1.0-SNAPSHOT.jar和original-hello-world-1.0-SNAPSHOT.jar,前者是带有Main-Class信息的可运行jar,后者是原始的jar,打开hello-world-1.0-SNAPSHOT.jar的META-INF/MANIFEST.MF,可以看到它包含这样一行信息:
Main-Class: com.juvenxu.mvnbook.helloworld.HelloWorld
现在,我们在项目根目录中执行该jar文件:
D: \code\hello-world>java -jar target\hello-world-1.0-SNAPSHOT.jar
Hello Maven
控制台输出为Hello Maven,这正是我们所期望的。
本小节介绍了Hello World项目,侧重点是Maven而非Java代码本身,介绍了POM、Maven项目结构、以及如何编译、测试、打包,等等。
3.5 使用Archetype生成项目骨架
Hello World项目中有一些Maven的约定:在项目的根目录中放置pom.xml,在src/main/java目录中放置项目的主代码,在src/test/java中放置项目的测试代码。我之所以一步一步地展示这些步骤,是为了能让可能是Maven初学者的你得到最实际的感受。我们称这些基本的目录结构和pom.xml文件内容称为项目的骨架,当你第一次创建项目骨架的时候,你还会饶有兴趣地去体会这些默认约定背后的思想,第二次,第三次,你也许还会满意自己的熟练程度,但第四、第五次做同样的事情,就会让程序员恼火了,为此Maven提供了Archetype以帮助我们快速勾勒出项目骨架。
还是以Hello World为例,我们使用maven archetype来创建该项目的骨架,离开当前的Maven项目目录。
如果是Maven 3,简单的运行:
mvn archetype:generate
如果是Maven 2,最好运行如下命令:
mvn org.apache.maven.plugins:maven-archetype-plugin:2.0-alpha-5:generate
很多资料会让你直接使用更为简单的 mvn archetype:generate 命令,但在Maven2中这是不安全的,因为该命令没有指定archetype插件的版本,于是Maven会自动去下载最新的版本,进而可能得到不稳定的SNAPSHOT版本,导致运行失败。然而在Maven 3中,即使用户没有指定版本,Maven也只会解析最新的稳定版本,因此这是安全的,具体内容见7.7小节。
我们实际上是在运行插件maven-archetype-plugin,注意冒号的分隔,其格式为groupId:artifactId:version:goal ,org.apache.maven.plugins 是maven官方插件的groupId,maven-archetype-plugin 是archetype插件的artifactId,2.0-alpha-5 是目前该插件最新的稳定版,generate是我们要使用的插件目标。
紧接着我们会看到一段长长的输出,有很多可用的archetype供我们选择,包括著名的Appfuse项目的archetype,JPA项目的archetype等等。每一个archetype前面都会对应有一个编号,同时命令行会提示一个默认的编号,其对应的archetype为maven-archetype-quickstart,我们直接回车以选择该archetype,紧接着Maven会提示我们输入要创建项目的groupId、artifactId、 version、以及包名package,如下输入并确认:
- Define value for groupId: : com.juvenxu.mvnbook
- Define value for artifactId: : hello-world
- Define value for version: 1.0-SNAPSHOT: :
- Define value for package: com.juvenxu.mvnbook: : com.juvenxu.mvnbook.helloworld
- Confirm properties configuration:
- groupId: com.juvenxu.mvnbook
- artifactId: hello-world
- version: 1.0-SNAPSHOT
- package: com.juvenxu.mvnbook.helloworld
- Y: : Y
Archetype插件将根据我们提供的信息创建项目骨架。在当前目录下,Archetype插件会创建一个名为hello-world(我们定义的artifactId)的子目录,从中可以看到项目的基本结构:基本的pom.xml已经被创建,里面包含了必要的信息以及一个junit依赖;主代码目录src/main/java已经被创建,在该目录下还有一个Java类com.juvenxu.mvnbook.helloworld.App,注意这里使用到了我们刚才定义的包名,而这个类也仅仅只有一个简单的输出Hello World!的main方法;测试代码目录src/test/java也被创建好了,并且包含了一个测试用例com.juvenxu.mvnbook.helloworld.AppTest。
Archetype可以帮助我们迅速地构建起项目的骨架,在前面的例子中,我们完全可以在Archetype生成的骨架的基础上开发Hello World项目以节省我们大量时间。
此外,我们这里仅仅是看到了一个最简单的archetype,如果你有很多项目拥有类似的自定义项目结构以及配置文件,你完全可以一劳永逸地开发自己的archetype,然后在这些项目中使用自定义的archetype来快速生成项目骨架,本书后面的章节会详细阐述如何开发Maven Archetype。
3.6 m2eclipse简单使用
介绍前面Hello World项目的时候,我们并没有涉及IDE,如此简单的一个项目,使用最简单的编辑器也能很快完成,但对于稍微大一些的项目来说,没有IDE就是不可想象的,本节我们先介绍m2eclipse的基本使用。
3.6.1 导入Maven项目
第2章介绍了如何安装m2eclipse,现在,我们使用m2ecilpse导入Hello World项目。选择菜单项File,然后选择Import,我们会看到一个Import对话框,在该对话框中选择General目录下的Maven Projects,然后点击Next,就会出现Import Projects对话框,在该对话框中点击Browse…选择Hello World的根目录(即包含pom.xml文件的那个目录),这时对话框中的Projects:部分就会显示该目录包含的Maven项目,如图3-1所示:
图3-1 在Eclipse中导入Maven项目
点击Finish之后,m2ecilpse就会将该项目导入到当前的workspace中,导入完成之后,我们就可以在Package Explorer视图中看到如图3-2所示的项目结构:
图3-2 Eclipse中导入的Maven项目结构
我们看到主代码目录src/main/java和测试代码目录src/test/java成了Eclipse中的资源目录,包和类的结构也十分清晰,当然pom.xml永远在项目的根目录下,而从这个视图中我们甚至还能看到项目的依赖junit-4.7.jar,其实际的位置指向了Maven本地仓库(这里我自定义了Maven本地仓库地址为D:\java\repository,后续章节会介绍如何自定义本地仓库位置)。
3.6.2 创建Maven项目
创建一个Maven项目也十分简单,选择菜单项File -> New -> Other,在弹出的对话框中选择Maven下的Maven Project,然后点击Next >,在弹出的New Maven Project对话框中,我们使用默认的选项(不要选择Create a simple project选项,那样我们就能使用Maven Archetype),点击Next >,此时m2eclipse会提示我们选择一个Archetype,我们选择maven-archetype-quickstart,再点击Next >。由于m2eclipse实际上是在使用maven-archetype-plugin插件创建项目,因此这个步骤与上一节我们使用archetype创建项目骨架类似,输入groupId,、artifactId、version、package(暂时我们不考虑Properties),如图3-3所示:
图3-3 在Eclipse中使用Archetype创建项目
注意,为了不和前面已导入的Hello World项目产生冲突和混淆,我们使用不同的artifactId和package。OK,点击Finish,Maven项目就创建完成了,其结构与前一个已导入的Hello World项目基本一致。
3.6.3 运行mvn命令
我们需要在命令行输入如mvn clean install之类的命令来执行maven构建,m2eclipse中也有对应的功能,在Maven项目或者pom.xml上右击,再选择Run As,就能看到如下的常见Maven命令,如图3-4所示:
图3-4 在Eclipse中运行默认mvn命令
选择想要执行的Maven命令就能执行相应的构建,同时我们也能在Eclipse的console中看到构建输出。这里常见的一个问题是,默认选项中没有我们想要执行的Maven命令怎么办?比如,默认带有mvn test,但我们想执行mvn clean test,很简单,选择Maven buid… 以自定义Maven运行命令,在弹出对话框中的Goals一项中输入我们想要执行的命令,如clean test,设置一下Name,点击Run即可。并且,下一次我们选择Maven build,或者使用快捷键Alt + Shift + X, M快速执行Maven构建的时候,上次的配置直接就能在历史记录中找到。图3-5就是自定义Maven运行命令的界面:
图3-5 在Eclipse中自定义mvn命令
3.7 NetBeans Maven插件简单使用
NetBeans的Maven插件也十分简单易用,我们可以轻松地在NetBeans中导入现有的Maven项目,或者使用Archetype创建Maven项目,我们也能够在NetBeans中直接运行mvn命令。
3.7.1 打开Maven项目
与其说打开Maven项目,不如称之为导入更为合适,因为这个项目不需要是NetBeans创建的Maven项目,不过这里我们还是遵照NetBeans菜单中使用的名称。
选择菜单栏中的文件,然后选择打开项目,直接定位到Hello World项目的根目录,NetBeans会十分智能地识别出Maven项目,如图3-6所示:
图3-6 在NetBeans中导入Maven项目
Maven项目的图标有别于一般的文件夹,点击打开项目后,Hello World项目就会被导入到NetBeans中,在项目视图中可以看到如图3-7所示的项目结构:
图3-7 NetBeans中导入的Maven项目结构
NetBeans中项目主代码目录的名称为源包,测试代码目录成了测试包,编译范围依赖为库,测试范围依赖为测试库,这里我们也能看到pom.xml,NetBeans甚至还帮我们引用了settings.xml。
3.7.2 创建Maven项目
在NetBeans中创建Maven项目同样十分轻松,在菜单栏中选择文件,然后新建项目,在弹出的对话框中,选择项目类别为Maven,项目为Maven项目,点击“下一步”之后,对话框会提示我们选择Maven原型(即Maven Archtype),我们选择Maven快速启动原型(1.0),(即前文提到的maven-archetype-quickstart),点击“下一步”之后,输入项目的基本信息,这些信息在之前讨论archetype及在m2eclipse中创建Maven项目的时候都仔细解释过,不再详述,如图3-8所示:
图3-8 在NetBeans中使用Archetype创建Maven项目
点击完成之后,一个新的Maven项目就创建好了。
3.7.3 运行mvn命令
NetBeans在默认情况下提供两种Maven运行方式,点击菜单栏中的运行,我们可以看到生成项目和清理并生成项目两个选项,我们可以尝试“点击运行Maven构建”,根据NetBeans控制台的输出,我们就能发现它们实际上对应了mvn install和mvn clean install两个命令。
在实际开发过程中,我们往往不会满足于这两种简单的方式,比如,有时候我们只想执行项目的测试,而不需要打包,这时我们就希望能够执行mvn clean test命令,所幸的是NetBeans Maven插件完全支持自定义的mvn命令配置。
在菜单栏中选择工具,接着选择选项,在对话框中,最上面一栏选择其他,下面选择Maven标签栏,在这里我们可以对NetBeans Maven插件进行全局的配置(还记得第2章中我们如何配置NetBeans使用外部Maven么?)。现在,选择倒数第三行的编辑全局定制目标定义…,我们添加一个名为Maven Test的操作,执行目标为clean test,暂时不考虑其他配置选项,如图3-9所示:
图3-9 在NetBeans中自定义mvn命令
点击“缺省保存该配置”,在Maven项目上右击,选择定制,就能看到刚才配置好的Maven运行操作,选择Maven Test之后,终端将执行mvn clean test。值得一提的是,我们也可以在项目上右击,选择定制,再选择目标…再输入想要执行的Maven目标(如clean package),点击确定之后NetBeans就会执行相应的Maven命令。这种方式十分便捷,但这是临时的,该配置不会被保存,也不会有历史记录。
3.8 小结
《Maven实战》的更多相关文章
- 简单物联网:外网访问内网路由器下树莓派Flask服务器
最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...
- 利用ssh反向代理以及autossh实现从外网连接内网服务器
前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...
- 外网访问内网Docker容器
外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...
- 外网访问内网SpringBoot
外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...
- 外网访问内网Elasticsearch WEB
外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...
- 怎样从外网访问内网Rails
外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...
- 怎样从外网访问内网Memcached数据库
外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...
- 怎样从外网访问内网CouchDB数据库
外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...
- 怎样从外网访问内网DB2数据库
外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...
- 怎样从外网访问内网OpenLDAP数据库
外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...
随机推荐
- appium+python自动化34-获取元素属性get_attribute
获取text # coding:utf-8 from appium import webdriver from time import sleep desired_caps = { 'platform ...
- SpringMVC中注解控制器及数据绑定
一.Spring2.5之前,我们都是通过实现Controller接口或其他实现来定义我们的处理器类. 二.Spring2.5引入注解式处理器支持,通过@Controller 和 @RequestMap ...
- lnmp环境应用实践
LNMP 用户通过浏览器输入域名请求nginx web服务,如果请求时静态资源,则由nginx解析返回给用户:如果是动态请求(.php结尾),那么nginx就会把它通过FastCGI接口(生产常用方法 ...
- 大白话系列之C#委托与事件讲解大结局
声明:本系列非原创,因为太精彩才转载,如有侵权请通知删除,原文:http://www.cnblogs.com/wudiwushen/archive/2010/04/20/1698795.html 今天 ...
- jQuery笔记——UI
jQuery UI 的官网网站为:http://jqueryui.com/,我们下载最新版本的即可,使用JQueryUI中的样式比我们使用原生的HTML要好看,还会有一些封装好的特效,JQueryUI ...
- Histogram
folly/Histogram.h Classes Histogram Histogram.h defines a simple histogram class, templated on the t ...
- JAVA for循环语句的循环变量类型问题
class HalfDollars { public static void main(String [] arguments) { int[] denver = {1_900_000,1_700_0 ...
- 上传图片demo
页面: js: 后台: @RequiresPermissions("pointwall:upload:edit") @RequestMapping(value = "sa ...
- 升级oracle 9i到10g
从9i升级到10g两个方案可供选择: 一是利用oracle提供的一个升级实用程序dbua(database upgrade assistant)直接将9i的数据库升级到10g. 再有就是新建一个1 ...
- TypeScript--deno前置学习
第一节:前言: 1.JavaScript 的发展简史图: 2.关于node与deno: (1)Node与Deno 的区别:Node 可以工作,而 Deno 不行,Deno 只是一个原型或实验性产品. ...