【Maven笔记3】Maven基础入门案例

本篇通过一个最基础的入门案例,熟悉一下maven最基础的使用方法。

编写POM

maven项目的核心是pom.xml文件,pom定义了项目的基本信息,用于描述项目如何构建,声明项目依赖等等。
这里我们新建一个maven-demo-hello项目,并编写pom依赖:

<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.0modelVersion>

  <groupId>org.examplegroupId>
  <artifactId>maven-demo-helloartifactId>
  <version>1.0-SNAPSHOTversion>
  <packaging>jarpackaging>

  <name>maven-demo-helloname>
  <url>http://maven.apache.orgurl>

  <properties>
    <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
  properties>
project>

在上述pom定义中,最重要的事groupId、artifactId和version,这三个元素定了一个项目的基本坐标,在maven的世界中,任何jar、pom或war都是基于这些基本的坐标进行区分的。

  • groupId定义项目属于哪个组,一般在公司中以公司域名或组织标识组成,比如com.mycom.myapp
  • artifactId定义了当前项目在组中的唯一id,比如在上面例子中定义的是maven-demo-hello
  • version指当前项目的版本,SNAPSHOT标识快照,说明当前项目处于开发中,是不稳定的版本,随着项目迭代,version会不断更新

没有任何实际的Java代码,我们就能够定义一个Maven项目的POM,这体现了Maven的一大优点,它能让项目对象模型最大程度地与实际代码相独立,我们可以称之为解耦,或者正交性。这在很大程度上避免了Java代码和POM代码的相互影响。比如当项目需要升级版本时,只需要修改POM,而不需要更改Java代码;而在POM稳定之后,日常的Java代码开发工作基本不涉及POM的修改。

编写主代码

项目的主代码和测试代码不同,项目主代码会被打包到最终的构件中(比如jar),而测试代码只在运行测试时用到,不会被打包。按照约定,maven主代码一般放在src/main/java目录下,在该目录下创建文件org/example/App.java,内容如下:

package org.example;

/**
 * Hello world!
 *
 */
package org.example;

/**
 * Hello world!
 *
 */
public class App 
{
    public String hello(){return "Hello World";}
    
    public static void main( String[] args )
    {
        System.out.println( new App().hello() );
    }
}

使用maven进行编译,在项目根目录下运行maven命令:mvn clean compile会得到如下输出:

[INFO] Scanning for projects...
[INFO] 
[INFO] --------------------< org.example:maven-demo-hello >--------------------
[INFO] Building maven-demo-hello 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- clean:3.2.0:clean (default-clean) @ maven-demo-hello ---
[INFO] 
[INFO] --- resources:3.3.1:resources (default-resources) @ maven-demo-hello ---
[INFO] skip non existing resourceDirectory /Users/happy/mine-code/maven-demo-hello/src/main/resources
[INFO] 
[INFO] --- compiler:3.11.0:compile (default-compile) @ maven-demo-hello ---
[INFO] Changes detected - recompiling the module! :source
[INFO] Compiling 1 source file with javac [debug target 1.8] to target/classes
[WARNING] 未与 -source 8 一起设置引导类路径
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.006 s
[INFO] Finished at: 2024-01-07T19:36:16+08:00
[INFO] ------------------------------------------------------------------------
  • clean告诉Maven清理输出目录target/
  • compile告诉Maven编译项目主代码
  • 从输出中看到Maven首先执行了clean:clean任务,删除target/目录
  • 默认情况下,Maven构建的所有输出都在target/目录中
  • 接着执行resources:resources任务(未定义项目资源,暂且略过)
  • 最后执行compiler:compile任务,将项目主代码编译至target/classes目录

上文提到的clean:clean、resources:resources和compiler:compile对应了一些Maven插件及插件目标,比如clean:clean是clean插件的clean目标,compiler:compile是compiler插件的compile目标

除了使用maven命令的方式运行maven项目之外,日常开发中使用IDE,可以直接界面上操作即可,如图:
【Maven笔记3】Maven基础入门案例_第1张图片

编写测试代码

Maven项目中默认的测试代码目录是src/test/java,测试代码需要使用到JUnit,这里我们需要引入JUnit的依赖,在pom中添加依赖:

  <dependencies>
    <dependency>
      <groupId>junitgroupId>
      <artifactId>junitartifactId>
      <version>4.13.2version>
      <scope>testscope>
    dependency>
  dependencies>

有了这段依赖,maven自动下载junit包,具体从哪里下载取决于maven配置,一般在企业中会有对应的私服仓库地址

上述POM代码中还有一个值为test的元素scope,scope为依赖范围,若依赖范围为test则表示该依赖只对测试有效。换句话说,测试代码中的import JUnit代码是没有问题的,但是如果在主代码中用import JUnit代码,就会造成编译错误。

如果不声明依赖范围,那么默认值就是compile,表示该依赖对主代码和测试代码都有效。

编写单元测试,代码如下:

package org.example;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

/**
 * Unit test for simple App.
 */
public class AppTest{

