安装和运行Maven
Maven Help 插件有四个目标。前三个目标是—— active-profiles, effective-pom 和
effective-settings —— 描述一个特定的项目,它们必须在项目的目录下运行。 最后
一个目标—— describe ——相对比较复杂,展示某个插件或者插件目标的相关信息。
help:active-profiles
列出当前构建中活动的Profile(项目的,用户的,全局的)。
help:effective-pom
显示当前构建的实际POM,包含活动的Profile。
help:effective-settings
打印出项目的实际settings, 包括从全局的settings和用户级别settings继承的
配置。
help:describe
描述插件的属性。它不需要在项目目录下运行。但是你必须提供你想要描述插件
的 groupId 和 artifactId。
2.7.1. 描述一个Maven插件
一旦你开始使用Maven,你会花很多时间去试图获得Maven插件的信息:插件如何工
作?配置参数是什么?目标是什么? 你会经常使用help:describe 目标来获取这些信
息。通过 plugin 参数你可以指定你想要研究哪个插件,你可以传入插件的前缀(如
help 插件就是 maven-help-plugin),或者可以是 groupId:artifact[:version] ,这
里 version 是可选的。比如, 下面的命令使用 help 插件的 describe 目标来输出
Maven Help 插件的信息。
$ mvn help:describe -Dplugin=help
...
Group Id: org.apache.maven.plugins
Artifact Id: maven-help-plugin
Version: 2.0.1
Goal Prefix: help
Description:
The Maven Help plugin provides goals aimed at helping to make sense out of
the build environment. It includes the ability to view the effective
POM and settings files, after inheritance and active profiles
have been applied, as well as a describe a particular plugin goal to give
usage information.
...
通过设置 plugin 参数来运行 describe 目标,输出为该插件的Maven坐标,目标前
缀,和该插件的一个简要介绍。尽管这些信息非常有帮助,你通常还是需要了解更多
15
32.
安装和运行Maven
的详情。如果你想要 Help 插件输出完整的带有参数的目标列表,只要运行带有参数
full的 help:describe 目标就可以了,像这样:
$ mvn help:describe -Dplugin=help -Dfull
...
Group Id: org.apache.maven.plugins
Artifact Id: maven-help-plugin
Version: 2.0.1
Goal Prefix: help
Description:
The Maven Help plugin provides goals aimed at helping to make sense out of
the build environment. It includes the ability to view the effective
POM and settings files, after inheritance and active profiles
have been applied, as well as a describe a particular plugin goal to give usage
information.
Mojos:
===============================================
Goal: 'active-profiles'
===============================================
Description:
Lists the profiles which are currently active for this build.
Implementation: org.apache.maven.plugins.help.ActiveProfilesMojo
Language: java
Parameters:
-----------------------------------------------
[0] Name: output
Type: java.io.File
Required: false
Directly editable: true
Description:
This is an optional parameter for a file destination for the output of this mojo...t
listing of active profiles per project.
-----------------------------------------------
[1] Name: projects
Type: java.util.List
Required: true
16
33.
安装和运行Maven
Directly editable: false
Description:
This is the list of projects currently slated to be built by Maven.
-----------------------------------------------
This mojo doesn't have any component requirements.
===============================================
... removed the other goals ...
该选项能让你查看插件所有的目标及相关参数。但是有时候这些信息显得太多了。这
时候你可以获取单个目标的信息,设置 mojo 参数和 plugin 参数。下面的命令列出了
Compiler 插件的 compile 目标的所有信息
$ mvn help:describe -Dplugin=compiler -Dmojo=compile -Dfull
注意
什么? Mojo ?在Maven里面, 一个插件目标也被认为是一个 “Mojo” 。
2.8. 关于Apache软件许可证
Apache Maven 是基于 Apache 许可证2.0版 发布的。如果你想阅读该许可证,你可
以查阅 /usr/local/maven/LICENSE.txt 或者从开源发起组织的网站上查阅 http://
www.opensource.org/licenses/apache2.0.php。
很有可能你正在阅读本书但你又不是律师。如果你想知道 Apache许可证2.0版意
味着什么,Apache软件基金会收集了一个很有帮助的,关于许可证的常见问题解答
(FAQ):http://www.apache.org/foundation/licence-FAQ.html。这里是对问题“我
不是律师,所有这些是什么意思?”的回答。
它允许你:
• • 自由的下载和使用 Apache 软件,无论是软件的整体还是部分,
也无论是出于个人目的,公司内部目的,还是商业目的。
• • 在你创建的类库或分发版本里使用 Apache 软件。
它禁止你:
• 在没有正当的权限下重新分发任何源于 Apache 的软件或软件片
段。
17
定制一个Maven项目
例 4.5. Simple Weather 的Main 类
package org.sonatype.mavenbook.weather;
import java.io.InputStream;
import org.apache.log4j.PropertyConfigurator;
public class Main {
public static void main(String[] args) throws Exception {
// Configure Log4J
PropertyConfigurator.configure(Main.class.getClassLoader()
.getResource("log4j.properties"));
// Read the Zip Code from the Command-line (if none supplied, use 60202)
int zipcode = 60202;
try {
zipcode = Integer.parseInt(args[0]);
} catch( Exception e ) {}
// Start the program
new Main(zipcode).start();
}
private int zip;
public Main(int zip) {
this.zip = zip;
}
public void start() throws Exception {
// Retrieve Data
InputStream dataIn = new YahooRetriever().retrieve( zip );
// Parse Data
Weather weather = new YahooParser().parse( dataIn );
// Format (Print) Data
System.out.print( new WeatherFormatter().format( weather ) );
}
}
47
一个简单的Web应用
例 5.6. 匹配 Simple Servlet
<!DOCTYPEweb-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>simple</servlet-name>
<servlet-class>org.sonatype.mavenbook.web.SimpleServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>simple</servlet-name>
<url-pattern>/simple</url-pattern>
</servlet-mapping>
</web-app>
一切文件就绪,准备测试这个 servlet 。 src/main/java 下的类,以及 web.xml 已
经被更新了。在启动 Jetty 插件之前,运行 mvn compile 以编译你的项目:
~/examples$ mvn compile
...
[INFO] [compiler:compile]
[INFO] Compiling 1 source file to ~/examples/ch05/simple-webapp/target/classes
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Compilation failure
~/ch05/simple-webapp/src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[4,
package javax.servlet does not exist
~/ch05/simple-webapp/src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[5,
package javax.servlet.http does not exist
~/ch05/simple-webapp/src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[7,
cannot find symbol
symbol: class HttpServlet
public class SimpleServlet extends HttpServlet {
~/ch05/simple-webapp/src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[8,
cannot find symbol
symbol : class HttpServletRequest
location: class org.sonatype.mavenbook.web.SimpleServlet
71
88.
一个简单的Web应用
~/ch05/simple-webapp/src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[9,
cannot find symbol
symbol : class HttpServletResponse
location: class org.sonatype.mavenbook.web.SimpleServlet
~/ch05/simple-webapp/src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[10
cannot find symbol
symbol : class ServletException
location: class org.sonatype.mavenbook.web.SimpleServlet
编译失败了,因为你的 Maven 项目没有对 Servlet API 的依赖。 在下一节,我们会
为你项目的 POM 添加 Servlet API 。
5.6. 添加J2EE依赖
为了编写一个 servlet ,我们需要添加 Servlet API 作为项目依赖。 Servlet
规格说明是一个 JAR 文件,它能从 Sun Microsystems 的站点下载到 http://
java.sun.com/products/servlet/download.html 。JAR 文件下载好之后你需要把它
安装到位于 ~/.m2/repository 的 Maven 本地仓库。你必须为所有 Sun Microsystems
维护的 J2EE API 重复同样的过程,包括 JNDI, JDBC, Servlet, JSP, JTA, 以
及其它。 如果你不想这么做因为觉得这样太无聊了,其实不只有你这么认为。 幸
运的是,有一种更简单的方法来下载所有这些类库并安装到本地仓库 —— Apache
Geronimo 的独立的开源实现。
很多年以来,获取 Servlet 规格说明 JAR 文件的唯一方式是从 Sun Microsystems
下载。 你必须到 Sun 的 web 站点,同意并且点击它的许可证协议,这样才能访问
Servlet JAR。这是必须的,因为 Sun 的规格说明 JAR 文件并没有使用一个允许再次
分发的许可证。 很多年来编写一个 Servlet 或者使用 JDBC 之前你必须手工下载 Sun
的构件。 这很乏味并且令人恼火,直到 Apache Geronimo 项目创建了很多通过 Sun
认证的企业级规格说明实现。 这些规格说明 JAR 是按照 Apache 软件许可证版本 2.0
发布的,该许可证允许对源代码和二进制文件进行免费的再次分发。 现在,对你的程
序来说,从 Sun Microsystems 下载的 Servlet API JAR 和从 Apache Geronimo 项目
下载的 JAR 没什么大的差别。 它们同样都通过了 Sun Microsystems 的严格的一个测
试兼容性工具箱(TCK)。
添加像 JSP API 或者 Servlet API 这样的依赖现在很简单明了了,不再需要你从 web
站点手工下载 JAR 文件然后再安装到本地仓库。 关键是你必须知道去哪里找,使用
什么 groupId, artifactId, 和 version 来引用恰当的 Apache Geronimo 实现。给
pom.xml 添加如下的依赖元素以添加对 Servlet 规格说明 API 的依赖。.
72
多模块企业级项目
[INFO] ------------------------------------------------------------------------
[INFO] Building Chapter 7 Simple Command Line Tool
[INFO] task-segment: [assembly:assembly] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:testCompile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [surefire:test]
...
[INFO] [jar:jar]
[INFO] Building jar: .../simple-parent/simple-command/target/simple-command.jar
[INFO] [assembly:assembly]
[INFO] Processing DependencySet (output=)
[INFO] Expanding: .../.m2/repository/.../simple-weather-1-SNAPSHOT.jar into
/tmp/archived-file-set.93251
[INFO] Expanding: .../.m2/repository/.../simple-model-1-SNAPSHOT.jar into
/tmp/archived-file-set.20124
[INFO] Expanding: .../.m2/repository/../hibernate-3.2.5.ga.jar into
/tmp/archived-file-set.12965
... skipping 25 lines of dependency unpacking ...
[INFO] Expanding: .../.m2/repository/.../velocity-1.5.jar into /tmp/archived-file-se
[INFO] Expanding: .../.m2/repository/.../commons-lang-2.1.jar into
/tmp/archived-file-set.13292
[INFO] Expanding: .../.m2/repository/.../oro-2.0.8.jar into /tmp/archived-file-set.1
[INFO] Building jar: .../simple-parent/simple-command/target/simple-command-jar-with
构建过程经过了生命周期中编译字节码,运行测试,然后最终为该项目构建一个JAR。
然后assembly:assembly目标创建一个带有依赖的JAR,它将所有依赖解压到一个临时
目录,然后将所有字节码收集到target/目录下一个名为simple-command-jar-with-
dependencies.jar的JAR中。这个“超级的”JAR的体重为15MB。
在你运行这个命令行工具之前,你需要调用Hibernate3插件的hbm2ddl目标来创建
HSQLDB数据库。在simple-command目录运行如下的命令:
$ mvn hibernate3:hbm2ddl
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'hibernate3'.
[INFO] org.codehaus.mojo: checking for updates from central
[INFO] ------------------------------------------------------------------------
[INFO] Building Chapter 7 Simple Command Line Tool
127
144.
多模块企业级项目
[INFO] task-segment: [hibernate3:hbm2ddl]
[INFO] ------------------------------------------------------------------------
[INFO] Preparing hibernate3:hbm2ddl
...
10:24:56,151 INFO org.hibernate.tool.hbm2ddl.SchemaExport - export complete
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
在此之后,你应该能在simple-command下看到data/目录。该data/目录包含了HSQLDB数
据库。要运行这个命令行天气预报器,在simple-command/项目目录下运行如下命令:
$ java -cp target/simple-command-jar-with-dependencies.jar
org.sonatype.mavenbook.weather.Main 60202
2321 INFO YahooRetriever - Retrieving Weather Data
2489 INFO YahooParser - Creating XML Reader
2581 INFO YahooParser - Parsing XML Response
2875 INFO WeatherFormatter - Formatting Weather Data
****************************************
Current Weather Conditions for:
Evanston,
IL,
US
****************************************
* Temperature: 75
* Condition: Partly Cloudy
* Humidity: 64
* Wind Chill: 75
* Date: Wed Aug 06 09:35:30 CDT 2008
要运行历史查询,运行如下命令:
$ java -cp target/simple-command-jar-with-dependencies.jar
org.sonatype.mavenbook.weather.Main 60202 history
2470 INFO WeatherFormatter - Formatting History Data
Weather History for:
Evanston, IL, US
****************************************
* Temperature: 39
* Condition: Heavy Rain
* Humidity: 93
* Wind Chill: 36
* Date: 2007-12-02 13:45:27.187
****************************************
128
优化和重构POM
[INFO] Chapter 8 Simple Parent Project
[INFO] Chapter 8 Simple Object Model
[INFO] Chapter 8 Simple Weather API
[INFO] Chapter 8 Simple Persistence API
[INFO] Chapter 8 Simple Command Line Tool
[INFO] Chapter 8 Simple Web Application
[INFO] Chapter 8 Parent Project
[INFO] Searching repository for plugin with prefix: 'dependency'.
...
[INFO] ------------------------------------------------------------------------
[INFO] Building Chapter 8 Simple Object Model
[INFO] task-segment: [dependency:analyze]
[INFO] ------------------------------------------------------------------------
[INFO] Preparing dependency:analyze
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:testCompile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [dependency:analyze]
[WARNING] Used undeclared dependencies found:
[WARNING] javax.persistence:persistence-api:jar:1.0:compile
[WARNING] Unused declared dependencies found:
[WARNING] org.hibernate:hibernate-annotations:jar:3.3.0.ga:compile
[WARNING] org.hibernate:hibernate:jar:3.2.5.ga:compile
[WARNING] junit:junit:jar:3.8.1:test
...
[INFO] ------------------------------------------------------------------------
[INFO] Building Chapter 8 Simple Web Application
[INFO] task-segment: [dependency:analyze]
[INFO] ------------------------------------------------------------------------
[INFO] Preparing dependency:analyze
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
138
站点生成
15.3. 自定义站点描述符
当你为站点添加内容的时候,你会想要修改站点左边的导航菜单。以下的站点描述符定
制了站点左上角的logo。除了站点的顶部,该描述符还为左边的导航菜单添加了一个菜
单小节"Sample Project"。该菜单包含了一个指向概述页面的链接。
例 15.1. 一个初始的站点描述符
<project name="Sample Project">
<bannerLeft>
<name>Sonatype</name>
<src>images/logo.png</src>
<href>http://www.sonatype.com</href>
</bannerLeft>
<body>
<menu name="Sample Project">
<item name="Overview" href="index.html"/>
</menu>
<menu ref="reports"/>
</body>
</project>
该站点描述符引用了一个图片。该图片logo.png应该放在/usr/local/hudson/hudson-
home/jobs/maven-guide-zh-to-production/workspace/content-zh/src/site/resources/
images目录下。除了更改站点描述符,你还会想要在/usr/local/hudson/hudson-home/
jobs/maven-guide-zh-to-production/workspace/content-zh/src/site/apt目录下创建一
个简单的index.apt页面。将以下的内容写入index.apt,它会被转化成index.html,当
用户访问Maven生成的站点时,他们就会看到这第一个页面。
Welcome to the Sample Project, we hope you enjoy your time
on this project site. We've tried to assemble some
great user documentation and developer information, and
we're really excited that you've taken the time to visit
this site.
What is Sample Project
Well, it's easy enough to explain. This sample project is
a sample of a project with a Maven-generated site from
Maven: The Definitive Guide. A dedicated team of volunteers
help maintain this sample site, and so on and so forth.
要预览该站点,运行mvn clean site,接着mvn site:run:
$ mvn clean site
331
站点生成
• FML参考: http://maven.apache.org/doxia/references/fml-format.html
15.5.1. APT样例
例 15.5 “APT文档”展示了一个简单的APT文档,它带有一段介绍文字和一个简单列
表。注意列表通过伪元素“[]”结束。
例 15.5. APT文档
---
Introduction to Sample Project
---
Brian Fox
---
26-Mar-2008
---
Welcome to Sample Project
This is a sample project, welcome! We're excited that you've decided to read the
index page of this Sample Project. We hope you enjoy the simple sample project
we've assembled for you.
Here are some useful links to get you started:
* {{{news.html}News}}
* {{{features.html}Features}}
* {{{faq.html}FAQ}}
[]
如果例 15.5 “APT文档”中的APT文档位于src/site/apt/index.apt,Maven Site插件
就会使用Doxia解析该APT,生成对应于index.html的XHTML文档。
15.5.2. FML样例
很多项目维护一个常见问题(FAQ)页面。例 15.6 “FAQ标记语言文档”展示了一个
FML文档的例子:
336
353.
站点生成
例 15.6. FAQ标记语言文档
<?xml version="1.0" encoding="UTF-8"?>
<faqs title="Frequently Asked Questions">
<part id="General">
<faq id="sample-project-sucks">
<question>Sample project doesn't work. Why does sample project suck?</questio
<answer>
<p>
We resent that question. Sample wasn't designed to work, it was designed
show you how to use Maven. Is you really think this project sucks, then
keep it to yourself. We're not interested in your pestering questions.
</p>
</answer>
</faq>
<faq id="sample-project-source">
<question>I want to put some code in Sample Project, how do I do this?</questi
<answer>
<p>
If you want to add code to this project, just start putting Java source in
src/main/java. If you want to put some source code in this FAQ, use the
source element:
</p>
<source>
for( int i = 0; i < 1234; i++ ) {
// do something brilliant
}
</source>
</answer>
</faq>
</part>
</faqs>
15.6. 部署你的项目web站点
一旦项目文档已经写好,并且你已经创建了一个引以为傲的站点,你会想将其部署
到服务器上。要部署你的站点,你需要使用Maven Site插件,它会使用很多种方法如
FTP,SCP,和DAV,将你的项目站点部署到远程服务器上。要使用DAV部署站点,在POM
中配置distributionManagement小节的site元素,如:
337
使用可选语言编写插件
例 18.6. 从Ruby Mojo中引用MavenProject对象
# Thisis a mojo description
# @goal test
# @phase validate
class Test < Mojo
# @parameter type="java.lang.String" default-value="nothing" alias="a_string"
def prop
end
# @parameter type="org.apache.maven.project.MavenProject" expression="${project}"
# @required true
def project
end
def execute
info "The following String was passed to prop: '#{$prop}'"
info "My project artifact is: #{$project.artifactId}"
end
end
run_mojo Test
在前面的例子中,我们可以使用标准的Ruby语法访问Project类的属性。如果你将
test.rb放到firstruby-maven-plugin的src/main/scripts目录,然后install这个插
件,接着运行它,你会看到如下的输出:
$ mvn install
...
[INFO] [plugin:descriptor]
[INFO] Using 3 extractors.
[INFO] Applying extractor for language: java
...
[INFO] Applying extractor for language: jruby
[INFO] Ruby Mojo File: /echo.rb
[INFO] Ruby Mojo File: /test.rb
[INFO] Extractor for language: jruby found 2 mojo descriptors.
...
$ mvn firstruby:test
...
[INFO] [firstruby:test]
[INFO] The following String was passed to prop: 'nothing'
[INFO] My project artifact is: firstruby-maven-plugin
433
450.
使用可选语言编写插件
18.3.3. Ruby Mojo中使用日志
要在Ruby Mojo中使用日志,调用info(), debug(), 和error()方法,并传入日志信息
参数。
# Tests Logging
# @goal logtest
# @phase validate
class LogTest < Mojo
def execute
info "Prints an INFO message"
error "Prints an ERROR message"
debug "Prints to the Console"
end
end
run_mojo LogTest
18.3.4. Raise一个MojoError
如果在一个Ruby Mojo中有一个未发现的错误,你就需要raise一个MojoError。例 18.7
“在Ruby Mojo中raise一个MojoError”展示了如何raise一个MojoError。例子中的
mojo首先打印了一条日志信息,然后raise一个MojoError。
434
451.
使用可选语言编写插件
例 18.7. 在Ruby Mojo中raise一个MojoError
# Prints a Message
# @goal error
# @phase validate
class Error < Mojo
# @parameter type="java.lang.String" default-value="Hello Maven World" expression=
# @required true
# @readonly false
# @deprecated false
def message
end
def execute
info $message
raise MojoError.new( "This Mojo Raised a MojoError" )
end
end
run_mojo Error
运行该Mojo,会产生如下的输出:
$ mvn firstruby:error
...
INFO] [firstruby:error]
[INFO] Hello Maven World
[ERROR] This Mojo Raised a MojoError
18.3.5. 在JRuby中引用Plexus组件
Ruby Mojo可以依赖于一个Plexus组件。为此,你需要使用@parameter注解的
expression参数,在这里为Plexus指定role和hint。下面的例子中,Ruby Mojo依赖于
Archiver组件,Maven会据此从Plexus获取该组件。
435
452.
使用可选语言编写插件
例 18.8. 在Ruby Mojo中依赖于一个Plexus组件
# This mojo tests plexus integration
# @goal testplexus
# @phase validate
class TestPlexus < Mojo
# @parameter type="org.codehaus.plexus.archiver.Archiver"
expression="${component.org.codehaus.plexus.archiver.Archiver#zip}"
def archiver
end
def execute
info $archiver
end
end
run_mojo TestPlexus
请注意Ruby Mojo注解的属性不能跨越多行。如果你要运行该目标,你会看到Maven将根
据role:org.codehaus.plexus.archiver.Archiver和hit:zip尝试从Plexus获取一个
组件。
18.4. 使用Groovy编写插件
Groovy是一个基于Java虚拟机的动态语言,它最终也被编译成Java字节码。Groovy
是Codehaus社区的项目。如果你十分熟悉Java,Groovy就会是一种很自然的脚本语
言。Groovy使用了Java的很多特性,同时进行了略微的裁剪,并加入了一些新特性,
如闭包(closure),鸭子类型判断(duck-typing),和正则表达式。要了解更多的关于
Groovy的信息,可以访问Groovy的站点:http://groovy.codehaus.org。
18.4.1. 创建一个Groovy插件
要使用Groovy创建一个Maven插件,你只需要两个文件:一个pom.xml和一个用Groovy实
现的Mojo。首先,创建一个名为firstgroovy-maven-plugin的项目目录,然后在该目录
下创建如下的pom.xml文件:
436