Maven学习心得

Maven学习心得,原文地址:https://www.yiibai.com/maven

7.17
添加了Maven的文件夹结构、依赖机制
创建一个Java项目及其目录结构
创建一个web项目及其目录结构
打包以及运行最基本的jar包

7.18

2. Maven的中央资源库

http://repo1.maven.org/maven/,改版后目录浏览不能使用,但是依然可以从这个网址获得依赖,同时可以通过https://search.maven.org/或http://repo1.maven.org/maven2来访问目录浏览。

3. 获取依赖

在Maven中,当你声明的库不存在于本地存储库中,也没有不存在于Maven中心储存库,该过程将停止并将错误消息输出到 Maven 控制台。

例:



        org.jvnet.localizer
        localizer
        1.8



  
    java.net
    https://maven.java.net/content/repositories/public/
  

声明库后,Maven的依赖库查找顺序变为:

  1. 在 Maven 本地资源库中搜索,如果没有找到,进入第 2 步,否则退出。
  2. 在 Maven 中央存储库搜索,如果没有找到,进入第 3 步,否则退出。
  3. 在java.net Maven的远程存储库搜索,如果没有找到,提示错误信息,否则退出。
    Maven中央仓库以外的远程仓库
    Java.net资源库:


   
    java.net
    https://maven.java.net/content/repositories/public/
  


JBoss Maven资源库:



  
    JBoss repository
    http://repository.jboss.org/nexus/content/groups/public/
  


4. Maven依赖机制

  1. 知道所需的包的Maven坐标,例如:
log4j
log4j
1.2.14
  1. 由Maven自动下载jar包,如果version标签被忽略,则当有新的版本时它会自动升级。
  2. Maven坐标转换成pom.xml文件,例如:

  
    log4j
    log4j
    1.2.14
  

  1. 当Maven编译或构建时,jar包会自动下载,并将其加入Maven本地存储库。
  2. 所有由Maven管理。

5. 将自定义的jar包添加到本地存储库

以kaptcha为例。
1. mvn安装
安装命令:

mvn install:install-file -Dfile=c:\kaptcha-{version}.jar 
-DgroupId=com.google.code 
-DartifactId=kaptcha 
-Dversion={version} 
-Dpackaging=jar
  • -Dfile:文件位置
  • -DgroupId:项目创建者或组织的唯一标识符
  • -DartifactId:项目的唯一标识符
  • -Dversion:版本号
  • -Dpackaging:可选,默认为jar

安装kaptcha-2.3.2.jar的命令:

mvn install:install-file -Dfile=c:\kaptcha-2.3.2.jar -DgroupId='com.google.code' -DartifactId=kaptcha -Dversion='2.3.2' -Dpackaging=jar

成功提示:

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] --- maven-install-plugin:2.4:install-file (default-cli) @ standalone-pom ---
[INFO] Installing d:\kaptcha-2.3.2.jar to C:\Users\话神闲\.m2\repository\com\google\code\kaptcha\2.3.2\kaptcha-2.3.2.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.020 s
[INFO] Finished at: 2019-07-17T13:55:42+08:00
[INFO] ------------------------------------------------------------------------

PS:当带"."的值(例如版本号的2.3.2和组织标识符的com.google.code)不用引号包起来时,有可能报错。
报错信息:

