Maven学习总结

Maven是什么

简而言之:maven是一个项目管理工具,它包含了一个项目对象模型(Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Management System),和用来运行定义在生命周期阶段(phase)中插件(plugin)目标(goal)的逻辑。
相关概念解释

  • POM 项目对象模型:pom.xml是maven工程的核心配置文件,可以通过一小段描述信息来管理项目的构建。
  • 标准集合:在maven中有很多种骨架(模板),通过同一种骨架创建项目的结构都是一样的。
  • 项目生命周期:开发一个项目需要经过编译、测试、打包、安装、部署阶段。
  • 依赖管理系统:开发一个项目需要依赖其它的jar包。
  • 插件:maven本身很小,它的很多功能都是通过插件完成的。

Maven的快速入门

1、Maven的下载安装
官方下载页面:http://maven.apache.org/download.cgi
下载并解压apache-maven-3.6.0-bin.zip(注意解压的路径,建议不要有中文、空格、特殊符号)
目录说明:
bin:Maven的运行脚本
boot:Maven自己的类装载器
conf:该目录下包含了全局行为定制文件setting.xml
lib:存放maven运行时的核心类库
maven本身的包很小,要想实现功能是通过插件来使用的
2、Maven的配置
① 配置jdk的环境变量
② 配置Maven的环境变量
③ path环境变量中,添加 %MAVEN_HOME%\bin
④ 测试是否配置成功:打开cmd,运行:mvn -v(mvn -version),出现相关信息就说明成功了
3、Maven本地仓库配置
① 本地仓库就是一个目录,这个目录被用来存储我们项目的所有依赖(就是jar包),本地仓库供你电脑上所有项目使用,maven所有的jar包都是从*仓库下载,*仓库的地址:http://mvnrepository.com/
② 本地仓库的位置是通过maven的核心配置文件(settings.xml)来配置的

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <!-- localRepository
   | The path to the local repository maven will use to store artifacts.
   | 默认的仓库位置是在当前登录用户的home目录中.m2/repository文件夹中。
   | Default: ${user.home}/.m2/repository
  <localRepository>/path/to/local/repo</localRepository>
  -->/
  // 此处是我们自己创建的目录,在此默认为我们的本地仓库
<localRepository>D:\apache-maven-3.5.2\repository</localRepository>

3、配置maven私服
在setting.xml中配置私服,默认是从*仓库下的,可以改成自己公司的私服,或者阿里云等等

	  <mirror>
      <id>nexus-aliyun</id>
      <mirrorOf>*</mirrorOf>
      <name>Nexus aliyun</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
	 </mirror>

4、构建一个helloworld工程项目(命令行方式)
① 创建一个mvnproject文件夹,用来存放maven项目
② 打开cmd窗口,切换到c:\mvnpeoject目录,可使用Maven Archetype插件的generate命令创建maven项目:mvn archetype:generate -DgroupId=com.ityang.maven.quickstart -DartifactId=helloworld -DarchetypeArtifactId=maven-archetype-quickstart
groupId:组id,一般就是所在公司域名的倒写,例如:com.ityang
artifactId:艺术品id,其实就是工程的名字,例如:helloworld
archetypeArtifactId:骨架id,选择什么骨架,就会生成什么样的项目结构,骨架一般都是现成的固定好的,例如:maven-archetype-quickstart是用来生成java工程的骨架
maven项目结构说明
pom.xml:位于工程根目录,是maven工程的核心配置文件
src/main/java:存放项目源码
src/test/java:存放项目测试代码
5、操作maven项目(命令行方式)
想要执行mvn命令,需要进入工程所在目录 (即进入到pom.xml 所在目录),所有的mvn命令都必须针对pom.xml运行
① 编译命令:mvn compile
作用:在工程目录生成target目录,将源码(\src\main)编译为class文件,存放在target/classes目录,不会对测试代码编译;如果对测试代码编译,需要执行mvn test-compile 在target/test-classes 生成class文件
② 清除命令:mvn clean
作用:清除编译后的结果,会删除target目录及相关文件。
③ 测试命令:mvn test
作用:运行测试,会先对代码自动编译,生成target目录和测试报告;Maven会自动先编译再自动运行测试。
④ 打包命令:mvn package
作用:Java项目自动打成 jar包;Web项目自动打成war包。
打包后文件名的名字为:工程名字(其实是artifactID)-版本-版本性质.jar,SNAPSHOT表示开发版本。另外:如果打包的时候不想执行测试(跳过测试),可以执行:mvn package -Dmaven.test.skip=true
⑤ 安装命令:mvn install
作用:将项目打包后,安装到本地仓库中;安装jar包到本地仓库目录是有一定规律的,格式如下:${仓库根目录}/groupId/artifactId/version/xxx.jar

IntelliJ IDEA中配置maven

1、打开IDEA 选择File—Settings
Maven学习总结
2、我们可以再勾选一些其他选项
Maven学习总结
3、我们可以更新一下本地仓库和远程仓库,这个样在pom.xml文件中添加依赖jia包的坐标时就可以很好的提示出来
Maven学习总结

maven应用详解

