Learning Maven 1 - Basic Introduction

来源:互联网 发布:淘宝鞋子店铺推荐 编辑:程序博客网 时间:2024/05/17 02:18


一、 maven常用的一些自动产生的模板

1. Java普通工程

mvn archetype:generate \-DgroupId=com.ftcl.weather \-DartifactId=simpleWeather \-Dversion=1.0 \-DarchetypeArtifactId=maven-archetype-quickstart \-DinteractiveMode=false


2.Java Web工程

mvn archetype:generate \-DgroupId=com.audi.automobile \-DartifactId=trucks \-Dversion=1.0 \-DarchetypeArtifactId=maven-archetype-webapp \-DinteractiveMode=false


参数说明:

groupId: 包的名字

artifactId:工程的名字

verson:版本号(产生jar文件)

archetypeArtifactId: 产生的应用的类型,如java普通工程,java Web工程等

interactiveMode: 是否为交互模式

其中前三个参数构成了Maven构建的工程的Coordinates。


手动添加依赖jar到本地仓库中:

mvn install:install-file  -Dfile=path/to/your/jar \ -DgroupId=net.sourceforge.pinyin4j \ -DartifactId=pinyin4j \ -Dversion=2.5.0 \ -Dpackaging=jar \ -DgeneratePom=true \ -DcreateChecksum=true


maven web项目从resources中获得输入流、输出流等:

InputStream is = CurrentClass.class.getResourceAsStream("res.txt");InputStream is = ClassLoader.getSystemResourceAsStream("res.txt"); // getResourceAsStream("res.txt")URL url = CurrentClass.class.getClassLoader().getResource("");// url.getProtocol()                                                                                          String pathToTheFile = url.getPath();




二、常用插件及其目标    plugin:goal

mvn compile

mvn package

mvn install

mvn install assembly:assembly

mvn help:effective-pom

mvn help:describe -Dplugin=exec -Dfull        //a full description of the Exec plugin

mvn dependency:resolve                              //dependency lists

mvn dependency:tree                                   //entire dependency tree of a project

mvn exec:java ...


这些可能涉及多个phrase,与maven的lifecycle息息相关。


三、A General Java Application Example

这个主要用的是assembly插件,把工程中所有的依赖打包成jar文件(或war文件)。

下面以一个完整的例子说明吧。


1.产生maven模板工程

mvn archetype:generate \-DgroupId=org.ftcl.weather \-DartifactId=simpleWeather \-Dversion=1.0 \-DarchetypeArtifactId=maven-archetype-quickstart \-DinteractiveMode=false
现在已经产生了一个maven Java工程,即maven标准的目录结构。工程名字为simpleWeather,包的名字为org.ftcl.weather,这个包里面有一个App.java的示例java文件。有一个简单的pom.xml POM。这个是关键。

产生的原始pom.xml为:

<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>org.ftcl</groupId>  <artifactId>simpleWeather</artifactId>  <version>1.0-SNAPSHOT</version>  <packaging>jar</packaging>  <name>simpleWeather</name>  <url>http://maven.apache.org</url>  <properties>    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  </properties>  <dependencies>    <dependency>      <groupId>junit</groupId>      <artifactId>junit</artifactId>      <version>3.8.1</version>      <scope>test</scope>    </dependency>  </dependencies></project> 

2.Configure the Maven Compiler plugin

We need to configure the Maven Compiler plugin to target Java 6. To do this, add the build element to the initial POM.

添加后如下:

。。。  </dependencies>  <build>    <plugins>      <plugin>        <artifactId>maven-compiler-plugin</artifactId>        <configuration>          <source>1.6</source>          <target>1.6</target>        </configuration>      </plugin>    </plugins>  </build></project> 


3. Add New Dependencies

Adding Dom4J, Jaxen, Velocity, and Log4J as Dependencies:

We can access http://mvnrepository.com/ to searche these dependencies(Strongly recommended).

<project> [...]  <dependencies>    <dependency>      <groupId>log4j</groupId>      <artifactId>log4j</artifactId>      <version>1.2.16</version>    </dependency>    <dependency>      <groupId>dom4j</groupId>      <artifactId>dom4j</artifactId>      <version>1.6.1</version>    </dependency>    <dependency>      <groupId>jaxen</groupId>      <artifactId>jaxen</artifactId>      <version>1.1.4</version>    </dependency>    <dependency>      <groupId>velocity</groupId>      <artifactId>velocity</artifactId>      <version>1.5</version>    </dependency>    <dependency>      <groupId>junit</groupId>      <artifactId>junit</artifactId>      <version>3.8.1</version>      <scope>test</scope>    </dependency>  </dependencies> [...]</project>