    @Test
    public void helloTest(){
        App app = new App();
        String result = app.hello();
        assertEquals("Hello World", result);
    }
}

使用maven命令执行测试,运行:mvn clean test,输出如下:

[INFO] Scanning for projects...
[INFO] 
[INFO] --------------------< org.example:maven-demo-hello >--------------------
[INFO] Building maven-demo-hello 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- clean:3.2.0:clean (default-clean) @ maven-demo-hello ---
[INFO] Deleting /Users/happy/mine-code/maven-demo-hello/target
[INFO] 
[INFO] --- resources:3.3.1:resources (default-resources) @ maven-demo-hello ---
[INFO] skip non existing resourceDirectory /Users/happy/mine-code/maven-demo-hello/src/main/resources
[INFO] 
[INFO] --- compiler:3.11.0:compile (default-compile) @ maven-demo-hello ---
[INFO] Changes detected - recompiling the module! :source
[INFO] Compiling 1 source file with javac [debug target 1.8] to target/classes
[WARNING] 未与 -source 8 一起设置引导类路径
[INFO] 
[INFO] --- resources:3.3.1:testResources (default-testResources) @ maven-demo-hello ---
[INFO] skip non existing resourceDirectory /Users/happy/mine-code/maven-demo-hello/src/test/resources
[INFO] 
[INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ maven-demo-hello ---
[INFO] Changes detected - recompiling the module! :dependency
[INFO] Compiling 1 source file with javac [debug target 1.8] to target/test-classes
[WARNING] 未与 -source 8 一起设置引导类路径
[INFO] 
[INFO] --- surefire:3.1.2:test (default-test) @ maven-demo-hello ---
[INFO] Using auto detected provider org.apache.maven.surefire.junit4.JUnit4Provider
[INFO] 
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running org.example.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.072 s -- in org.example.AppTest
[INFO] 
[INFO] Results:
[INFO] 
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  3.165 s
[INFO] Finished at: 2024-01-07T20:13:30+08:00
[INFO] ------------------------------------------------------------------------

可以看到compiler:testCompile,surefire:test插件运行成功,并输出了测试报告,显示一共运行了多少测试,失败多少,出错了多少,跳过多少。

打包和运行

项目编译、测试都通过之后,下一个重要步骤就是打包(package)。本项目pom中没有指定打包类型,使用默认的打包类型jar。

使用maven命令:mvn clean package 进行打包,输出如下:

[INFO] --- jar:3.3.0:jar (default-jar) @ maven-demo-hello ---
[INFO] Building jar: /Users/happy/mine-code/maven-demo-hello/target/maven-demo-hello-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.015 s
[INFO] Finished at: 2024-01-07T20:24:22+08:00
[INFO] ------------------------------------------------------------------------

类似地,在执行打包之前,会先执行编译、测试等操作,这里看到jar:jar任务负责打包,实际上就是jar插件的jar目标将项目主代码打包成一个名为maven-demo-hello-1.0-SNAPSHOT.jar的文件。

至此,我们拿到了整个项目的输出,可以通过maven命令:mvn clean install 命令将输出的构件安装到本地仓库,这样其他项目也可以使用该构件。在企业中,一般会通过流水线或构建平台等将包发布到企业私有仓库中。

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

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.pluginsgroupId>
        <artifactId>maven-shade-pluginartifactId>
        <version>1.2.1version>
        <executions>
          <execution>
            <phase>packagephase>
            <goals>
              <goal>shadegoal>
            goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <mainClass>
                    org.example.App
                  mainClass>
                transformer>
              transformers>
            configuration>
          execution>
        executions>
      plugin>
    plugins>
  build>

再次运行maven打包命令:mvn clean package,输出如下:

[INFO] --- jar:3.3.0:jar (default-jar) @ maven-demo-hello ---
[INFO] Building jar: /Users/happy/mine-code/maven-demo-hello/target/maven-demo-hello-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- shade:1.2.1:shade (default) @ maven-demo-hello ---
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing /Users/happy/mine-code/maven-demo-hello/target/maven-demo-hello-1.0-SNAPSHOT.jar with /Users/happy/mine-code/maven-demo-hello/target/maven-demo-hello-1.0-SNAPSHOT-shaded.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  3.223 s
[INFO] Finished at: 2024-01-07T20:40:00+08:00
[INFO] ------------------------------------------------------------------------

可以看到maven-demo-hello-1.0-SNAPSHOT.jar和original-maven-demo-hello-1.0-SNAPSHOT.jar,前者是带有Main-Class信息的可运行jar,后者是原始的jar。

运行jar包:

➜  target java -jar maven-demo-hello-1.0-SNAPSHOT.jar 
Hello World
➜  target java -jar original-maven-demo-hello-1.0-SNAPSHOT.jar 
original-maven-demo-hello-1.0-SNAPSHOT.jar中没有主清单属性

【Maven笔记1】Maven介绍
【Maven笔记2】Maven安装与配置

你可能感兴趣的:(maven,笔记,java)