zoukankan      html  css  js  c++  java
  • Maven使用入门

    编写POM

    像Make的Makefile、Ant的build.xml一样,Maven项目的核心是pom.xml。POM(Project Object Model,项目对象模型)定义了项目的基本信息,用于描述项目如何构建,声明项目依赖,等等。现在先为Hello World项目编写一个简单的pom.xml文件。

    首先,创建一个名为hello-world的文件夹,并在该文件夹下创建一个名为pom.xml的文件,并输入如下内容:

    <?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>4.0.0</modelVersion>
      <groupId>com.juvenxu.mvnbook</groupId>
      <artifactId>hello-world</artifactId>
      <version>1.0-SNAPSHOT</version>
      <name>Maven Hello World Project</name>
    </project>  
    

      

    代码的第一行是XML头,指定了该xml文档的版本和编码方式。紧接着是project元素,project是所有pom.xml的根元素,它还声明了一些POM相关的命名空间及xsd元素,虽然这些属性不是必须,但使用这些属性可以让第三方工具(如IDE中的XML编辑器)帮助我们快速编辑POM。

    根元素的第一个子元素modelVersion指定了当前POM模型的版本,对于Maven2及Maven3来说,它只能是4.0.0。

    这段代码最重要的事包含了groupId、artifactId、version的三行。这三个元素定义了一个项目的基本坐标,在Maven的世界,任何的jar、pom或者war都是基于这些基本的坐标来区分的。

    groupId定义了项目属于哪个组,这个组往往和项目所在的组织或者公司存在关联。比如,在goolecode上建立一个名为myapp的项目,那么groupId就应该是com.googlecode.myapp,如果你的公司是mycom,有一个项目为myapp,那么groupId就应该是com.mycom.myapp。

    artifactId定义了当前Maven项目在组中唯一的ID,我们为这个Hello World项目定义artifactId为hello-world。

    version指定了Hello World项目当前的版本:1.0-SNAPSHOT。SNAPSHOT意为快照,说明该项目还处于开发中,是不稳定的版本。

    最后一个name元素声明了一个对于用户更为友好的项目名称,虽然不是必须,但还是推荐为每个POM声明name,以方便信息交流。

    编写主代码

    项目的主代码和测试代码不同,项目的主代码会被打包到最终的构件中(如:jar),而测试代码只在运行测试用例时用到,不会被打包。默认情况下,Maven假设项目主代码位于src/main/java目录,我们遵循Maven的约定,创建该目录,然后在该目录下创建com/juvenxu/mvnbook/helloworld/HelloWorld.java,其内容如下:

    package com.juvenxu.mvnbook.helloworld;
    
    public class HelloWorld {
        public String sayHello() {
            return "Hello Maven";
        }
    
        public static void main(String[] args) {
            System.out.println(new HelloWorld().sayHello());
        }
    }
    

      

    这是一个简单的Java类,它有一个sayHello()方法,返回String。同时这个类还带有一个main方法,创建一个HelloWorld实例,调用sayHello()方法,并将结果输出在控制台。

    关于该Java代码有两点需要注意,在绝大数情况下,应该把项目的主代码放到/src/main/java目录下(遵循Maven的约定),而无须额外的配置,Maven会自动搜索该目录找到项目主代码。其次,Java类的包名是com.juvenxu.mvnbook.helloworld,这与之前在POM中定义的groupId和artifactId相吻合。一般来说,项目中的Java类的包都应该基于项目的groupId和artifactId,这样更清晰,更符合逻辑,也方便搜索构件或者Java类。

    代码编写完毕后,使用Maven进行编译,在项目根目录下运行mvn clean compile会得到如下输出:

    D:D学习maven_demohello-world>mvn clean compile
    [INFO] Scanning for projects...
    [INFO]
    [INFO] ------------------< com.juvenxu.mvnbook:hello-world >-------------------
    [INFO] Building Maven Hello World Project 1.0-SNAPSHOT
    [INFO] --------------------------------[ jar ]---------------------------------
    [INFO]
    [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ hello-world ---
    [INFO]
    [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello-world ---
    [WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory D:D学习maven_demohello-worldsrcmain
    esources
    [INFO]
    [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hello-world ---
    [INFO] Changes detected - recompiling the module!
    [WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent!
    [INFO] Compiling 1 source file to D:D学习maven_demohello-world	argetclasses
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    

      

    clean告诉Maven清理输出目录target/,compile告诉Maven编译项目主代码,从输出中看到Maven首先执行了clean任务,删除target/目录。默认情况下,Maven构建的所有输出都在target/目录中;接着执行resource任务,由于我没有定义项目资源,暂时略过。最后执行compile任务,将项目主代码编译至target/classes目录,编译好的类为com/juvenxu/mvnbook/helloworld/HelloWorld.class。

    之前提到clean、resource、compile对应了一些Maven的插件及插件目标,比如clean是clean插件的clean目标,compile是compiler插件的compile目标。至此,Maven在没有任何额外配置的情况下就执行了项目的清理和编译任务。接下来,编写一些单元测试代码并让Maven执行自动化测试。

    编写测试代码

    为了使项目结构保持清晰,主代码和测试代码应该分别于独立的目录中,之前说过Maven默认主代码目录是/src/main/java,对应地,Maven项目中默认的测试代码目录是/src/test/java。因此,在编写测试用例前,应当先创建该目录。

    在Java世界中,JUnit是单元测试的标准。要使用JUnit,首先要为Hello World项目添加一个JUnit依赖,修改项目的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>4.0.0</modelVersion>
        <groupId>com.juvenxu.mvnbook</groupId>
        <artifactId>hello-world</artifactId>
        <version>1.0-SNAPSHOT</version>
        <name>Maven Hello World Project</name>
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.7</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </project>
    

      

    代码中添加了dependencies元素,该元素下可以包含多个dependency元素以声明项目的依赖。这里添加了一个依赖——groupId是juint,artifactId是juint,version是4.7。前面提到的groupId、artifactId和version是任何一个Maven项目最基本的坐标,JUnit也不例外,有了这段声明,Maven就能够自动下载junit-4.7.jar。也许你会问,Maven从哪里下载这个jar包呢?在Maven之前,可以去JUnit的官网下载分发包,有了Maven,它会自动访问中央仓库,下载需要的文件。

    上述的POM代码还有一个值为test的元素scope,scope为依赖范围,若以来范围为test则表示该依赖只对测试有效。换句话说,在测试代码引用JUnit代码是没有问题的,按如果在主代码引用JUnit,就会造成编译错误。如果不声明依赖范围,默认就是compile,表示该依赖对主代码和测试代码都有效。

    配置了测试依赖,接着就可以编写测试类。回顾一下前面的HelloWorld类,现在要测试该类的sayHello()方法,检查返回值是否为"Hello Maven"。在src/test/java目录下创建文件:

    package com.juvenxu.mvnbook.helloworld;
    
    import static org.junit.Assert.assertEquals;
    import org.junit.Test;
    
    import com.juvenxu.mvnbook.helloworld.HelloWorld;
    
    public class HelloWorldTest
    {
        @Test
        public void testSayHello()
        {
            HelloWorld helloWorld = new HelloWorld();
    
            String result = helloWorld.sayHello();
    
            assertEquals( "Hello Maven", result );
        }
    }
    

      

    测试用例编写完毕之后就可以调用Maven进行测试,运行mvn clean test命令:

    D:D学习maven_demohello-world>mvn clean test
    [INFO] Scanning for projects...
    [INFO]
    [INFO] ------------------< com.juvenxu.mvnbook:hello-world >-------------------
    [INFO] Building Maven Hello World Project 1.0-SNAPSHOT
    [INFO] --------------------------------[ jar ]---------------------------------
    [INFO]
    [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ hello-world ---
    [INFO] Deleting D:D学习maven_demohello-world	arget
    [INFO]
    [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello-world ---
    [WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory D:D学习maven_demohello-worldsrcmain
    esources
    [INFO]
    [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hello-world ---
    [INFO] Changes detected - recompiling the module!
    [WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent!
    [INFO] Compiling 1 source file to D:D学习maven_demohello-world	argetclasses
    [INFO]
    [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello-world ---
    [WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory D:D学习maven_demohello-worldsrc	est
    esources
    [INFO]
    [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ hello-world ---
    [INFO] Changes detected - recompiling the module!
    [WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent!
    [INFO] Compiling 1 source file to D:D学习maven_demohello-world	arget	est-classes
    [INFO]
    [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hello-world ---
    [INFO] Surefire report directory: D:D学习maven_demohello-world	argetsurefire-reports
    
    -------------------------------------------------------
     T E S T S
    -------------------------------------------------------
    Running com.juvenxu.mvnbook.helloworld.HelloWorldTest
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.032 sec
    
    Results :
    
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
    
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    

      

    可以看到Maven实际上执行的不止两个任务,有clean、resource、compile、testResource、testCompile。暂时需要了解的是,在Maven执行测试(test)之前,它会先自动执行项目主资源处理、主代码编译、测试资源处理、测试代码编译等工作,这是Maven生命周期的一个特性,后面还会详细介绍Maven的生命周期。

    我们看到testCompile任务执行成功,测试代码在通过编译之后在target/test-classes下生成二进制文件,紧接着test任务运行测试,surefire是Maven中负责执行测试的插件,这里它运行测试用例HelloWorldTest,并且输出测试报告,显示一共运行了多少测试,失败了多少,出错了多少,跳过了多少。显然,我们的测试是通过的。

    打包和运行

    将项目进行编译、测试之后,下一个重要的步骤就是打包(package)。Hello World的POM中没有指定打包类型,使用默认打包类型jar。简单地执行mvn clean package进行打包,可以看到如下输出:

    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
    
    [INFO]
    [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello-world ---
    [INFO] Building jar: D:D学习maven_demohello-world	argethello-world-1.0-SNAPSHOT.jar
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    

      

    类似地,Maven会在打包之前执行编译、测试等操作。这里看到jar任务负责打包,实际上就是jar插件的jar目标将项目主代码打包成一个名为hello-world-1.0-SNAPSHOT.jar的文件。该文件也位于target/输出目录中,它是根据artifact-version.jar规则进行命名的,如有需要,还可以使用finalName来自定义该文件名称,这里先不展开,后面再详细解释。

    至此,我们得到项目的输出,如果有需要的话,可以复制这个jar文件到其他项目的Classpath中从而使用HelloWorld类。但是,如何才能让其他的Maven项目直接引用这个jar呢?还需要一个安装步骤,执行mvn clean install:

    [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello-world ---
    [INFO] Building jar: D:D学习maven_demohello-world	argethello-world-1.0-SNAPSHOT.jar
    [INFO]
    [INFO] --- maven-install-plugin:2.4:install (default-install) @ hello-world ---
    [INFO] Installing D:D学习maven_demohello-world	argethello-world-1.0-SNAPSHOT.jar to D:Fworkjavamaven_repositorycomjuvenxumvnbookhello-world1.0-SNAPSHOThello-world-1.0-SNAPSHOT.jar
    [INFO] Installing D:D学习maven_demohello-worldpom.xml to D:Fworkjavamaven_repositorycomjuvenxumvnbookhello-world1.0-SNAPSHOThello-world-1.0-SNAPSHOT.pom
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    

      

    打包之后又执行安装任务install,从输出可以看到该任务将项目输出的jar安装到maven本地仓库中,可以打开相应的文件夹看到Hello World项目的pom和jar。之前讲述的JUnit的POM及jar的下载的时候,我们说只有构件被下载到本地仓库后,才能由所有Maven项目使用,同样的道理,之后将Hello World的构件安装到本地仓库后,其他Maven项目才能使用它。

    我们已经体验了Maven最主要的命令:mvn clean compile、mvn clean test、mvn clean package、mvn clean install。执行test之前会执行compile,执行package会执行test,类似地,install之前会执行package。

    到目前为止,我们还没运行Hello World项目,不要忘了HelloWorld类可是有一个main方法。默认打包生成的jar是不能直接运行的,因为带有main方法的类信息不会添加到manifest中(打开jar文件中的META-INF/MANIFEST.MF文件,将无法看到Main-Class一行)。为了生成可执行的jar文件,需要借助maven-shade-plugin,配置该插件如下:

      <plugin>
    	<groupId>org.apache.maven.plugins</groupId>
    	<artifactId>maven-shade-plugin</artifactId>
    	<version>1.2.1</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:D学习maven_demohello-world>java -jar targethello-world-1.0-SNAPSHOT.jar
    Hello Maven
    

      

    控制台所输出的Hello Maven,正是我们所期望的。

    使用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也只会解析最新的稳定版本,因此这是安全的。 我们实际上是在运行插件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 property 'groupId': com.juvenxu.mvnbook
    Define value for property 'artifactId': hello-world
    Define value for property 'version' 1.0-SNAPSHOT: :
    Define value for property 'package' com.juvenxu.mvnbook: :
    Confirm properties configuration:
    groupId: com.juvenxu.mvnbook
    artifactId: hello-world
    version: 1.0-SNAPSHOT
    package: com.juvenxu.mvnbook
     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。

  • 相关阅读:
    巧用css实现强制不换行、自动换行、强制换行(转)
    解决IE6最后一行文字溢出
    CSS控制透明度
    中兴ZTEU880刷机
    ADO.NET Entity Framework AtaGlance
    低版本的IE浏览器position:relative跟随滚动条滚动解决方案
    ObjectARX ads_point 和AcGePoint3d 的转化
    ObjectARX代码片段三
    创建AcDb2dPolyline实体
    数据库处理
  • 原文地址:https://www.cnblogs.com/beiluowuzheng/p/12740261.html
Copyright © 2011-2022 走看看