4. Simple Weather Source Code

org.ftcl.weather.Main

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)        String zipcode = "02101";        try {          zipcode = args[0];        } catch( Exception e ) {}        // Start the program        new Main(zipcode).start();    }    private String zip;    public Main(String 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 ) );    }}

org.ftcl.weather.Weather

package org.ftcl.weather;public class Weather {    private String city;    private String region;    private String country;    private String condition;    private String temp;    private String chill;    private String humidity;        public Weather() {}    public String getCity() { return city; }                                                                                                                             public void setCity(String city) { this.city = city; }    public String getRegion() { return region; }    public void setRegion(String region) { this.region = region; }    public String getCountry() { return country; }    public void setCountry(String country) { this.country = country; }    public String getCondition() { return condition; }    public void setCondition(String condition) { this.condition = condition; }    public String getTemp() { return temp; }    public void setTemp(String temp) {  this.temp = temp; }    public String getChill() { return chill; }    public void setChill(String chill) { this.chill = chill; }    public String getHumidity() { return humidity; }    public void setHumidity(String humidity) { this.humidity = humidity; }}


org.ftcl.weather.YahooRetriever

package org.ftcl.weather;                                                                                                                                            import java.io.InputStream;import java.net.URL;import java.net.URLConnection;import org.apache.log4j.Logger;public class YahooRetriever {    private static Logger log = Logger.getLogger(YahooRetriever.class);    public InputStream retrieve(String zipcode) throws Exception {        log.info( "Retrieving Weather Data" );        String url = "http://weather.yahooapis.com/forecastrss?p=" + zipcode;        URLConnection conn = new URL(url).openConnection();        return conn.getInputStream();    }}


org.ftcl.weather.YahooParser

package org.ftcl.weather;                                                                                                                                            import java.io.InputStream;import java.util.HashMap;import java.util.Map;import org.apache.log4j.Logger;import org.dom4j.Document;import org.dom4j.DocumentFactory;import org.dom4j.io.SAXReader;public class YahooParser {    private static Logger log = Logger.getLogger(YahooParser.class);    public Weather parse(InputStream inputStream) throws Exception {        Weather weather = new Weather();        log.info( "Creating XML Reader" );        SAXReader xmlReader = createXmlReader();        Document doc = xmlReader.read( inputStream );        log.info( "Parsing XML Response" );        weather.setCity( doc.valueOf("/rss/channel/y:location/@city") );        weather.setRegion( doc.valueOf("/rss/channel/y:location/@region") );        weather.setCountry( doc.valueOf("/rss/channel/y:location/@country") );        weather.setCondition( doc.valueOf("/rss/channel/item/y:condition/@text") );        weather.setTemp( doc.valueOf("/rss/channel/item/y:condition/@temp") );        weather.setChill( doc.valueOf("/rss/channel/y:wind/@chill") );        weather.setHumidity( doc.valueOf("/rss/channel/y:atmosphere/@humidity") );                return weather;    }    private SAXReader createXmlReader() {        Map<String,String> uris = new HashMap<String,String>();        uris.put( "y", "http://xml.weather.yahoo.com/ns/rss/1.0" );        DocumentFactory factory = new DocumentFactory();        factory.setXPathNamespaceURIs( uris );        SAXReader xmlReader = new SAXReader();        xmlReader.setDocumentFactory( factory );        return xmlReader;    }}


org.ftcl.weather.WeatherFormatter

package org.ftcl.weather;                                                                                                                                            import java.io.InputStreamReader;import java.io.Reader;import java.io.StringWriter;import org.apache.log4j.Logger;import org.apache.velocity.VelocityContext;import org.apache.velocity.app.Velocity;public class WeatherFormatter {    private static Logger log = Logger.getLogger(WeatherFormatter.class);    public String format( Weather weather ) throws Exception {        log.info( "Formatting Weather Data" );        Reader reader = new InputStreamReader( getClass().getClassLoader().getResourceAsStream("output.vm"));        VelocityContext context = new VelocityContext();        context.put("weather", weather );        StringWriter writer = new StringWriter();        Velocity.evaluate(context, writer, "", reader);        return writer.toString();    }}


这些文件可在<maven-definitive-guide>找到源代码。


5.Add Resources

[songguo@songuo simpleWeather]$ mkdir src/main/resources

Add the log4j.properties and output.vm files in the resources directory.

log4j.properties