1、仓库
maven中仓库分为两大类共三种:
① 本地仓库:在maven的核心配置文件settings.xml 中指定,可以将网络上的jar包缓存到本地仓库,也可以使用mvn install命令将自己开发项目也部署到本地仓库。
② 远程仓库:网络上的仓库(分两种)

  • *仓库:当本地项目依赖其它jar包,而该jar包本地仓库没有,maven就会自动到网络上的*仓库去找
  • 私服:公司内部搭建服务器,可以快速下载jar包,还可以存放公司内部私密的一些项目
    2、POM配置详解
    ① :文件的根节点,固定的。
    ② :pom.xml使用的对象模型版本,一般也都是4.0.0版本。
    ③ :创建项目的组织或团体的唯一Id,一般是公司域名的倒写。
    ④ :艺术品id, 其实就是项目名。
    ⑤ :打包类型,一般有jar、war、pom 等。如果是简单java项目,packaging设置成jar;如果是web项目,packaging设置成war;如果是父工程,packaging设置成pom.
    ⑥ :产品的版本号。我们把groupId、artifactId以及version结合起来称为项目的坐标,因为这三个组合在一起可以唯一锁定项目在仓库中的位置,一个项目在仓库中的位置格式:仓库/groupId/artifactId/version/项目包(jar、war),因此,如果要寻找一个项目,先要获得其项目坐标
    ⑦ :项目的显示名,常用于 Maven 生成的文档。
    ⑧ :项目描述,常用于 Maven 生成的文档。
    3、依赖管理 (dependencies)
    什么是依赖?在项目工程中,需要用到junit这个jar包,我们就说junit是项目工程的一个依赖,在pom.xml中通过节点来专门声明项目的依赖。要导入jar,首先要得到其坐标,有两种方式获取jar包的坐标:
  • 方式一:通过网站搜索jar包的坐标:http://mvnrepository.com/
    为什么只导入核心core一个jar,但会导入除了核心以外的jar?原因是:这个core的jar包会依赖其他jar,其本身的项目中的POM会描述其依赖的jar。
  • 方式二:使用maven插件的搜索功能
    4、依赖的相关配置
    完整的dependency 配置如下:
        <dependency>
            <groupId></groupId>
            <artifactId></artifactId>
            <version></version>
            <classifier></classifier>
            <scope></scope>
            <type></type>
            <systemPath></systemPath>
            <optional></optional>
            <exclusions></exclusions>
        </dependency>

主要介绍几个:
① groupId、artifactId、version是依赖的基本坐标,缺一不可。
② scope:配置依赖范围

  • compile :编译时有效,测试时有效、运行时也有效(会被打包),大部分的jar包都是这个范围
  • test: 编译时无效、测试时有效、运行时无效,不会被打包,例如junit包
  • provided :编译时有效,测试时有效,运行时无效,不会被打包,例如servlet-api包
  • runtime: 编译时无效,测试时有效,运行时有效,会被打包,例如:jdbc驱动包
  • system:一个jar包如果是在本地,不在maven仓库内,那么scope的取值为system.编译时有效,测试时有效,运行时无效,不会被打包。例如:oracle的驱动包,从*仓库无法下载,需要先下载到本地,再通过本地路径引入;
<dependency>
			<groupId>oracle</groupId>
			<artifactId>ojdbc</artifactId>
			<version>1.0</version>
			<scope>system</scope>
			<systemPath>C:\apache-maven-3.2.3\repository\ojdbc6.jar</systemPath>
</dependency>
// 也可以将jar包上传到本地仓库,通过坐标查找(推荐)
<dependency>
			<groupId>cn.itcast</groupId>
			<artifactId>ojdbc</artifactId>
			<version>0.0.1-SNAPSHOT</version>
			<scope>runtime</scope>
</dependency>

③ exclusions:排除传递依赖,即某些依赖的jar包不想导入进来。主要用来解决版本冲突问题。

什么是传递性依赖?
如果A依赖D,D依赖X,那X就是A的传递依赖。传递性依赖也称之为间接依赖。

问题:如果两个jar,同时依赖与另外一个jar的不同版本,就可能导致jar冲突问题。这就是传递依赖的jar版本冲突问题。
maven是如何选择版本的呢?(maven的依赖调节策略)
① A->B->C->D->X(1.6)
② A->B->X(2.0)
调解原则:
1、第一原则:路径近者优先原则,上面的情况,会优先选择②X2.0传递给A最近
2、第二原则:第一声明者优先原则:当路径相等的情况下,谁先声明(谁在上面),就用谁的版本

传递性依赖指定某个版本:
如果采用maven自带的调节原则,得到的jar包版本不是我们想要的,就需要采用如下办法来解决

  • 方案一:解决间接依赖,最好的方式就是直接依赖 ,因为直接依赖优先间接依赖
  • 方案二: 锁定版本;对应的pom文件的代码,使用了对依赖的版本进行锁定
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
                <version>4.3.13.RELEASE</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
  • 方案三:排除依赖
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.6.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