[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.109 s
[INFO] Finished at: 2019-07-17T14:05:18+08:00
[INFO] ------------------------------------------------------------------------
[ERROR] **The goal you specified requires a project to execute but there is no POM in this directory (C:\Users\话神闲\Downloads). Please verify you invoked Maven from the correct directory. -> [Help 1]

2. 配置pom.xml
在pom.xml中声明刚才安装到本地存储库的jar包的坐标


  com.google.code
  kaptcha
  2.3

3. 完成

完成以上步骤便可从Maven本地存储库检索了。

6. 创建Java项目

  1. 从Maven模板创建一个项目
    创建命令:
mvn archetype:generate 
-DgroupId={project-packaging} 
-DartifactId={project-name} 
-DarchetypeArtifactId=maven-archetype-quickstart 
-DinteractiveMode=false
  • -DgroupId:组织唯一标识符
  • -DartifactId:项目唯一标识符
  • -DarchetypeArtifactId:使用的模板
  • -DinteractiveMode:是否需要和用户交互以获得输入

PS:

1. 同上面安装jar包到本地存储库的命令相同,带"."的参数(如组织唯一标识符)可能会引起报错,因此最好用引号包住。
2. 创建项目时可能会停留在下面这一步很久
[INFO] Generating project in Batch mode

解决方案是:

  1. 将http://repo1.maven.org/maven2/archetype-catalog.xml的archetype-catalog.xml文件下载并放到 ~.m2\repository\org\apache\maven\archetype\archetype-catalog{版本号}"文件夹下。然后在创建项目的命令后增加新的参数-DarchetypeCatalog=local,表示从本地读取这个文件
  2. 第二种方法更简单,只要添加-DarchetypeCatalog=internal参数就可以,而且不需要添加-DinteractiveMode=false

7. Maven Java项目目录布局

HelloWorld
    ├──src
    │   ├──main
    │   │   └──java
    │   │       └──mycompany
    │   │              └──App.java
    │   └──test
    │        └──java
    │             └──mycompany
    │                    └──App.java
    └──pom.xml
Directory Description
src/main/java Application/Library sources
src/main/resources Application/Library resources
src/main/filters Resource filter files
src/main/webapp Web application sources
src/test/java Test sources
src/test/resources Test resources
src/test/filters Test resource filter files
src/it Integration Tests (primarily for plugins)
src/assembly Assembly descriptors
src/site Site
LICENSE.txt Project's license
NOTICE.txt Notices and attributions required by libraries that the project depends on
README.txt Project's readme

8. 打包jar

在终端使用以下命令:

mvn package

在target目录生成jar文件
此时文件目录结构:

HelloWorld
    ├──src
    │   ├──main
    │   │   └──java
    │   │       └──mycompany
    │   │             └──App.java
    │   └──test
    │       └──java
    │           └──mycompany
    │                 └──App.java
    ├──target
    └──pom.xml

9. 运行jar包

java -cp HelloWorld.jar mycompany.App
这里要用cp(classpath)指定运行的主类名称

Maven导出的包中:

  • 如果指定了主类,可以用Java -jar xxx.jar
  • 如果未指定主类,可以用Java -cp xxx.jar 包名.主类

10. Maven创建Web项目

命令:

mvn archetype:generate 
-DgroupId=mycompany
-DartifactId=myapp 
-DarchetypeArtifactId=maven-archetype-webapp 
-DinteractiveMode=false

Web项目目录布局:

MyApp
    ├──src
    │   └──main
    │       ├──webapp
    │       │     ├──WEB-INF
    │       │     │     └──web.xml
    │       │     └──index.jsp
    │       └──resources
    └──pom.xml
Directory Description
src/main/java Application/Library sources
src/main/resources Application/Library resources
src/main/filters Resource filter files
src/main/webapp Web application sources
src/test/java Test sources
src/test/resources Test resources
src/test/filters Test resource filter files
src/it IntegrationTests (primarily for plugins)
src/assembly Assembly descriptors
src/site Site
LICENSE.txt Project's license
NOTICE.txt Notices and attributions required by libraries that the project depends on
README.txt Project's readme

11. 使用IDEA创建Maven项目

12. Maven Pom

POM:项目对象模型
POM的例子


   4.0.0
   com.yiibai.project-group
   project
   1.0

POM的三个必填字段:groupId、artifactId、version。
在库中的项目符号:groupId:artifactId:version。
根元素:project

节点 描述
groupId 这是项目组的编号,这在组织或项目中通常是独一无二的。 例如,一家银行集团com.company.bank拥有所有银行相关项目。
artifactId 这是项目的ID。这通常是项目的名称。 例如,consumer-banking。 除了groupId之外,artifactId还定义了artifact在存储库中的位置。
version 这是项目的版本。与groupId一起使用,artifact在存储库中用于将版本彼此分离。 例如:com.company.bank:consumer-banking:1.0,com.company.bank:consumer-banking:1.1

有效POM:
超级POM:被所有的POM继承的,包含继承默认值的基础POM。
有效的POM:超级POM加项目配置的配置

子pom.xml会完全继承父pom.xml中所有的元素,而且对于相同的元素,一般子pom.xml中的会覆盖父pom.xml中的元素,但是有几个特殊的元素它们会进行合并而不是覆盖。这些特殊的元素是:

  • dependencies
  • developers
  • contributors
  • plugin列表,包括plugin下面的reports
  • resources

查看有效POM的命令:

mvn help:effective-pom
PS D:\home\mavenworkspace\HelloMaven> mvn help:effective-pom
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------< com.ltc:HelloMaven >-------------------------
[INFO] Building HelloMaven 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-help-plugin:3.2.0:effective-pom (default-cli) @ HelloMaven ---
[INFO]
Effective POMs, after inheritance, interpolation, and profiles are applied:














  4.0.0
  com.ltc
  HelloMaven
  1.0-SNAPSHOT
  HelloMaven
  http://maven.apache.org
  

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  4.881 s
[INFO] Finished at: 2019-07-18T14:47:49+08:00
[INFO] ------------------------------------------------------------------------

13. 快照版本和正式版本

SNAPSHOT版本:

  • 一个SNAPSHOT版本可以多次发布(deploy)到仓库中,也就是说,一个SNAPSHOT是一系列版本的集合,而HEAD指针总是指向最新的版本。因此,当有新的SNAPSHOT版本发布时,由于本地的版本和实际HEAD指针所指向的版本不同,因此Maven会自动下载新版本的SNAPSHOT版本。
    SNAPSHOT文件夹里用来保存历史发布的文件内容


  ltc
  SnapShot
  1.0-SNAPSHOT
  
    
      true
    
    20190718152857
    
      
        jar
        1.0-SNAPSHOT
        20190718152857
      
      
        pom
        1.0-SNAPSHOT
        20190718152857
      
    
  

  • SNAPSHOT写法:
{version}-SNAPSHOT
  • Maven在工作时,会自动下载最新版的SNAPSHOT版本,但是也可以通过任何命令加上 -U 参数来强制获取最新的SNAPSHOT。
mvn clean -U

RELEASE版本:

  • 一个正式版本对应的就是一个特定的版本,版本名称后缀为:-RELEASE。正式版本,不允许覆盖。如果一定要提交,要么删除私服上已经存在的版本,要么升级版本重新发布。
  • RELEASE写法:
{version}-RELEASE

总结:
RELEASE版本 -> 稳定性
SNAPSHOT版本 -> 方便性

快照和正式版本的选择:

  • 在开发期间,方便性优于稳定性。
  • 生产环境,稳定性重于一切。
    例子:

模块A依赖模块B的1.0版本,而假如B假如发布新特性或者修复了旧版本的漏洞,则必须发布新的1.1版本,并通知所有依赖B-1.0版本的模块更新依赖。
但是如果模块A依赖的是模块B的1.0-SNAPSHOT版本,则B修复完漏洞,只需再次发布1.0-SNAPSHOT版本,而A模块就能获得了最新版本的B模块。

14. 版本区间

范围 说明
1.0 version >= 1.0 * The default Maven meaning for 1.0 is everything (,) but with 1.0 recommended. Obviously this doesn't work for enforcing versions here, so it has been redefined as a minimum version.
(,1.0] version <= 1.0
(,1.0) version < 1.0
[1.0] version == 1.0
[1.0,) version >= 1.0
(1.0,) version > 1.0
(1.0,2.0) 1.0 < version < 2.0
[1.0,2.0] 1.0 <= version <= 2.0
(,1.0],[1.2,) version <= 1.0 or version >= 1.2. Multiple sets are comma-separated
(,1.1),(1.1,) version != 1.0

测试:
本地库版本有:

  • 0.9
  • 1.0
  • 1.0-SNAPSHOT
  • 1.1
  • 1.9
  • 2.0
  • 2.0-SNAPSHOT
  • 2.1-SNAPSHOT
  • 2.2-SNAPSHOT
(1,)
导入的为2.3-SNAPSHOT
----------------------------------
(1,2]
导入的为2.0
----------------------------------
(1,2)
导入的为2.0-SNAPSHOT
----------------------------------
(,1)
导入的为1.0-SNAPSHOT
----------------------------------
(,0.99)
导入的为0.9
----------------------------------
(,0.9) , (2.3,)
报错,找不到符合范围的包
----------------------------------

15. 移除依赖包

当想导入的jar包依赖于另一个jar包,而实际上并没用到这个包又或者自动导入的这个包并不稳定而需要重新导入另一个稳定版本时,可以将其移除。


  ltc
  B
  1.0-SNAPSHOT
  
    
      ltc
      A
    
  

如上,其中B部分功能依赖于A,当前项目C依赖于B,当未使用到B中依赖A的功能时可以把A包移除。同样的,如果B中自动导入的A并不稳定,也可通过这个方式先将其移除,然后将导入A的稳定版本。

16. Profiles

通过定义多个profile,可以分别为不同的环境配置不同的设置,然后在需要激活的时候通过特定方法激活特定的配置。
项目结构如下:

ProfileTest
    ├──src
    │   ├──main
    │   │   ├──java
    │   │   │    └──ltc
    │   │   │        └──App.java
    │   │   └──resources
    │   │           ├──dev
    │   │           │   └──application-dev.properties
    │   │           ├──prod
    │   │           │   └──application-prod.properties
    │   │           └──test
    │   │                └──application-test.properties
    │   └──test
    │       └──java
    │           └──ltc
    │               └──App.java
    └──pom.xml

其中,pom.xml文件配置如下:



  4.0.0
  ltc
  ProfileTest
  jar
  1.0-SNAPSHOT
  ProfileTest
  http://maven.apache.org
  
    
      junit
      junit
      3.8.1
      test
    
  
  
    
    
      
      dev
      
      
        dev
      
    
    
      prod
      
        prod
      
      
      
        true
      
    
    
      test
      
        test
      
    
  
  
    
      
      
        src/main/resources/${env}
      
    
  

激活profile:

  1. 通过标签所在的profile来激活,这时无需指定profile
mvn compile

编译后的target文件夹:

target
   ├──classes
   │   ├──ltc
   │   │   └──App.class
   │   └──application-prod.properties
   └──maven-status

可见,被所指定的properties文件被添加到了目标文件夹中。

  1. 通过编译时的-P参数来激活
mvn clean compile -Pdev

编译后的target文件夹:

target
   ├──classes
   │   ├──ltc
   │   │   └──App.class
   │   └──application-dev.properties
   └──maven-status

由于在编译时指定了profile,所以默认的profile并没有被添加到target文件夹 。

进阶配置:

  • filter的配置:
    原理:
    用build-filters-filter里选择的文件中的键值对填充resources-resource-directory-includes-include选择的文件中的${...}占位符。
    配置:
    该项目文件结构:
ProfileTest
    ├──src
    │   ├──main
    │   │   ├──java
    │   │   └──resources
    │   │           ├──dev
    │   │           │   └──application-dev.properties
    │   │           ├──prod
    │   │           │   └──application-prod.properties
    │   │           ├──test
    │   │           │   └──application-test.properties
    │   │           └──application.properties
    │   └──test
    └──pom.xml

pom.xml:


  src/main/resources/${env}/application-${env}.properties


  
    src/main/resources/
    
    true
    
    
      application.properties
     
 

application.properties:

url=${url}
username=${username}
password=${password}

application-dev.properties:

url=dev
username=name-dev
password=password-dev

prod和test配置文件的内容与dev基本相似,编译打包后,application.properties中用${...}占位符表示的地方,会用filter选择的文件进行填充,因此编译打包后的application.properties的内容为:

url=dev
username=name-dev
password=password-dev

此外,如果需要打包的配置文件中(application.properties),有filter文件中未出现的键值对,那么${...}将保持原样不会被替换。

参考资料:
maven profile动态选择配置文件
maven(三)最详细的profile的使用
maven 根据profile,resources,filters来区分部署环境

17. 继承

一个项目可以继承另一个项目的依赖,前者被称为子项目,后者被称为父项目。
在父项目声明的依赖,在子项目中可以直接获得。父项目也可以通过标签来管理依赖,该标签下的依赖子项目默认不继承,但可通过在子pom.xml声明groupId和artifactId即可继承父项目中的依赖。

父pom配置:
--------------------------------------------------------------------------------------------
4.0.0
  ltc
  Parent
  pom
  1.0
  Parent
  http://maven.apache.org
  
      
        junit
        junit
        4.11
        test
    
  
  
     
       
         commons-io
         commons-io
         2.5
       
         
             log4j
             log4j
             1.2.11
         
     
  
--------------------------------------------------------------------------------------------
子pom配置:
--------------------------------------------------------------------------------------------
4.0.0
  Child1
  http://maven.apache.org
  
    Parent
    ltc
    1.0
  
  
      
          commons-io
          commons-io
      
      
          log4j
          log4j
      
  
--------------------------------------------------------------------------------------------

子项目中的依赖

可以看到,子项目中不需要配置就直接继承了父项目在dependencies中声明的junit,通过配置commons-io和log4j的groupId和artifactId也获取到了父项目中对应版本的jar包。
PS:

  • 父项目需要打包格式为pom
  • 父项目需要安装或者指定,否则子项目将找不到父项目

18. 聚合

  • 创建方式
    父模块:创建普通的Maven项目,打包方式为pom
    子模块:命令行模式下,在父模块目录下,创建Maven项目。IDEA中在父模块上右键新建Module。
    父模块pom:
  4.0.0
  ltc
  Combine
  pom
  1.0-SNAPSHOT
  Combine
  http://maven.apache.org
  
    
      junit
      junit
      3.8.1
      test
    
  
 
  Son1
  Son2
 

子模块pom:

4.0.0
  
    ltc
    Combine
    1.0-SNAPSHOT
  
  ltc
  Son1
  1.0-SNAPSHOT
  Son1
  http://maven.apache.org
  
    
      junit
      junit
      3.8.1
      test
    
  

父模块在module声明了子模块的名称,子模块也声明了父模块,不过与继承不同的是父模块不用安装到存储库中,子模块也能找到对应父模块。同时子模块也可以继承父模块的依赖。

你可能感兴趣的:(Maven学习心得)