# Set root category priority to INFO and its only appender to CONSOLE.log4j.rootCategory=INFO, CONSOLE# Set the enterprise logger category to FATAL and its only appender to CONSOLE.#log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE# CONSOLE is set to be a ConsoleAppender using a PatternLayout.log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppenderlog4j.appender.CONSOLE.Threshold=INFOlog4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayoutlog4j.appender.CONSOLE.layout.ConversionPattern=%-4r %-5p %c{1} %x - %m%n 

output.vm

*********************************                                                                                                                                     Current Weather Conditions for:  ${weather.city}, ${weather.region}, ${weather.country} Temperature: ${weather.temp}   Condition: ${weather.condition}    Humidity: ${weather.humidity}  Wind Chill: ${weather.chill}*********************************


6.Running the Simple Weather Program

mvn installmvn exec:java -Dexec.mainClass=org.sonatype.mavenbook.weather.Main

mvn exec:java -Dexec.mainClass=org.sonatype.mavenbook.weather.Main -Dexec.args="70112"

7. Building a Packaged Command Line Application

This part outlines a process for using a predefined assembly descriptor in the Maven Assembly plugin to produce a distributable JAR file, which contains the project’s bytecode and all of the dependencies.

we're going to use the predefined jar-with-dependencies format. To configure the Maven Assembly Plugin, we need to add the following plugin configuration to our existing build configuration in the pom.xml.

<project> [...]<build>    <plugins>      <plugin>        <artifactId>maven-compiler-plugin</artifactId>        <configuration>          <source>1.6</source>          <target>1.6</target>        </configuration>      </plugin>       <plugin>         <artifactId>maven-assembly-plugin</artifactId>         <configuration>           <descriptorRefs>             <descriptorRef>jar-with-dependencies</descriptorRef>           </descriptorRefs>        </configuration>       </plugin>    </plugins>  </build></project> 


注意,一个<build></build>下只能有一个<plugins></plugins>.

Once you’ve added this configuration, you can build the assembly by running the assembly:assembly goal. In the following screen listing, the assembly:assembly goal is executed after the Maven build reaches the install lifecycle phase:

mvn install assembly:assembly

Once our assembly is assembled in target/simple-weather-1.0-jar-with-dependencies.jar, we can run the Main class again from the command line. To run the simple weather application’s Main class, execute the following commands from your project’s base directory:

cd targetjava -cp simple-weather-1.0-jar-with-dependencies.jar org.sonatype.mavenbook.weather.Main 10002

The jar-with-dependencies format creates a single JAR file that includes all of the bytecode from the simple-weather project as well as the unpacked bytecode from all of the dependencies. This somewhat unconventional format produces a 9 MiB JAR file containing approximately 5,290 classes, but it does provide for an easy distribution format for applications you’ve developed with Maven. Later, I’ll show you how to create a custom assembly descriptor to produce a more standard distribution.


7.1Attaching the Assembly Goal to the Package Phase

The following plugin configuration configures the Maven Assembly plugin to execute the attached goal during the package phase of the Maven default build lifecycle. The attached goal does the same thing as the assembly goal. To bind to assembly:attached goal to the package phase we use the executions element under plugin in the build section of the project's POM.

<project> [...]  <build>    <plugins>      <plugin><artifactId>maven-assembly-plugin</artifactId><configuration>  <descriptorRefs>    <descriptorRef>jar-with-dependencies</descriptorRef>  </descriptorRefs></configuration><executions>  <execution>    <id>simple-command</id>    <phase>package</phase>    <goals>      <goal>attached</goal>    </goals>  </execution></executions>      </plugin>    </plugins> </build>[...]</project>

Once you have this configuration in your POM, all you need to do to generate the assembly is run mvn package. The execution configuration will make sure that the assembly:attached goal is executed when the Maven lifecycle transitions to the package phase of the lifecycle.


四、Defining the Simple Web Application

1.Creating the Simple Web Project



Next, we will need to configure the Maven Compiler plugin to target Java 6. To do this, add the plugins element to the initial POM, same as the above.

 [...]   <groupId>org.ftcl.webapp</groupId>  <artifactId>simpleWweb</artifactId>  <packaging>war</packaging> <build>    <finalName>simpleWeb</finalName>    <plugins>      <plugin>        <artifactId>maven-compiler-plugin</artifactId>        <configuration>          <source>1.6</source>          <target>1.6</target>        </configuration>      </plugin>    </plugins>  </build></project>  