5、统一维护版本:方便对项目中使用的jar包版本进行升级

  • 第一步 :在pom.xml中使用属性定义jar包的版本
    <!-- 集中定义依赖版本号 -->
    <properties>
        <junit.version>4.12</junit.version>
        <spring.version>4.3.13.RELEASE</spring.version>
        <mybatis.version>3.2.8</mybatis.version>
        <mybatis.spring.version>1.2.2</mybatis.spring.version>
        <mybatis.paginator.version>1.2.15</mybatis.paginator.version>
        <mysql.version>5.1.32</mysql.version>
        <slf4j.version>1.6.4</slf4j.version>
        <jackson.version>2.9.0</jackson.version>
        <druid.version>1.0.9</druid.version>
        <httpclient.version>4.3.5</httpclient.version>
        <jstl.version>1.2</jstl.version>
        <servlet-api.version>2.5</servlet-api.version>
        <jsp-api.version>2.0</jsp-api.version>
        <joda-time.version>2.5</joda-time.version>
        <commons-lang3.version>3.3.2</commons-lang3.version>
        <commons-io.version>1.3.2</commons-io.version>
    </properties>
  • 第二步 :在依赖的中使用${}引入前面定义好的版本
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>

调整编译级别(就是告诉maven用jdk几编译):
方式一:全局设置:首先我们要在settings.xml文件中找到标签,然后在此标签内部粘贴如下配置:

<profile>
    <id>jdk-1.8</id>
    <activation>
        <jdk>1.8</jdk>
    </activation>
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
    </properties>
</profile>

方式二:单个项目单独设置:如果需要在某个项目中指定编译级别,可以在项目的pom.xml文件中配置,如下:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

继承

一个maven工程继承父工程后,就可以重用父工程的一些配置,在实际开发中,公司都会有一个现成的父工程,来管理我们可能用到的依赖的版本。

<?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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ityang.parent</groupId>
    <artifactId>ssm</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <modules>
        <module>demo-ssm</module>
    </modules>
    <packaging>pom</packaging>

    <!-- 集中定义依赖版本号 -->
    <properties>
        <junit.version>4.12</junit.version>
        <spring.version>4.3.13.RELEASE</spring.version>
        <mybatis.version>3.2.8</mybatis.version>
        <mybatis.spring.version>1.2.2</mybatis.spring.version>
        <mybatis.paginator.version>1.2.15</mybatis.paginator.version>
        <mysql.version>5.1.32</mysql.version>
        <slf4j.version>1.6.4</slf4j.version>
        <jackson.version>2.9.0</jackson.version>
        <druid.version>1.0.9</druid.version>
        <httpclient.version>4.3.5</httpclient.version>
        <jstl.version>1.2</jstl.version>
        <servlet-api.version>2.5</servlet-api.version>
        <jsp-api.version>2.0</jsp-api.version>
        <joda-time.version>2.5</joda-time.version>
        <commons-lang3.version>3.3.2</commons-lang3.version>
        <commons-io.version>1.3.2</commons-io.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- 单元测试 -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>${spring.version}</version>
                <scope>test</scope>
            </dependency>
            <!-- Spring -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <!-- Mybatis -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>${mybatis.version}</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>${mybatis.spring.version}</version>
            </dependency>
            <dependency>
                <groupId>com.github.miemiedev</groupId>
                <artifactId>mybatis-paginator</artifactId>
                <version>${mybatis.paginator.version}</version>
            </dependency>

            <!-- MySql -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
                <scope>runtime</scope>
            </dependency>

            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <version>${slf4j.version}</version>
            </dependency>

            <!-- Jackson Json处理工具包 -->
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>${jackson.version}</version>
            </dependency>

            <!-- 连接池 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>

            <!-- httpclient -->
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>${httpclient.version}</version>
            </dependency>

            <!-- JSP相关 -->
            <dependency>
                <groupId>jstl</groupId>
                <artifactId>jstl</artifactId>
                <version>${jstl.version}</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>${servlet-api.version}</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jsp-api</artifactId>
                <version>${jsp-api.version}</version>
                <scope>provided</scope>
            </dependency>

            <!-- 时间操作组件 -->
            <dependency>
                <groupId>joda-time</groupId>
                <artifactId>joda-time</artifactId>
                <version>${joda-time.version}</version>
            </dependency>

            <!-- Apache工具组件 -->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>${commons-lang3.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-io</artifactId>
                <version>${commons-io.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
        <!-- 资源文件拷贝插件 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-resources-plugin</artifactId>
            <version>2.7</version>
            <configuration>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
        <!-- java编译插件 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.2</version>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    </plugins>
    <pluginManagement>
        <plugins>
            <!-- 配置Tomcat插件 -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
            </plugin>
        </plugins>
    </pluginManagement>
    </build>

</project>

附录:常见问题解决

初始情况下,我们的本地仓库是没有任何jar包的,此时会从私服去下载(如果没有配置,就直接从*仓库去下载),可能由于网络的原因,jar包下载不完全,这些不完整的jar包都是以lastUpdated结尾。此时,maven不会再重新帮你下载,需要你删除这些以lastUpdated结尾的文件。如果本地仓库中有很多这样的以lastUpadted结尾的文件,可以执行如下脚本来删除:
Maven学习总结
双击运行该脚本即可!