Notice the packaging element contains the value war. This packaging type is what configures Maven to produce a web application archive in a WAR file. A project with war packaging is going to create a WAR file in the target/ directory. The default name of this file is ${artifactId}-${version}.war. In this project, the default WAR would be generated in target/simple-webapp-1.0-SNAPSHOT.war. In the simple-webapp project, we’ve customized the name of the generated WAR file by adding a finalName element inside of this project’s build configuration. With a finalName of simple-webapp, the package phase produces a WAR file in target/simple-webapp.war.


2. Configuring the Jetty Plugin

We can use the Maven Jetty plugin to run your web application within Maven. To do this, we’ll need to configure the Maven Jetty plugin in our project’s pom.xml. Add the plugin element shown in the following example to your project’s
build configuration.

  <build>    <finalName>simpleWeb</finalName>    <plugins>      <plugin>        <artifactId>maven-compiler-plugin</artifactId>        <configuration>          <source>1.6</source>          <target>1.6</target>        </configuration>      </plugin>    <plugin>      <groupId>org.mortbay.jetty</groupId>      <artifactId>maven-jetty-plugin</artifactId>    </plugin>    </plugins>  </build></project>    

Once you've configured the Maven Jetty Plugin in your project's pom.xml, you can then invoke the Run goal of the Jetty plugin to start your web application in the Jetty Servlet container. Run mvn jetty:run from the simpleWeb/ project directory as follows:

mvn jetty:run

After Maven starts the Jetty Servlet container, load the URL http://localhost:8080/simpleWeb/ in a web browser. The simple index.jsp generated by the Archetype is trivial; it contains a second-level heading with the text "Hello World!". Maven expects the document root of the web application to be stored in src/main/webapp. It is in this directory where you will find the index.jsp file, “Contents of src/main/webapp/index.jsp”.

In src/main/webapp/WEB-INF, we will find the smallest possible web application descriptor in web.xml,


3.Adding a Simple Servlet

A web application with a single JSP page and no configured servlets is next to useless. Let’s add a simple servlet to this application and make some changes to the pom.xml and web.xml to support this change. First, we’ll need to create a new package under src/main/java named org.ftcl.webapp.web:

mkdir -p src/main/java/org/ftcl/webapp/webcd src/main/java/org/ftcl/webapp/web

Now create a class named SimpleServlet in SimpleServlet.java, which contains the code shown in the SimpleServlet class:

package org.ftcl.webapp.web;                                                                  import java.io.*;import javax.servlet.*;import javax.servlet.http.*;public class SimpleServlet extends HttpServlet {    public void doGet(HttpServletRequest request,                      HttpServletResponse response)        throws ServletException, IOException {    PrintWriter out = response.getWriter();    out.println( "SimpleServlet Executed" );        out.flush();        out.close();    }}

Our SimpleServlet class is just that: a servlet that prints a simple message to the response’s Writer. To add this servlet to your web application and map it to a request path, add the servlet and servlet-mapping elements shown in the following web.xml to your project’s web.xml file. The web.xml file can be found in src/main/webapp/WEB-INF.

<!DOCTYPE web-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.ftcl.webapp.web.SimpleServlet</servlet-class>  </servlet>  <servlet-mapping>    <servlet-name>simple</servlet-name>    <url-pattern>/simple</url-pattern>  </servlet-mapping></web-app>


Everything is in place to test this servlet; the class is in src/main/java and the web.xml has been updated. Before we launch the Jetty plugin, compile your project by running mvn compile:

mvn compile

The compilation fails because your Maven project doesn't have a dependency on the Servlet API. In the next section, we'll add the Servlet API to this project's POM.


4.Adding J2EE Dependencies

To write a servlet, we’ll need to add the Servlet API as a project dependency. To add the Servlet specification API as a dependency to your project’s POM.

<dependencies>    <dependency>        <groupId>org.jboss.spec.javax.servlet</groupId>        <artifactId>jboss-servlet-api_3.0_spec</artifactId>        <version>1.0.2.Final</version>        <scope>provided</scope>                                                                 </dependency>

It is also worth pointing out that we have used the provided scope for this dependency. This tells Maven that the jar is "provided" by the container and thus should not be included in the war. If you were interested in writing a custom JSP tag for this simple web application, you would need to add a dependency on the JSP 2.0 spec. Use the configuration shown in this example:

<dependency>        <groupId>org.apache.tomcat</groupId>        <artifactId>jsp-api</artifactId>                                                            <version>6.0.35</version>    </dependency>

Once you've added the Servlet specification as a dependency, run mvn clean install followed by mvn jetty:run.

mvn clean installmvn jetty:run

At this point, you should be able to retrieve the output of the SimpleServlet. From the command line, you can use curl to print the output of this servlet to standard output:

curl http://localhost:8080/simpleWeb/simpleSimpleServlet Executed