Maven自动化构建工具详解

一、Maven概述

1、使用Maven原因

我们先通过企业开发中的实际需求来看一看哪些方面是我们现有技术的不足。

1. 第三方Jar包添加

在今天的JavaEE开发领域,有大量的第三方框架和工具可以供我们使用。要使用这些jar包最简单的方法就是复制粘贴到WEB-INF目录下的lib目录下。但是这会导致每次创建一个新的工程就需要将jar包重复复制到lib目录下,从而造成工作区中存在大量重复的文件。

而使用Maven后每个jar包在本地仓库中保存一份,需要jar包的工程只需要维护一个文本形式的jar包的引用——我们称之为“坐标”。不仅极大的节约了存储空间,更避免了重复文件太多而造成的混乱

2. 第三方Jar包获取

JavaEE开发中需要使用到的jar包种类繁多,几乎每个jar包在其本身的官网上的获取方式都不尽相同。为了查找一个jar包找遍互联网,身心俱疲,没有经历过的人或许体会不到这种折磨。不仅如此,费劲心血找的jar包里有的时候并没有你需要的那个类,又或者有同名的类没有你要的方法——以不规范的方式获取的jar包也往往是不规范的。

使用Maven我们可以享受到一个完全统一规范的jar包管理体系。你只需要在你的项目中坐标的方式依赖一个jar包,Maven就会自动从中央仓库进行下载,并同时下载这个jar包依赖的其他jar包——规范、完整、准确!一次性解决所有问题!

3. Jar包之间的依赖关系

jar包往往不是孤立存在的,很多jar包都需要在其他jar包的支持下才能够正常工作,我们称之为jar包之间的依赖关系。最典型的例子是:commons-fileupload-1.3.jar依赖于commons-io-2.0.1.jar,如果没有IO包,FileUpload包就不能正常工作。

那么问题来了,你知道你所使用的所有jar包的依赖关系吗?当你拿到一个新的从未使用过的jar包,你如何得知他需要哪些jar包的支持呢?如果不了解这个情况,导入的jar包不够,那么现有的程序将不能正常工作。再进一步,当你的项目中需要用到上百个jar包时,你还会人为的,手工的逐一确认它们依赖的其他jar包吗?这简直是不可想象的。

而引入Maven后,Maven就可以替我们自动的将当前jar包所依赖的其他所有jar包全部导入进来,无需人工参与,节约了我们大量的时间和精力。用实际例子来说明就是:通过Maven导入commons-fileupload-1.3.jar后,commons-io-2.0.1.jar会被自动导入,程序员不必了解这个依赖关系。

4. Jar包之间的冲突处理

上一点说的是jar包不足项目无法正常工作,但其实有的时候jar包多了项目仍然无法正常工作,这就是jar包之间的冲突。

举个例子:我们现在有三个工程MakeFriend、HelloFriend和Hello。MakeFriend依赖HelloFriend,HelloFriend依赖Hello。而Hello依赖log4j.1.2.17.jar,HelloFriend依赖log4j.1.2.14.jar。

如下图所示:

那么MakeFriend工程的运行时环境中该导入log4j.1.2.14.jar呢还是log4j.1.2.17.jar呢?

这样的问题一个两个还可以手工解决,但如果系统中存在几十上百的jar包,他们之间的依赖关系会非常复杂,几乎不可能手工实现依赖关系的梳理。

使用Maven就可以自动的处理jar包之间的冲突问题。因为Maven中内置了两条依赖原则:最短路径者优先和声明者优先,上述问题MakeFriend工程会自动使用log4j.1.2.14.jar。

5. 将项目拆分成多个工程模块

随着JavaEE项目的规模越来越庞大,开发团队的规模也与日俱增。一个项目上千人的团队持续开发很多年对于JavaEE项目来说再正常不过。那么我们想象一下:几百上千的人开发的项目是同一个Web工程。那么架构师、项目经理该如何划分项目的模块、如何分工呢?这么大的项目已经不可能通过package结构来划分模块,必须将项目拆分成多个工程协同开发。多个模块工程中有的是Java工程,有的是Web工程。

那么工程拆分后又如何进行互相调用和访问呢?这就需要用到Maven的依赖管理机制。

例如:某项目拆分的情况如下:

上层模块依赖下层,所以下层模块中定义的API都可以为上层所调用和访问。 

6. 实现项目的分布式部署

在实际生产环境中,项目规模增加到一定程度后,可能每个模块都需要运行在独立的服务器上,我们称之为分布式部署,这里同样需要用到Maven。

 

2、Maven 简介 

Maven是一款自动化构建工具,专注服务于Java平台的项目构建和依赖管理。在JavaEE开发的历史上构建工具的发展也经历了一系列的演化和变迁:Make→Ant→Maven→Gradle→其他……

1. 构建的概念

构建并不是创建,创建一个工程并不等于构建一个项目。要了解构建的含义我们应该由浅入深的从以下三个层面来看:

1)纯Java代码

大家都知道,我们Java是一门编译型语言,.java扩展名的源文件需要编译成.class扩展名的字节码文件才能够执行。所以编写任何Java代码想要执行的话就必须经过编译得到对应的.class文件。

2)Web工程

当我们需要通过浏览器访问Java程序时就必须将包含Java程序的Web工程编译的结果“拿”到服务器上的指定目录下,并启动服务器才行。这个“拿”的过程我们叫部署

我们可以将未编译的Web工程比喻为一只生的鸡,编译好的Web工程是一只煮熟的鸡,编译部署的过程就是将鸡炖熟。

Web工程和其编译结果的目录结构对比见下图:

3)实际项目

在实际项目中整合第三方框架,Web工程中除了Java程序和JSP页面、图片等静态资源之外,还包括第三方框架的jar包以及各种各样的配置文件。所有这些资源都必须按照正确的目录结构部署到服务器上,项目才可以运行。

所以综上所述:构建就是以我们编写的Java代码、框架配置文件、国际化等其他资源文件、JSP页面和图片等静态资源作为“原材料”,去生产出一个可以运行的项目的过程。

那么项目构建的全过程中都包含哪些环节呢

2. 构建环节

1)清理:删除以前的编译结果,为重新编译做好准备。

2)编译:将Java源程序编译为字节码文件。

3)测试:针对项目中的关键点进行测试,确保项目在迭代开发过程中关键点的正确性。

4)报告:在每一次测试后以标准的格式记录和展示测试结果。

5)打包:将一个包含诸多文件的工程封装为一个压缩文件用于安装或部署。Java工程对应jar包,Web工程对应war包。

6)安装:在Maven环境下特指将打包的结果——jar包或war包安装到本地仓库中。

7)部署:将打包的结果部署到远程仓库或将war包部署到服务器上运行。

3. 自动化构建

其实上述环节我们在IDEA中都可以找到对应的操作,只是不太标准。那么既然IDE已经可以进行构建了我们为什么还要使用Maven这样的构建工具呢?我们来看一个小故事:

这是阳光明媚的一天。托马斯向往常一样早早的来到了公司,冲好一杯咖啡,进入了自己的邮箱——很不幸,QA小组发来了一封邮件,报告了他昨天提交的模块的测试结果——有BUG。“好吧,反正也不是第一次”,托马斯摇摇头,进入IDE,运行自己的程序,编译、打包、部署到服务器上,然后按照邮件中的操作路径进行测试。“嗯,没错,这个地方确实有问题”,托马斯说道。于是托马斯开始尝试修复这个BUG,当他差不多有眉目的时候已经到了午饭时间。

下午继续工作。BUG很快被修正了,接着托马斯对模块重新进行了编译、打包、部署,测试之后确认没有问题了,回复了QA小组的邮件。

一天就这样过去了,明媚的阳光化作了美丽的晚霞,托马斯却觉得生活并不像晚霞那样美好啊。

让我们来梳理一下托马斯这一天中的工作内容:

从中我们发现,托马斯的很大一部分时间花在了“编译、打包、部署、测试”这些程式化的工作上面,而真正需要由“人”的智慧实现的分析问题和编码却只占了很少一部分。 

能否将这些程式化的工作交给机器自动完成呢?——当然可以!这就是自动化构建。 

那么Maven又是如何实现自动化构建的呢?简单的说来就是它可以自动的从构建过程的起点一直执行到终点: 

3、Maven仓库

仓库分类:

1)本地仓库:为当前本机电脑上的所有Maven工程服务。

2)远程仓库,包含以下:

      a)私服:架设在当前局域网环境下,为当前局域网范围内的所有Maven工程服务。

    b)中央仓库:架设在Internet上,为全世界所有Maven工程服务。

    c)中央仓库的镜像:架设在各个大洲,为中央仓库分担流量。减轻中央仓库的压力,同时更快的响应用户请求。

仓库中的文件:

1)Maven的插件。

2)我们自己开发的项目的模块。

3)第三方框架或工具的jar包。

※不管是什么样的jar包,在仓库中都是按照坐标生成目录结构,所以可以通过统一的方式查询或依赖。

二、Maven安装与配置

1、安装Maven核心程序

1)检查JAVA_HOME环境变量

Maven是使用Java开发的,所以必须知道当前系统环境中JDK的安装目录:

C:\Windows\System32>echo %JAVA_HOME%
D:\Java\jdk1.8.0_111

2)解压Maven的核心程序

将apache-maven-3.2.2-bin.zip解压到一个非中文无空格的目录下。例如:

D:\apache-maven-3.2.2

3)配置环境变量

4) 在系统变量里面创建M2_HOME变量并赋值

变量:M2_HOME
值:D:\apache-maven-3.2.2

5)在Path变量中添加maven环境变量

变量:Path
值:%M2_HOME%\bin或D:\apache-maven-3.2.2\bin

6)查看Maven版本信息验证安装是否正确

1. 按Win +r,进入电脑运行模式;

2. 在打开里面输入:cmd;

3. 在管理员窗口输入;

C:\Users\Administrator>mvn -v

2、Maven本地仓库的配置

1)Maven默认的本地仓库

~\.m2\repository目录

说明:~表示当前用户的家目录。

2)Maven的核心配置文件位置

解压目录D:\apache-maven-3.2.2\conf\settings.xml

3)本地仓库地址更改到E:\LocalRepository

默认在C:\Users\Administrator\.m2\repository。

<localRepository>E:\LocalRepository</localRepository>

4)配置阿里云镜像(下载速度快)

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

3、在Idea中配置Maven

1)close project所有项目后,回到如下页面,点击右下角的Configure=》点击setting

2)设置Maven的安装目录及本地仓库 

说明:

  • Maven home directory:可以指定本地 Maven 的安装目录所在,因为我已经配置了M2_HOME系统参数,所以直接这样配置IntelliJ IDEA是可以找到的。但是假如你没有配置的话,这里可以选择你的Maven安装目录。此外,这里不建议使用IDEA默认的。
  • User settings file / Local repository:我们还可以指定 Maven 的 settings.xml 位置和本地仓库位置。

3)配置Maven自动导入依赖的jar包 

说明:

  • Import Maven projects automatically:表示 IntelliJ IDEA 会实时监控项目的 pom.xml 文件,进行项目变动设置,勾选上。
  • Automatically download:在 Maven 导入依赖包的时候是否自动下载源码和文档。默认是没有勾选的,也不建议勾选,原因是这样可以加快项目从外网导入依赖包的速度,如果我们需要源码和文档的时候我们到时候再针对某个依赖包进行联网下载即可。IntelliJ IDEA 支持直接从公网下载源码和文档的。
  • VM options for importer:可以设置导入的VM参数。一般这个都不需要主动改,除非项目真的导入太慢了我们再增大此参数。

三、Maven工程与插件原理

1、创建Maven程序

1)创建Project

2)创建一个空的Project 

3)创建一个module

4)右键→new Module→Maven 

5)点击Next,配置坐标 

6)点击Next,给Module命名

目录结构及说明:

说明:

  • main目录用于存放主程序。
  • java目录用于存放源代码文件。
  • resources目录用于存放配置文件和资源文件。
  • test目录用于存放测试程序。

7)配置Maven的核心配置文件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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.atguigu.maven</groupId>
    <artifactId>Hello</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

8)编写主代码

在src/main/java目录下新建文件Hello.java:

public class Hello {
    public String sayHello(String name){
        return "Hello "+name+"!";
    }
}

9)编写测试代码

在/src/test/java目录下新建测试文件HelloTest.java:

import org.junit.Test;

public class HelloTest {

    @Test
    public void testHello(){
        Hello hello = new Hello();
        String maven = hello.sayHello("Maven");
        System.out.println(maven);
    }
}

10)使用Maven的方式运行Maven工程

来到BigData项目的根目录(例如E:\ideaProject1\BigData):

1. compile命令

查看target目录的变化,编译前=》

 

编译后=》 

2. clean命令

然后再次查看根目录变化,clean前=》

 

clean后=》 

 

3. test命令

查看target目录变化:

4. package命令

查看target目录变化:

 

5. install命令

查看本地仓库的目录变化:

执行install命令前:

 

执行命令后: 

2、通过Maven创建Web工程

1)创建简单的Maven工程,打包方式为war包

<groupId>com.atguigu.maven</groupId>
<artifactId>MavenWeb</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>

2)点击Project Structure

3)选择对应的Module,添加web目录 

4)设置目录名称 

5)在web目录下创建index.jsp页面 

部署到Tomcat上运行即可。

3、目录结构

1. POM

Project Object Model:项目对象模型。

Java工程的相关信息封装为对象作为便于操作和管理的模型。Maven工程的核心配置。可以说学习Maven就是学习pom.xml文件中的配置。

2. 约定的目录结构

现在JavaEE开发领域普遍认同一个观点:约定>配置>编码。意思就是能用配置解决的问题就不编码,能基于约定的就不进行配置。而Maven正是因为指定了特定文件保存的目录才能够对我们的Java工程进行自动化构建。

a-maven-project
├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   └── resources
│   └── test
│       ├── java
│       └── resources
└── target

项目的根目录a-maven-project是项目名,它有一个项目描述文件pom.xml,存放Java源码的目录是src/main/java,存放资源文件的目录是src/main/resources,存放测试源码的目录是src/test/java,存放测试资源的目录是src/test/resources,最后,所有编译、打包生成的文件都放在target目录里。这些就是一个Maven项目的标准目录结构。

所有的目录结构都是约定好的标准结构,我们千万不要随意修改目录结构。使用标准结构不需要做任何配置,Maven就可以正常使用。

4、插件和目标

Maven的核心仅仅定义了抽象的生命周期,具体的任务都是交由插件完成的。每个插件都能实现多个功能,每个功能就是一个插件目标,Maven的生命周期与插件目标相互绑定,但是真正实现流程的工程是由插件来完成的。

我们也可以说 Maven 是一个执行插件的框架,每一个任务实际上都是有插件来完成。进一步说每个任务对应了一个插件目标(goal),每个插件会有一个或者多个目标,例如maven-compiler-plugin的compile目标用来编译位于src/main/java/目录下的主源码,testCompile目标用来编译位于src/test/java/目录下的测试源码。

1. 配置编译插件

一般我们创建一个 Maven 工程,就算指定了 JDK 的版本,但是你执行 update project 操作,一般 Maven 工程会自动恢复到默认的 JDK 版本,有可能是1.4,有可能是1.5(和 Maven 版本有关)。

那么我们如何指定其 JDK 版本呢?在 pom.xml 中添加如下代码:

<build>
	<plugins>
		<!-- 编译插件,指定 JDK 的版本为1.7 -->
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-compiler-plugin</artifactId>
			<configuration>
				<source>1.7</source>
  				<target>1.7</target>
  				<encoding>UTF-8</encoding>
			</configuration>
		</plugin>
	</plugins>
</build>

下面我们来添加一个 tomcat 插件,首先我们要知道如何创建 Maven Web 工程。

2. 创建 Maven Web 工程

第一步:New maven project,注意打包方式为 war.

第二步:右击项目名,选择 properties,选择Project Facets

第三步:将 Dynamic Web Module 取消,点击 Apply 

第四步:将 Dynamic Web Module 重新勾选,点击 下方生成的超链接

第五步:点击超链接,修改目录结构,然后点击 OK,创建 Maven Web 工程完成 

创建的 Web 工程目录结构如下: 

 

3. 添加 tomcat 插件

我们在上面创建的 web 工程,可以输入 tomcat:run 来使用默认的 tomcat 插件去启动 web 工程,但是默认的插件版本有点低,我们可以手动添加插件。

<build>
   <plugins>
   	<!--配置tomcat 插件  -->
   <plugin>
   	<groupId>org.apache.tomcat.maven</groupId>
   	<artifactId>tomcat7-maven-plugin</artifactId>
   	<configuration>
   		<port>8080</port><!--端口号  -->
   		<path>/</path>
   	</configuration>
   </plugin>
</plugins>

执行命令是输入:

tomcat7:run

四、Maven坐标与依赖管理

1、坐标

1. 几何中的坐标

1)在一个平面中使用x、y两个向量可以唯一的确定平面中的一个点。

2)在空间中使用x、y、z三个向量可以唯一的确定空间中的一个点。

2. Maven的坐标

使用如下三个向量在Maven的仓库中唯一的确定一个唯一的jar。

1)groupId:公司或组织的域名倒序+当前项目名称;

2)artifactId:当前项目的模块名称;

3)version:当前模块的版本;

在项目的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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.atguigu.maven</groupId>
    <artifactId>Hello</artifactId>
    <version>1.0-SNAPSHOT</version>

</project>

3. 如何通过坐标到仓库中查找jar包

1)将gav三个向量连起来

com.atguigu.maven + Hello + 1.0-SNAPSHOT

2)以连起来的字符串作为目录结构到仓库中查找

com/atguigu/maven/Hello/1.0-SNAPSHOT/Hello-1.0-SNAPSHOT.jar

※注意:我们自己的Maven工程必须执行安装操作才会进入仓库。

安装的命令是:

mvn install

2、项目依赖

1)创建HelloFriend Module

2)在pom.xml配置文件中配置当前工程依赖Hello 

<?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.atguigu.maven</groupId>
    <artifactId>HelloFriend</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>com.atguigu.maven</groupId>
            <artifactId>Hello</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

3)主程序

在src/main/java目录下新建文件HelloFriend.java:

public class HelloFriend {

    public String sayHelloToFriend(String name){
        Hello hello = new Hello();
        String str = hello.sayHello(name)+" I am "+this.getMyName();
        return str;
    }

    public String getMyName(){
        return "Idea";
    }
}

4)测试程序

在/src/test/java目录下新建测试文件HelloFriendTest.java:

import org.junit.Test;

public class HelloFriendTest {
    @Test
    public void testHelloFriend(){
        HelloFriend helloFriend = new HelloFriend();
        String results = helloFriend.sayHelloToFriend("Maven");
        System.out.println(results);
    }
}

5)关键:对Hello的依赖

这里Hello就是我们的第一个Maven工程,现在HelloFriend对它有依赖。那么这个依赖能否成功呢?更进一步的问题是:HelloFriend工程会到哪里去找Hello呢?

答案是:本地仓库。任何一个Maven工程会根据坐标到本地仓库中去查找它所依赖的jar包。如果能够找到则可以正常工作,否则就不行。

3、依赖管理

1)基本概念

当A jar包需要用到B jar包中的类时,我们就说A对B有依赖。例如:HelloFriend-1.0-SNAPSHOT.jar依赖于Hello-1.0-SNAPSHOT.jar。

通过第二个Maven工程我们已经看到,当前工程会到本地仓库中根据坐标查找它所依赖的jar包。

配置的基本形式是使用dependency标签指定目标jar包的坐标。

例如:

<dependency>
    <!--坐标-->
    <dependency>
        <groupId>com.atguigu.maven</groupId>
        <artifactId>Hello</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.0</version>
        <scope>test</scope>
    </dependency>
</dependency>

2)直接依赖和间接依赖

如果A依赖B,B依赖C,那么A→B和B→C都是直接依赖,而A→C是间接依赖。

1. 依赖的范围

1)compile(默认就是这个范围)

(1)main目录下的Java代码可以访问这个范围的依赖。

(2)test目录下的Java代码可以访问这个范围的依赖。

(3)部署到Tomcat服务器上运行时要放在WEB-INF的lib目录下。

例如:对Hello的依赖。主程序、测试程序和服务器运行时都需要用到。

2)test

(1)main目录下的Java代码不能访问这个范围的依赖。

(2)test目录下的Java代码可以访问这个范围的依赖。

(3)部署到Tomcat服务器上运行时不会放在WEB-INF的lib目录下。

例如:对junit的依赖。仅仅是测试程序部分需要。

3)provided

(1)main目录下的Java代码可以访问这个范围的依赖。

(2)test目录下的Java代码可以访问这个范围的依赖。

(3)部署到Tomcat服务器上运行时不会放在WEB-INF的lib目录下。

例如:servlet-api在服务器上运行时,Servlet容器会提供相关API,所以部署的时候不需要。

4)其他:runtime、import、system等。

各个依赖范围的作用可以概括为下图:

2. 依赖的传递性

当存在间接依赖的情况时,主工程对间接依赖的jar可以访问吗?这要看间接依赖的jar包引入时的依赖范围——只有依赖范围为compile时可以访问。

例如:

3. 依赖的原则:解决jar包冲突 

1)路径最短者优先

2)路径相同时先声明者优先 

这里“声明”的先后顺序指的是dependency标签配置的先后顺序。 

4. 依赖的排除 

有的时候为了确保程序正确可以将有可能重复的间接依赖排除。请看如下的例子:

假设当前工程为MakeFriend,直接依赖OurFriends。

OurFriends依赖commons-logging的1.1.1对于MakeFriend来说是间接依赖。

当前工程MakeFriend直接依赖commons-logging的1.1.2

加入exclusions配置后可以在依赖OurFriends的时候排除版本为1.1.1的commons-logging的间接依赖:

<dependency>
    <groupId>com.atguigu.maven</groupId>
    <artifactId>OurFriends</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--依赖排除-->
    <exclusions>
        <exclusion>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.1.2</version>
</dependency>

5. 统一管理目标Jar包的版本 

以对Spring的jar包依赖为例:Spring的每一个版本中都包含spring-context,springmvc等jar包。我们应该导入版本一致的Spring jar包,而不是使用4.0.0的spring-context的同时使用4.1.1的springmvc。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.0.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.0.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.0.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>4.0.0.RELEASE</version>
</dependency>

问题是如果我们想要将这些jar包的版本统一升级为4.1.1,是不是要手动一个个修改呢?显然,我们有统一配置的方式:

<!--统一管理当前模块的jar包的版本-->
<properties>
    <spring.version>4.0.0.RELEASE</spring.version>
</properties>
……
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</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-orm</artifactId>
    <version>${spring.version}</version>
</dependency>

这样一来,进行版本调整的时候只改一改地方就行了。

五、Maven生命周期

1、Maven生命周期简介

使用Maven时,我们首先要了解什么是Maven的生命周期(lifecycle),Maven的生命周期由一系列阶段(phase)构成,定义了各个构建环节的执行顺序,有了这个清单,Maven就可以自动化的执行构建命令了。

Maven有三套相互独立的生命周期,分别是:

  • Clean Lifecycle在进行真正的构建之前进行一些清理工作。
  • Default Lifecycle构建的核心部分,编译,测试,打包,安装,部署等等。
  • Site Lifecycle生成项目报告,站点,发布站点。

再次强调一下它们是相互独立的,你可以仅仅调用clean来清理工作目录,仅仅调用site来生成站点。当然你也可以直接运行 mvn clean install site 运行所有这三套生命周期。

每套生命周期都由一组阶段(Phase)组成,我们平时在命令行输入的命令总会对应于一个特定的阶段。比如,运行mvn clean,这个clean是Clean生命周期的一个阶段。有Clean生命周期,也有clean阶段。

2、clean生命周期

Clean生命周期一共包含了三个阶段:

  • pre-clean 执行一些需要在clean之前完成的工作。
  • clean 移除所有上一次构建生成的文件。
  • post-clean 执行一些需要在clean之后立刻完成的工作。

3、Site生命周期

  • pre-site执行一些需要在生成站点文档之前完成的工作。
  • site生成项目的站点文档。
  • post-site执行一些需要在生成站点文档之后完成的工作,并且为部署做准备。
  • site-deploy将生成的站点文档部署到特定的服务器上。

这里经常用到的是site阶段和site-deploy阶段,用以生成和发布Maven站点,这可是Maven相当强大的功能,Manager比较喜欢,文档及统计数据自动生成,很好看。

4、Default生命周期

Default生命周期是Maven生命周期中最重要的一个,绝大部分工作都发生在这个生命周期中。这里,只解释一些比较重要和常用的阶段:

validate   验证工程是否正确,所需的信息是否完整
initialize 初始化构建平台,例如:设置properties或创建目录
generate-sources
process-sources
generate-resources
process-resources 复制并处理资源文件,至目标目录,准备打包。
compile 编译项目的源代码。
process-classes   源码编译后的后期处理,比如java字节码的增强(优化?)
generate-test-sources
process-test-sources
generate-test-resources
process-test-resources 复制并处理资源文件,至目标测试目录。
test-compile 编译测试源代码(默认是test目录下)
process-test-classes
test 使用合适的单元测试框架运行测试。这些测试代码不会被打包或部署。
prepare-package
package 接受编译好的代码,打包成可发布的格式,如JAR,WAR等
pre-integration-test
integration-test      集成测试
post-integration-test
verify                检查package是否有效、符合标准
install               将包安装至本地仓库,以让其它项目依赖。
deploy                将最终的包复制到远程的仓库,以让其它开发人员与项目共享或部署到服务器上运行。

如果我们运行mvn package,Maven就会执行default生命周期,它会从开始一直运行到package这个phase为止:

validate
...
package

5、生命周期与自动化构建

运行任何一个阶段的时候,它前面的所有阶段都会被运行,例如我们运行mvn install 的时候,代码会被编译,测试,打包,这就是Maven为什么能够自动执行构建过程的各个环节的原因。

此外,Maven的插件机制是完全依赖Maven的生命周期的,因此理解生命周期至关重要。

六、Maven继承

有三个 Maven 工程,每个工程都依赖某个 jar 包,比如 Junit,由于 test 范围的依赖不能传递,它必然会分散在每个工程中,而且每个工程的jar 包版本可能不一致,那么如何管理各个工程中对于某个 jar 包的版本呢?

1、继承机制

由于非compile范围的依赖信息是不能在“依赖链”中传递的,所以有需要的工程只能单独配置。例如:

Hello

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.0</version>
    <scope>test</scope>
</dependency>

HelloFriend

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.9</version>
    <scope>test</scope>
</dependency>

MakeFriend

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.10</version>
    <scope>test</scope>
</dependency>

此时如果项目需要将各个模块的junit版本统一为4.9,那么到各个工程中手动修改无疑是非常不可取的。

使用继承机制就可以将 jar 包版本统一提取到 “父" 工程中,在子工程中声明依赖时不指定版本,以父工程中统一设定的为准,同时也便于修改。

2、管理依赖

1. 创建父工程

父工程的打包方式为pom:

<groupId>com.atguigu.maven</groupId>
<artifactId>Parent</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>

父工程只需要保留pom.xml文件即可。

2. 在子工程中引用父工程

<parent>
	<!-- 父工程坐标 -->
<groupId>...</groupId>
	<artifactId>...</artifactId>
	<version>...</version>
<!--指定从当前pom.xml文件出发寻找父工程的pom.xml文件的相对路径-->
<relativePath>..</relativePath>
</parent>

例如:

<!--继承-->
<parent>
    <groupId>com.atguigu.maven</groupId>
    <artifactId>Parent</artifactId>
    <version>1.0-SNAPSHOT</version>
<!--指定从当前pom.xml文件出发寻找父工程的pom.xml文件的相对路径-->
<relativePath>../Parent/pom.xml</relativePath>
</parent>

此时如果子工程的groupId和version如果和父工程重复则可以删除。

3. 在父工程中管理依赖

将Parent项目中的dependencies标签,用dependencyManagement标签括起来:

<!--依赖管理-->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

在子项目中重新指定需要的依赖,删除范围和版本号:

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
</dependency>

七、Maven聚合

在真实项目中,一个项目有表现层、业务层、持久层等。我们在用Maven 管理项目的时候,通常为创建多个 Maven 工程,也就是一个项目的多个模块。但是这样分成多个模块了,当我们进行项目打包发布的时候,那么要每一个模块都执行打包操作吗?这种重复的操作我们怎么才能避免呢?

1、聚合机制

将多个工程拆分为模块后,需要手动逐个安装到仓库后依赖才能够生效。修改源码后也需要逐个手动进行clean操作。而使用了聚合之后就可以批量进行Maven工程的安装、清理工作。

2、如何配置聚合

在总的聚合工程中使用modules/module标签组合,指定模块工程的相对路径即可。

<!--聚合-->
<modules>
    <module>../MakeFriend</module>
    <module>../OurFriends</module>
    <module>../HelloFriend</module>
    <module>../Hello</module>
</modules>

Maven可以根据各个模块的继承和依赖关系自动选择安装的顺序。

八、项目模块管理

在软件开发中,把一个大项目分拆为多个模块是降低软件复杂度的有效方法:

                        ┌ ─ ─ ─ ─ ─ ─ ┐
                          ┌─────────┐
                        │ │Module A │ │
                          └─────────┘
┌──────────────┐ split  │ ┌─────────┐ │
│Single Project│───────>  │Module B │
└──────────────┘        │ └─────────┘ │
                          ┌─────────┐
                        │ │Module C │ │
                          └─────────┘
                        └ ─ ─ ─ ─ ─ ─ ┘

对于Maven工程来说,原来是一个大项目:

single-project
├── pom.xml
└── src

现在可以分拆成3个模块:

mutiple-project
├── module-a
│   ├── pom.xml
│   └── src
├── module-b
│   ├── pom.xml
│   └── src
└── module-c
    ├── pom.xml
    └── src

Maven可以有效地管理多个模块,我们只需要把每个模块当作一个独立的Maven项目,它们有各自独立的pom.xml。

1、提取共同部分作parent

parent的<packaging>是pom而不是jar,因为parent本身不含任何Java代码。编写parent的pom.xml只是为了在各个模块中减少重复的配置。现在我们的整个工程结构如下:

multiple-project
├── pom.xml (我在idea中不需要)
├── parent
│   └── pom.xml
├── module-a
│   ├── pom.xml
│   └── src
├── module-b
│   ├── pom.xml
│   └── src
└── module-c
    ├── pom.xml
    └── src

Maven支持模块化管理,可以把一个大项目拆成几个模块:

  • 可以通过继承在parent的pom.xml统一定义重复配置;
  • 可以通过<modules>编译多个模块;

2、超级pom

在Maven中定义了超级pom.xml,任何没有申明自己父pom.xml的pom.xml都将默认继承自这个超级pom.xml。文件为pom-4.0.0.xml,后文pom之间的关系里有说明。

超级pom.xml的位置:

Maven 2.xxx版本:在maven安装目录下的maven2/lib/maven-xxx-uber.jar中,org.apache.maven.project下会有pom-4.0.0.xml的文件。

Maven 3.xxx版本: 在maven安装目录下的maven3/lib/maven-model-builder-xxx.jar中, \org\apache\maven\mode目录中的pom-4.0.0.xml。

先来看一下这个超级pom.xml的定义:

<?xml version="1.0" encoding="UTF-8"?>

<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
-->

<!-- START SNIPPET: superpom -->
<project>
  <modelVersion>4.0.0</modelVersion>

  <repositories>
    <repository>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>

  <pluginRepositories>
    <pluginRepository>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
      <releases>
        <updatePolicy>never</updatePolicy>
      </releases>
    </pluginRepository>
  </pluginRepositories>

  <build>
    <directory>${project.basedir}/target</directory>
    <outputDirectory>${project.build.directory}/classes</outputDirectory>
    <finalName>${project.artifactId}-${project.version}</finalName>
    <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
    <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
    <scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory>
    <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
    <resources>
      <resource>
        <directory>${project.basedir}/src/main/resources</directory>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <directory>${project.basedir}/src/test/resources</directory>
      </testResource>
    </testResources>
    <pluginManagement>
      <!-- NOTE: These plugins will be removed from future versions of the super POM -->
      <!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) -->
      <plugins>
        <plugin>
          <artifactId>maven-antrun-plugin</artifactId>
          <version>1.3</version>
        </plugin>
        <plugin>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.2-beta-5</version>
        </plugin>
        <plugin>
          <artifactId>maven-dependency-plugin</artifactId>
          <version>2.8</version>
        </plugin>
        <plugin>
          <artifactId>maven-release-plugin</artifactId>
          <version>2.3.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>

  <reporting>
    <outputDirectory>${project.build.directory}/site</outputDirectory>
  </reporting>

  <profiles>
    <!-- NOTE: The release profile will be removed from future versions of the super POM -->
    <profile>
      <id>release-profile</id>

      <activation>
        <property>
          <name>performRelease</name>
          <value>true</value>
        </property>
      </activation>

      <build>
        <plugins>
          <plugin>
            <inherited>true</inherited>
            <artifactId>maven-source-plugin</artifactId>
            <executions>
              <execution>
                <id>attach-sources</id>
                <goals>
                  <goal>jar</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <inherited>true</inherited>
            <artifactId>maven-javadoc-plugin</artifactId>
            <executions>
              <execution>
                <id>attach-javadocs</id>
                <goals>
                  <goal>jar</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <inherited>true</inherited>
            <artifactId>maven-deploy-plugin</artifactId>
            <configuration>
              <updateReleaseInfo>true</updateReleaseInfo>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>

</project>
<!-- END SNIPPET: superpom -->

前面说到一个pom.xml来说有几个元素是必须定义的,一个是project根元素,然后就是它里面的modelVersion、groupId、artifactId和version。由上面的超级pom.xml的内容我们可以看到pom.xml中没有groupId、artifactId和version的定义,所以我们在建立自己的pom.xml的时候就需要定义这三个元素。和java里面的继承类似,子pom.xml会完全继承父pom.xml中所有的元素,而且对于相同的元素,一般子pom.xml中的会覆盖父pom.xml中的元素,但是有几个特殊的元素它们会进行合并而不是覆盖。这些特殊的元素是:

  • dependencies
  • developers 开发者,和功能无关
  • contributors 贡献者,和功能无关
  • build下的plugin列表,包括plugin下面的reports
  • build下的resources

3、项目pom

下面示例是maven项目中的pom.xml文件。注意,其中的modelVersion是4.0.0,这是当前仅有可以被Maven2&3同时支持的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.0</modelVersion>
    
    <!-- 基本设置 The Basics -->
    <groupId>...</groupId>
    <artifactId>...</artifactId>
    <version>...</version>
    <packaging>...</packaging>
    <dependencies>...</dependencies>
    <parent>...</parent>
    <dependencyManagement>...</dependencyManagement>
    <modules>...</modules>
    <properties>...</properties>
    
    <!-- 构建过程的设置 Build Settings -->
    <build>...</build>
    <reporting>...</reporting>
    
    <!-- 项目信息设置 More Project Information -->
    <name>...</name>
    <description>...</description>
    <url>...</url>
    <inceptionYear>...</inceptionYear>
    <licenses>...</licenses>
    <organization>...</organization>
    <developers>...</developers>
    <contributors>...</contributors>
    
    <!-- 环境设置 Environment Settings -->
    <issueManagement>...</issueManagement>
    <ciManagement>...</ciManagement>
    <mailingLists>...</mailingLists>
    <scm>...</scm>
    <prerequisites>...</prerequisites>
    <repositories>...</repositories>
    <pluginRepositories>...</pluginRepositories>
    <distributionManagement>...</distributionManagement>
    <profiles>...</profiles>
</project>

一个最简单的pom.xml的定义必须包含modelVersion、groupId、artifactId和version这四个元素,当然这其中的元素也是可以从它的父项目中继承的。

<?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>
    <!-- 
        含义:组织标识,定义了项目属于哪个组,风向标,坐标,或者说若把本项目打包
        用途:此名称则是本地仓库中的路径,列如:otowa.user.dao,在M2_REPO目录下,将是: 					otowa/user/dao目录
        命名规范:项目名称,模块,子模块
    -->
    <groupId>otowa.user.dao</groupId>
    <!-- 
        含义:项目名称也可以说你所模块名称,定义当面Maven项目在组中唯一的ID
        用途:例如:user-dao,在M2_REPO目录下,将是:otowa/user/dao/user-dao目录
        命名规范:唯一就好
    -->
    <artifactId>user-dao</artifactId>
    <!-- 
        含义:项目当前的版本号
        用途:例如:0.0.1-SNAPSHOT,在M2_REPO目录下,将是:otowa/user/dao/user-dao/0.0.1-			SNAPSHOT目录
    -->
    <version>0.0.1-SNAPSHOT</version>
    <!-- 打包的格式,可以为:pom , jar , maven-plugin , ejb , war , ear , rar , par -->
    <packaging>war</packaging>
    <!-- 元素声明了一个对用户更为友好的项目名称 -->
    <name>maven</name>
</project>

碰上非开源包,maven支持不了这个包,那么则有有三种 方法处理:

  1. 本地安装这个插件install plugin
  2. 创建自己的repositories并且部署这个包。
  3. 设置scope为system,并且指定系统路径。

对于某个依赖,Maven只需要3个变量即可唯一确定某个jar包:

  1. groupId:属于组织的名称,类似Java的包名;
  2. artifactId:该jar包自身的名称,类似Java的类名;
  3. version:该jar包的版本。

通过上述3个变量,即可唯一确定某个jar包。Maven通过对jar包进行PGP签名确保任何一个jar包一经发布就无法修改。修改已发布jar包的唯一方法是发布一个新版本。

因此,某个jar包一旦被Maven下载过,即可永久地安全缓存在本地。

:只有以-SNAPSHOT结尾的版本号会被Maven视为开发版本,开发版本每次都会重复下载,这种SNAPSHOT版本只能用于内部私有的Maven repo,公开发布的版本不允许出现SNAPSHOT。

4、多模块项目pom的继承

通过idea的多模块管理进行测验:

建立empty project,在project中再建立maven module。

父工程的packaging的标签值必须为pom。

父工程下的目录结构只有一个pom.xml文件(idea自己的配置文件不算)

父工程module-p的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/maven-v4_0_0.xsd">  
  <modelVersion>4.0.0</modelVersion> 
  <groupId>com.cijian.maven</groupId>  
  <artifactId>module-p</artifactId> 
  <version>1.0.0</version>  
  
  <packaging>pom</packaging>  
</project>  

子工程maven-01,需要继承父工程module-p,子工程必须指明父工程的groupId、artifactId和version。

可以这样定义maven-01的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/maven-v4_0_0.xsd">  
  <parent>  
    <groupId>com.cijian.maven</groupId>  
    <artifactId>module-p</artifactId>  
    <version>1.0.0</version>
    <relativePath>../projectA/pom.xml</relativePath>
  </parent>  
  <modelVersion>4.0.0</modelVersion>    
  <artifactId>maven-01</artifactId>  
  <!--默认是jar,可省略 -->
  <packaging>jar</packaging> 
</project>  

1)pom中dependency设置说明

依赖关系列表(dependency list)是POM的重要部分。

​ 项目之间的依赖是通过pom.xml文件里面的dependencies元素下面的dependency元素进行的。一个dependency元素定义一个依赖关系。在dependency元素中我们主要通过依赖项目的groupId、artifactId和version来定义所依赖的项目。

​ 先来看一个简单的项目依赖的示例吧,假设我现在有一个项目projectA,然后它里面有对junit的依赖,那么它的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>com.tiantian.mavenTest</groupId>  
  <artifactId>projectB</artifactId>  
  <version>1.0-SNAPSHOT</version>  
  <packaging>jar</packaging>  
   
  <dependencies>  
    <dependency>  
      <groupId>junit</groupId>  
      <artifactId>junit</artifactId>  
      <version>3.8.1</version>  
      <scope>test</scope>  
      <optional>true</optional>  
    </dependency>  
  </dependencies>  
</project>  

groupId, artifactId, version:描述了依赖的项目唯一标志。

type:对应于依赖项目的packaging类型,默认是jar。

scope:用于限制相应的依赖范围、传播范围。scope的主要取值范围如下(还有一个是在Maven2.0.9以后版本才支持的import,关于import作用域将在后文《Dependency介绍》中做介绍):

  • test:在测试范围有效,它在执行命令test的时候才执行,并且它不会传播给其他模块进行引入,比如 junit,dbunit 等测试框架。

  • compile(default 默认):这是它的默认值,这种类型很容易让人产生误解,以为只有在编译的时候才是需要的,其实这种类型表示所有的情况都是有用的,包括编译和运行时。而且这种类型的依赖性是可以传递的。

  • runtime:在程序运行的时候依赖,在编译的时候不依赖,比如mysql的jdbc。

  • provided:这个跟compile很类似,但是它表示你期望这个依赖项目在运行时由JDK或者容器来提供。这种类型表示该依赖只有在测试和编译的情况下才有效,在运行时将由JDK或者容器提供。这种类型的依赖性是不可传递的。比如 javaee:

    • eclipse开发web环境中是没有javaee必须要手动添加。
    • myeclipse新建web项目会有JavaEE(servlet-api.jar,jsp-api.jar...)web容器依赖的jar包,一般都是做开发的时候才使用。但是myeclipse不会把这些 jar包发布的,lib下你是找不到javaee引入的jar包,因为myeclipse发布项目的时候会忽略它。为什么?因为tomcat容器bin/lib已经存在了这个jar包了。
  • system:这种类型跟provided类似,唯一不同的就是这种类型的依赖我们要自己提供jar包,这需要与另一个元素systemPath来结合使用。systemPath将指向我们系统上的jar包的路径,而且必须是给定的绝对路径。

    • systemPath:上面已经说过了这个元素是在scope的值为system的时候用于指定依赖的jar包在系统上的位置的,而且是绝对路径。该元素必须在依赖的 jar包的scope为system时才能使用,否则Maven将报错。

    • optional:当该项目本身作为其他项目的一个依赖时标记该依赖为可选项。假设现在projectA有一个依赖性projectB,我们把projectB这个依赖项设为optional,这表示projectB在projectA的运行时不一定会用到。这个时候如果我们有另一个项目projectC,它依赖于projectA,那么这个时候因为projectB对于projectA是可选的,所以Maven在建立projectC的时候就不会安装projectB,这个时候如果projectC确实需要使用到projectB,那么它就可以定义自己对projectB的依赖。当一个依赖是可选的时候,我们把optional元素的值设为true,否则就不设置optional元素。

    • exclusions:考虑这样一种情况,我们的projectA依赖于projectB,然后projectB又依赖于projectC,但是在projectA里面我们不需要projectB依赖的projectC,那么这个时候我们就可以在依赖projectB的时候使用exclusions元素下面的exclusion排除projectC。这个时候我们可以这样定义projectA对projectB的依赖:

<dependencies>  
     <dependency>  
            <groupId>com.tiantian.mavenTest</groupId>  
            <artifactId>projectB</artifactId>  
            <version>1.0-SNAPSHOT</version>  
            <exclusions>  
                   <exclusion>  
                          <groupId>com.tiantian.mavenTest</groupId>  
                          <artifactId>projectC</artifactId>  
                   </exclusion>  
            </exclusions>  
     </dependency>  
</dependencies>

2)pom中build设置说明

defaultGoal:默认的目标,必须跟命令行上的参数相同,如:jar:jar,或者与时期parse相同,例如install。

directory:指定build target目标的目录,默认为$(basedir}/target,即项目根目录下的target

finalName:指定去掉后缀的工程名字,例如:默认为artifactId−artifactId−{version}

filters:用于定义指定filter属性的位置,例如filter元素赋值filters/filter1.properties,那么这个文件里面就可以定义name=value对,这个name=value对的值就可以在工程pom中通过name引用,默认的filter目录是name引用,默认的filter目录是{basedir}/src/main/fiters/ 。

resources:描述工程中资源的位置。

    <resource>
        <targetPath>META-INF/plexus</targetPath>
        <filtering>false</filtering>
        <directory>${basedir}/src/main/plexus</directory>
        <includes>
            <include>configuration.xml</include>
        </includes>
        <excludes>
            <exclude>**/*.properties</exclude>
        </excludes>
    </resource>
  • targetPath:指定build资源到哪个目录,默认是base directory
  • filtering:指定是否将filter文件(即上面说的filters里定义的*.property文件)的变量值在这个resource文件有效,例如上面就指定那些变量值在configuration文件无效。
  • directory:指定属性文件的目录,build的过程需要找到它,并且将其放到targetPath下,默认的directory是${basedir}/src/main/resources
  • includes:指定包含文件的patterns,符合样式并且在directory目录下的文件将会包含进project的资源文件。
  • excludes:指定不包含在内的patterns,如果inclues与excludes有冲突,那么excludes胜利,那些符合冲突的样式的文件是不会包含进来的。
  • testResources:这个模块包含测试资源元素,其内容定义与resources类似,不同的一点是默认的测试资源路径是${basedir}/src/test/resources,测试资源是不部署的。

plugins配置:

<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>2.0</version>
        <extensions>false</extensions>
        <inherited>true</inherited>
        <configuration>
            <classifier>test</classifier>
        </configuration>
        <dependencies>...</dependencies>
        <executions>...</executions>
</plugin>

pluginManagement:<pluginManagement>与<plugins>并列,两者之间的关系类似于<dependencyManagement>与<dependencies>之间的关系。<pluginManagement>中也配置<plugin>,其配置参数与<plugins>中的<plugin>完全一致。

只是,<pluginManagement>往往出现在父项目中,其中配置的<plugin>往往通用于子项目。子项目中只要在<plugins>中以<plugin>声明该插件,该插件的具体配置参数则继承自父项目中<pluginManagement>对该插件的配置,从而避免在子项目中进行重复配置。

3)pom中其它参数设置说明

dependencyManagement:是用于帮助管理chidren的dependencies的。例如如果parent使用dependencyManagement定义了一个dependencyon junit:junit4.0,那么 它的children就可以只引用 groupId和artifactId,而version就可以通过parent来设置,这样的好处就是可以集中管理 依赖的详情

modules:对于多模块的project,outer-module没有必需考虑inner-module的dependencies,当列出modules的时候,modules的顺序是不重要的,因为maven会自动根据依赖关系来拓扑排序。

properties:是用来定义一些配置属性,例如设置编码,版本号等。

reporting设置:reporting包含site生成阶段的一些元素,某些maven plugin可以生成reports并且在reporting下配置。例如javadoc,maven site等,在reporting下配置的report plugin的方法与build几乎一样,最不同的是build的plugin goals在executions下设置,而reporting的configures goals在reporttest。

name:项目除了artifactId外,可以定义多个名称
description: 项目描述
url:项目url
inceptionYear:创始年份

等略...

4)pom引用属性

在pom.xml文件中我们可以使用propertyName的形式引用属性。是值的占位符,类似EL,类似ant的属性,比如propertyName的形式引用属性。是值的占位符,类似EL,类似ant的属性,比如{X},可用于pom文件任何赋值的位置。有以下分类:

  • env.propertyName:这种形式表示引用的是环境变量,比如我们需要引用当前系统的环境变量PATH的时候,就可以使用${env.PATH}。
  • project.propertyName:这种形式表示引用的是当前这个pom.xml中project根元素下面的子元素的值。比如我们需要引用当前project下面的version的时候,就可以使用${project.version}。
  • settings.propertyName:这种形式引用的是Maven本地配置文件settings.xml或本地Maven安装目录下的settings.xml文件根元素settings下的元素。比如我们需要引用settings下的本地仓库localRepository元素的值时,我们可以用${settings.localRepository}
  • Java System Properties:java的系统属性,所有在java中使用java.lang.System.getProperties()能够获取到的属性都可以在pom.xml中引用,比如${java.home}。
  • 自定义:pom.xml中properties元素下面的子元素作为属性。假如在pom.xml中有如下一段代码<hello.world>helloWorld</hello.world>,那么我们就可以使用${hello.world}引用到对应的helloWorld。

九、Maven构建SSM工程实践

实现 SSM 工程构建,规范依赖管理。场景:根据 id 展示商品信息。

1、创建一个 maven 工程

新建一个 ssm_maven  项目,使用下图选中的骨架:

填写坐标:

查看是否使用的自己的私服:

在 main 目录下新建 java 和 resources 文件夹:

把 java 和 resources 文件夹转成 source root:

修改编译版本,在 pom.xml 文件中添加:

<build>
    <plugins>
        <!-- 设置编译版本为 1.8 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version >
            <configuration>
                   <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

先添加 springmvc 的核心依赖的坐标:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
</dependencies>

会发现出现除了 spring-webmvc 以外的其他 jar。因为我们的项目依赖 spring-webmv.jar,而 spring-webmv.jar 会依赖 spring-beans.jar 等等,所以 spring-beans.jar 这些 jar 包也出现在了我 们的 maven 工程中,这种现象我们称为依赖传递。

从下图中可看到他们的关系:(请注意 spring-beans 的版本)。

2、依赖冲突的解决 

接着添加一个依赖:

我们会发现这两个 jar 包同时都依赖了 spring-beans。

但是,spring-webmvc 依赖 spirng-beans-4.2.4,spring-context 依赖 spring-beans-5.0.2,但是发现 spirng-beans-4.2.4 加入到工程中。

而我们希望  spring-beans-5.0.2    加入工程。这就造成了依赖冲突。

解决依赖冲突有以下原则:

maven自动按照下边的原则调解:

1. 第一声明者优先原则

在 pom 文件定义依赖,先声明的依赖为准。

测试:

如果将上边 spring-webmvc 和 spring-context 顺序颠倒,系统将导入 spring-beans-5.0.2。 分析:
由于 spring-webmvc 在前边以 spring-webmvc 依赖的 spring-beans-5.0.2  为准,所以最终spring-beans-5.0.2   添加到了工程中。

2. 路径近者优先原则

例如:还是上述情况,spring-contex 和 spring-webmvc 都会传递过来 spirng-beans,那 如果直接把 spring-beans 的依赖直接写到 pom 文件中,那么项目就不会再使用其他依赖传 递来的 spring-beans,因为自己直接在 pom 中定义 spring-beans 要比其他依赖传递过来的路径要近。

在本工程中的 pom 中加入 spirng-beans-5.0.2 的依赖,根据路径近者优先原则,系统将导入spirng-beans-5.0.2:

上边的问题也可以通过排除依赖方法辅助依赖调解,如下:

比如在依赖 spring-webmvc 的设置中添加排除依赖,排除 spring-beans, 下边的配置表示:依赖 spring-webmvc,但排除 spring-webmvc 所依赖的 spring-beans。

3、锁定版本

面对众多的依赖,有一种方法不用考虑依赖路径、声明优化等因素可以采用直接锁定版 本的方法确定依赖构件的版本,版本锁定后则不考虑依赖的声明顺序或依赖的路径,以锁定 的版本的为准添加到工程中,此方法在企业开发中常用。

如下的配置是锁定了 spring-beans 和 spring-context 的版本:

还可以把版本号提取出来,使用<properties>标签设置成变量。

注意:在工程中锁定依赖的版本并不代表在工程中添加了依赖,如果工程需要添加锁定版本 的依赖则需要单独添加<dependencies></dependencies>标签,如下: 

上边添加的依赖并没有指定版本,原因是已在<dependencyManagement>中锁定了版本, 所以在<dependency>下不需要再指定版本。

4、定义 pom.xml

maven 工程首先要识别依赖,web 工程实现 SSM 整合,需要依赖 spring-webmvc5.0.2、 spring5.0.2、mybatis3.4.5  等,在 pom.xml  添加工程如下依赖:

(在实际企业开发中会有架构师专门来编写 pom.xml)

分两步:

1. 锁定依赖版本

2. 添加依赖

<?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>cn.itcast.ssm_maven</groupId>
    <artifactId>ssm_maven</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <spring.version>5.0.2.RELEASE</spring.version>
        <springmvc.version>5.0.2.RELEASE</springmvc.version>
        <mybatis.version>3.4.5</mybatis.version>
    </properties>

<!--锁定依赖版本-->
  <dependencyManagement>
    <dependencies>
            <!-- Mybatis -->
          <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}</version>
          </dependency>

<!-- springMVC -->
          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${springmvc.version}</version>
          </dependency>

          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
          </dependency>

<!-- spring -->
          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
          </dependency>

          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
          </dependency>

          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
          </dependency>

          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</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-aspects</artifactId>
            <version>${spring.version}</version>
          </dependency>

          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
          </dependency>

          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</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-tx</artifactId>
            <version>${spring.version}</version>
          </dependency>
    </dependencies>

  </dependencyManagement>
<!--添加依赖-->
    <dependencies>
<!-- Mybatis 和 mybatis 与 spring 的整合 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>

<!-- MySql 驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>

<!-- druid 数据库连接池 -->
       <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.9</version>
        </dependency>

<!-- springMVC 核心-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
        </dependency>
    
<!-- spring 相关 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </dependency>
<!-- junit 测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>

<!-- jstl -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>

  <build>
    <plugins>
<!-- 设置编译版本为 1.8 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version >
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <path>/</path>
                <port>8080</port>
            </configuration>
        </plugin>
    </plugins>
  </build>
</project>

5、Dao 

在 src/main/java 中定义 dao 接口,实现根据 id 查询商品信息。

1. pojo 模型类

在 src/main/java 创建模型类:

public class Items { 
    private Integer id; 
    private String name; 
    private Float price; 
    private String pic;
    private Date createtime;
    private String detail;
………
}

2. dao层代码

3. 配置文件

 注意配置文件的位置:

内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"  >
<mapper namespace="cn.itcast.ssm.dao.ItemsMapper" >
    <select id="findById" parameterType="int" resultType="items">
        select * from items where     id=#{id}
    </select>
</mapper>

在 src/main/resources 创建 applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"     xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 数据库连接池 -->
<bean  id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!-- 驱动 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<!-- url -->
<property name="url" value="jdbc:mysql://localhost:3306/maven" />
<!-- 用户名 -->
<property name="username" value="root" />
<!-- 密码 -->
<property name="password" value="root" />
</bean>
<!-- mapper 配置 -->
<!-- 让 spring 管理 sqlsessionfactory 使用 mybatis 和 spring 整合包中的 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据库连接池 -->
<property name="dataSource" ref="dataSource" />
<property name="typeAliasesPackage" value="cn.itcast.ssm.pojo"></property>
</bean>

<!-- mapper 扫描器 :用来产生代理对象-->
<bean   class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.itcast.ssm.dao"></property>
</bean>


</beans>

在 src/main/resources 配置 log4j.properties:

### direct log messages to stdout ### 
log4j.appender.stdout=org.apache.log4j.ConsoleAppender 
log4j.appender.stdout.Target=System.out 
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5 p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
#在开发阶段日志级别使用 debug
log4j.rootLogger=debug, stdout
### 在日志中输出 sql 的输入参数 ### 
log4j.logger.org.hibernate.type=TRACE

4. 单元测试

在 src/test/java 创建单元测试类:

public class ItemsMapperTest {
    @Test
    public void testFindItemsById() {
        //获取 spring 容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        //获取 Mapper
        ItemsMapper itemsMapper = applicationContext.getBean(ItemsMapper.class);
        //调用 Mapper 方法
        Items items = itemsMapper.findById(1); System.out.println(items);
    }
}

6、Service 层

@Service
@Transactional
public class ItemsServiceImpl implements ItemsService {

        @Autowired
        private ItemsMapper itemsMapper;
        @Override
        public Items findById(int itemId) { return itemsMapper.findById(itemId);
}

 在 applicationContext.xml 中配置 service:

<context:component-scan base-package="cn.itcast.ssm.service"/>

7、Web层

@Controller
@RequestMapping("/items/") 
public class ItemsController {

    @Autowired
    private ItemsService itemsService ;
// 展示商品信息页面
    @RequestMapping("/showItem")
        public String showItem(int id,Model model){ Items items =                 itemsService.findById(id); 
        model.addAttribute("item", items);
        return "viewItem";
}

在springmvc.xml中进行配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">

<context:component-scan
base-package="cn.itcast.ssm.controller"></context:component-scan>

<!--	配置视图解析器的前缀和后缀 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>

Web.xml中加载 spring 容器,配置 springmvc 前端控制器:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<!--	前端控制器 加载 springmvc 容器 -->
<servlet>
<servlet-name>springmvc</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servl et-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<!--	监听器 加载 spring 容器 -->
<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</ listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext*.xml</param-value>
</context-param>
</web-app>

8、JSP

/WEB-INF/jsp/viewItem.jsp配置,如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"	
 	pageEncoding="UTF-8"%>
<%@	taglib	uri="http://java.sun.com/jsp/jstl/core"	prefix="c" %>	
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt"	prefix="fmt"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>商品信息</title>
</head>
<body>
<form>
<table width="100%" border=1>
<tr>
<td>商品名称</td>
 	<td> ${item.name } </td>	
</tr>
<tr>
<td>商品价格</td>
 	<td> ${item.price } </td>	
</tr>
<tr>
<td>生成日期</td>
<td> <fmt:formatDate value="${item.createtime}"
pattern="yyyy-MM-dd HH:mm:ss"/> </td>	
</tr>
<tr>
<td>商品简介</td>
 	<td>${item.detail} </textarea>	
</td>
</tr>
</table>
</form>
</body>
</html>

9、运行与调试

添加 tomcat7 插件,双击右侧 tomcat7 运行:

运行结果如下: 

10、将SSM工程拆分为多个模块开发

分为以下三个模块:

ssm_dao

ssm_service

ssm_web

1. 创建maven-parent 父模块

选择骨架创建父工程:

填写坐标: 

确认使用的是本地仓库:

注意代码所在的路径(默认):

设置项目的打包方式:

在父工程的 pom.xml   中抽取一些重复的配置的,比如:锁定 jar   包的版本、设置编译版本等。

<properties>
    <spring.version>5.0.2.RELEASE</spring.version>
    <springmvc.version>5.0.4.RELEASE</springmvc.version>
    <mybatis.version>3.4.5</mybatis.version>
</properties>

<dependencyManagement>
    <dependencies>
        <!-- Mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}</version>
        </dependency>

        <!-- springMVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${springmvc.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</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-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</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-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>

    </dependencies>
</dependencyManagement>

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

2. 将父工程发布至仓库

父工程创建完成执行 install 将父工程发布到仓库方便子工程继承:

3. 创建dao子模块

在父工程上右击创建maven模块:

选择“跳过骨架选择”: 

填写模块名称:

下一步,确定项目的目录:

打包方式是 jar:

只添加到层的 pom,mybatis 和 spring 的整合相关依赖:

<dependencies>
<!-- Mybatis 和 mybatis 与 spring 的整合 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>

<!-- MySql 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>

<!-- druid 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>

<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>

<!-- spring 相关 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
</dependencies>

把文件夹转成 sources root:

将 ssm_maven 工程中的 dao 接口、映射文件及 pojo 类拷贝到 src/main/java 中: 

将 applicationContext.xml 拆分出一个 applicationContext-dao.xml,此文件中只配置 dao 相关:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">


    <!-- 数据库连接池 -->
    <bean  id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <!-- 驱动 -->
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <!-- url -->
        <property name="url" value="jdbc:mysql://localhost:3306/maven" />
        <!-- 用户名 -->
        <property name="username" value="root" />
        <!-- 密码 -->
        <property name="password" value="root" />
    </bean>
    <!-- mapper 配置 -->
    <!-- 让 spring 管理 sqlsessionfactory 使用 mybatis 和 spring 整合包中的 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 数据库连接池 -->
        <property name="dataSource" ref="dataSource" />
        <property name="typeAliasesPackage" value="cn.itcast.ssm.pojo"></property>
    </bean>

    <!-- mapper 扫描器 :用来产生代理对象-->
    <bean   class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="cn.itcast.ssm.dao"></property>
    </bean>

</beans>

在 dao 模块的 pom.xml 添加 junit 的依赖,添加时 Scope 选择 test:

 

编写 junit 测试代码 :

public class ItemsMapperTest {
    @Test
    public void testFindItemsById() {
        //获取 spring 容器
        ApplicationContext applicationContext = new     ClassPathXmlApplicationContext("classpath:applicationContext-dao.xml");
        //获取 Mapper
        ItemsMapper itemsMapper = applicationContext.getBean(ItemsMapper.class);
        //调用 Mapper 方法
        Items items = itemsMapper.findById(1); System.out.println(items);
}
}

4. 把 dao 模块 install 到本地仓库。

调过测试,install到本地仓库:

5. 创建service子模块

方法同 ssm_dao 模块创建方法,模块名称为 ssm_service。

ssm_service 模块的 pom.xml 文件中需要继承父模块,ssm_service 依赖 ssm_dao 模块,添加
spring 相关的依赖:

<dependencies>
    <!-- spring 相关 -->

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
    </dependency>
    <!--	dao 层的依赖 -->
    <dependency>
        <groupId>cn.itcast.ssm</groupId>
        <artifactId>ssm_dao</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

将 ssm_maven 工程中的 service 接口拷贝到 src/main/java 中:

创建 applicationContext-service.xml,此文件中定义的 service:

<context:component-scan base-package="cn.itcast.ssm"/>

当在写junit测试时发现,代码报出没有找不到类的错误信息:

是因为没有 junit.jar 引起的,为什么会这样呢?我们 ssm_dao  模块中有 junit 依赖而ssm_service 模块依赖了 ssm_dao,难道 junit 不应该传递过来吗?

6. 依赖范围对传递依赖的影响 

是因为依赖会有依赖范围,依赖范围对传递依赖也有影响,例如有 A、B、C,A 依赖 B、B
依赖 C,C 可能是 A 的传递依赖,如下图:

最左边一列为直接依赖,理解为 A 依赖 B 的范围,最顶层一行为传递依赖,理解为B依赖C的范围,行与列的交叉即为 A 传递依赖C的范围。

举例 1:

比如 A  对 B  有 compile  依赖,B  对 C  有 runtime  依赖,那么根据表格所示 A 对 C 有
runtime 依赖。

ssm_dao 依赖 junit,scop 为 test ssm_service 依赖 ssm_dao. 查看下图红色框内所示传递依赖范围:

所以 ssm_dao 工程所依赖的 junit 的 jar 没有加入到 ssm_service 工程。 

举例 2:如果修改 ssm_dao 工程依赖 junit 的 scop 为 compile,ssm_dao 工程所依赖的 junit
的 jar  包会加入到 ssm_service  工程中,符合上边表格所示,查看下图红色框内所示:

遇到依赖没有传递过来的问题我们通常的解决方案是在本工程中直接添加依赖。

把如下依赖添加到 ssm_service  的工程中: 

再看测试代码也不报错了:

 Install 到本地仓库:

7. 创建 web 子模块

选择骨架创建 web 子模块:

确认使用自己的本地仓库:

填写模块名称:

使用骨架创建 web  项目会花费些时间,请耐心等待。

创建 java 和 resources 文件夹,转成 source root:

添加打包方式 war:

ssm_web 模块的 pom.xml 文件中需要继承父模块,ssm_web 依赖 ssm_service 模块,和 springmvc 的依赖:

<?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">
    <parent>
        <artifactId>ssm_parent</artifactId>
        <groupId>cn.itcast.ssm</groupId
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>ssm_web</artifactId>
    <packaging>war</packaging>
    <dependencies>
        <!-- 依赖 service -->
        <dependency>
            <groupId>cn.itcast.ssm</groupId>
            <artifactId>ssm_service</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- springMVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${springmvc.version}</version>
    </dependency>
</dependencies>
</project>

将 ssm_web 工程中的 controller 代码拷贝到 src/main/java 中:

 

拷贝 ssm_web  工程中如下配置文件: 

运行调试:

方法 1:在 ssm_web 工程的 pom.xml 中配置 tomcat 插件运行。

运行 ssm_web 工程它会从本地仓库下载依赖的 jar 包,所以当 ssm_web 依赖的 jar 包内容修 改了必须及时发布到本地仓库,比如:ssm_web 依赖的 ssm_service 修改了,需要及时将ssm_service   发布到本地仓库。

方法 2:在父工程的 pom.xml 中配置 tomcat 插件运行,自动聚合并执行。

推荐方法 2,如果子工程都在本地,采用方法 2 则不需要子工程修改就立即发布到本地仓库, 父工程会自动聚合并使用最新代码执行。

注意:如果子工程和父工程中都配置了  tomcat   插件,运行的端口和路径以子工程为准。

8. 分模块构建工程-依赖整合

每个模块都需要 spring 或者 junit 的 jar,况且最终 package 打完包最后生成的项目中的 jar 就是各个模块依赖的整合,所以我们可以把项目中所需的依赖都可以放到父工程中,模块 中只留模块和模块之间的依赖,那父工程的  pom.xml  可以如下配置:

<properties>
<spring.version>5.0.2.RELEASE</spring.version>
<springmvc.version>5.0.2.RELEASE</springmvc.version>
<mybatis.version>3.4.5</mybatis.version>
</properties>


<dependencyManagement>
<dependencies>
<!-- Mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>

<!-- springMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springmvc.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>

<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>

</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</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-aspects</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</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-tx</artifactId>
<version>${spring.version}</version>
</dependency>

</dependencies>

</dependencyManagement>

<dependencies>
<!-- Mybatis 和 mybatis 与 spring 的整合 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>

<!-- MySql 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>

<!-- druid 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>

<!-- springMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springmvc.version}</version>
</dependency>


<!-- spring 相关 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>

<artifactId>spring-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>


<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>

<!-- spring 相关 事务相关 -->

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>

<!-- junit 测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>

<!-- jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>

</dependencies>


<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<target>1.8</target>
<source>1.8</source>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
</plugin>
</plugins>
</build>

正式开发,不同的项目组开发不同的工程,ssm_dao  工程开发完毕,发布到私服。

ssm_service 从私服下载 dao。

十、Maven常用插件与私服

1、Maven资源

我们可以到以下两个网址搜索需要的jar包及依赖信息。

https://mvnrepository.com/

Maven Central Repository Search

2、Maven常用的插件

maven-shade-plugin:打包所有依赖包并生成可执行jar;

cobertura-maven-plugin:生成单元测试覆盖率报告;

findbugs-maven-plugin:对Java源码进行静态分析以找出潜在问题。

3、Maven私服

公司在自己的局域网内搭建自己的远程仓库服务器,称为私服,私服服务器即是公司内 部的 maven 远程仓库,每个员工的电脑上安装 maven 软件并且连接私服服务器,员工将自 己开发的项目打成  jar     并发布到私服服务器,其它项目组从私服服务器下载所依赖的构件
(jar)。

私服还充当一个代理服务器,当私服上没有 jar 包会从互联网中央仓库自动下载,如下 图:

1. 搭建私服环境 

Nexus 是 Maven 仓库管理器,通过 nexus 可以搭建 maven 仓库,同时 nexus 还提供强 大的仓库管理功能,构件搜索功能等。

下载 Nexus:http://www.sonatype.org/nexus/archived/

2. 安装 nexus

解压 nexus-2.12.0-01-bundle.zip,本教程将它解压在 F 盘,进入 bin 目录:

cmd 进入 bin 目录,执行 nexus.bat install:

安装成功在服务中查看有nexus服务: 

3. 卸载 nexus

cmd 进入 nexus 的 bin 目录,执行:nexus.bat uninstal:

查看 window 服务列表 nexus 已被删除。

4. 启动 nexus

方法 1:cmd 进入 bin 目录,执行 nexus.bat start。

方法 2:直接启动 nexus 服务。

查看 nexus 的配置文件 conf/nexus.properties:

# Jetty section
application-port=8081	# nexus 的访问端口配置 
application-host=0.0.0.0	# nexus 主机监听配置(不用修改) 
nexus-webapp=${bundleBasedir}/nexus		# nexus 工程目录 
nexus-webapp-context-path=/nexus	# nexus 的 web 访问路径
# Nexus section
nexus-work=${bundleBasedir}/../sonatype-work/nexus	# nexus 仓库目录
runtime=${bundleBasedir}/nexus/WEB-INF	# nexus 运行程序目录

访问:http://localhost:8081/nexus/ 

访问:使用 Nexus 内置账户admin/admin123 登陆,点击右上角的Log in,输入账号和密码登陆。

 

登陆成功: 

查看 nexus 的仓库: 

nexus 的仓库有 4 种类型: 

1. hosted,宿主仓库,部署自己的 jar 到这个类型的仓库,包括 releases 和 snapshot 两部 分,Releases 公司内部发布版本仓库、 Snapshots 公司内部测试版本仓库。

2. proxy,代理仓库,用于代理远程的公共仓库,如 maven   中央仓库,用户连接私服,私 服自动去中央仓库下载 jar  包或者插件。

3. group,仓库组,用来合并多个 hosted/proxy  仓库,通常我们配置自己的 maven  连接仓 库组。

4. virtual(虚拟):兼容 Maven1 版本的 jar 或者插件。

nexus 仓库默认在 sonatype-work 目录中:

 

central:代理仓库,代理中央仓库。

  • apache-snapshots:代理仓库(存储 snapshots   构件,代理地址 https://repository.apache.org/snapshots/)
  • central-m1virtual 类型仓库,兼容 Maven1 版本的 jar 或者插件
  • releases:本地仓库,存储 releases  构件。
  • snapshots:本地仓库,存储 snapshots  构件。
  • thirdparty:第三方仓库
  • public:仓库组

5. 将项目发布到私服

企业中多个团队协作开发通常会将一些公用的组件、开发模块等发布到私服供其它团队 或模块开发人员使用。

本例子假设多团队分别开发 ssm_dao、ssm_service、ssm_web,某个团队开发完在 ssm_dao 会将 ssm_dao 发布到私服供 ssm_service 团队使用,本例子会将 ssm_dao 工程打成 jar  包发布到私服。

第一步:需要在客户端即部署 ssm_dao工程的电脑上配置 maven 环境,并修改 settings.xml文件,配置连接私服的用户和密码 。 此用户名和密码用于私服校验,因为私服需要知道上传的账号和密码是否和私服中的账号和密码一致。

<server>
    <id>releases</id>
    <username>admin</username>
    <password>admin123</password>
</server>
<server>
    <id>snapshots</id>
    <username>admin</username>
    <password>admin123</password>
</server>

releases连接发布版本项目仓库,snapshots连接测试版本项目仓库。

第二步: 配置项目 pom.xml。

配置私服仓库的地址,本公司的自己的 jar 包会上传到私服的宿主仓库,根据工程的版本号 决定上传到哪个宿主仓库,如果版本为 release 则上传到私服的 release 仓库,如果版本为 snapshot 则上传到私服的 snapshot 仓库。

<distributionManagement>
    <repository>
        <id>releases</id>
        <url>http://localhost:8081/nexus/content/repositories/releases/</url>
    </repository>
    <snapshotRepository>
        <id>snapshots</id>
        <url>http://localhost:8081/nexus/content/repositories/snapshots/</url>
    </snapshotRepository>
</distributionManagement>

注意:pom.xml 这里<id> 和 settings.xml 配置 <id> 对应!

6. 将项目 dao 工程打成 jar 包发布到私服

1、首先启动 nexus

2、对 ssm_dao 工程执行 deploy 命令

根据本项目pom.xml中version定义决定发布到哪个仓库,如果 version定义为 snapshot, 执行 deploy 后查看 nexus 的 snapshot 仓库,如果 version 定义为 release 则项目将发布到 nexus 的 release 仓库,本项目将发布到 snapshot 仓库:

也可以通过 http 方式查看:

7. 从私服下载 jar 包

没有配置 nexus 之前,如果本地仓库没有,去中央仓库下载,通常在企业中会在局域网 内部署一台私服服务器,有了私服本地项目首先去本地仓库找 jar,如果没有找到则连接私 服从私服下载 jar 包,如果私服没有 jar 包私服同时作为代理服务器从中央仓库下载 jar 包, 这样做的好处是一方面由私服对公司项目的依赖 jar 包统一管理,一方面提高下载速度,项 目连接私服下载 jar    包的速度要比项目连接中央仓库的速度快的多。 

从私服下载 ssm_dao 工程 jar 包:

管理仓库组

nexus中包括很多仓库,hosted 中存放的是企业自己发布的jar包及第三方公司的 jar包, proxy 中存放的是中央仓库的 jar,为了方便从私服下载 jar 包可以将多个仓库组成一个仓库 组,每个工程需要连接私服的仓库组下载 jar包。

打开 nexus 配置仓库组,如下图:

上图中仓库组包括了本地仓库、代理仓库等。

在客户端的 setting.xml 中配置私服的仓库,由于 setting.xml 中没有 repositories 的配置 标签需要使用 profile 定义仓库。

<profile>
<!--profile 的 id-->
<id>dev</id>
<repositories>
<repository>
<!--仓库 id,repositories 可以配置多个仓库,保证 id 不重复-->
<id>nexus</id>
<!--仓库地址,即 nexus 仓库组的地址-->
<url>http://localhost:8081/nexus/content/groups/public/</url>
<!--是否下载 releases 构件-->
<releases>
<enabled>true</enabled>
</releases>
<!--是否下载 snapshots 构件-->
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<!--  插件仓库,maven 的运行依赖插件,也需要从私服下载插件 -->
<pluginRepository>
<!--  插件仓库的 id 不允许重复,如果重复后边配置会覆盖前边 -->
<id>public</id>
<name>Public Repositories</name>
<url>http://localhost:8081/nexus/content/groups/public/</url>
</pluginRepository>
</pluginRepositories>
</profile>

使用 profile  定义仓库需要激活才可生效。 

<activeProfiles>
    <activeProfile>dev</activeProfile>
</activeProfiles>

配置成功后通过 eclipse 查看有效 pom,有效 pom 是 maven 软件最终使用的 pom 内容,程 序员不直接编辑有效 pom,打开有效 pom。

有效 pom 内容如下:

下边的 pom 内容中有两个仓库地址,maven 会先从前边的仓库的找,如果找不到 jar 包再从 下边的找,从而就实现了从私服下载 jar  包。

<repositories>

<repository>

<releases>

<enabled>true</enabled>

</releases>

<snapshots>

<enabled>true</enabled>

</snapshots>

<id>public</id>
<name>Public Repositories</name>
<url>http://localhost:8081/nexus/content/groups/public/</url></repository>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots><id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>Public Repositories</name>
<url>http://localhost:8081/nexus/content/groups/public/ </url>
</pluginRepository>
<pluginRepository>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
</pluginRepository>
</pluginRepositories>

从私服下载 jar 包:

测试1:局域网环境或本地网络即可

在 ssm_service 工程中添加以上配置后,添加 ssm_dao 工程的依赖,删除本地仓库中 ssm_dao
工程,同时在 eclipse 中关闭 ssm_dao 工程。 观察控制台:

项目先从本地仓库找 ssm_dao,找不到从私服找,由于之前执行 deploy 将 ssm_dao 部署到 私服中,所以成功从私服下载 ssm_dao    并在本地仓库保存一份。

如果此时删除私服中的 ssm_dao,执行 update project 之后是否正常? 如果将本地仓库的 ssm_dao 和私服的 ssm_dao 全部删除是否正常?

测试 2:需要互联网环境

在项目的 pom.xml 添加一个依赖,此依赖在本地仓库和私服都不存在,maven 会先从本 地仓库找,本地仓库没有再从私服找,私服没有再去中央仓库下载,jar 包下载成功在私服、 本地仓库分别存储一份。 

8. 把第三方 jar 包放入本地仓库或私服

导入本地库,随便找一个 jar 包测试,可以先 CMD 进入到 jar 包所在位置,运行:

mvn install:install-file -DgroupId=com.alibaba -DartifactId=fastjson -Dversion=1.1.37 -Dfile=fastjson-1.1.37.jar -Dpackaging=jar

导入私服,需要在 maven 软件的核心配置文件 settings.xml 中配置第三方仓库的 server 信息:

<server>
    <id>thirdparty</id>
    <username>admin</username>
    <password>admin123</password>
</server>

才能执行一下命令:

mvn deploy:deploy-file  -DgroupId=com.alibaba  -DartifactId=fastjson -Dversion=1.1.37
-Dpackaging=jar -Dfile=fastjson-1.1.37.jar
-Durl=http://localhost:8081/nexus/content/repositories/thirdparty/
-DrepositoryId=thirdparty

参数说明:

DgroupId 和 DartifactId 构成了该 jar 包在 pom.xml 的坐标,项目就是依靠这两个属性定位。 自己起名字也行。
Dfile      表示需要上传的 jar 包的绝对路径。
Durl       私服上仓库的位置,打开 nexus——>repositories  菜单,可以看到该路径。
DrepositoryId 服务器的表示 id,在 nexus 的 configuration 可以看到。
Dversion    表示版本信息,
关于 jar    包准确的版本: 包的名字上一般会带版本号,如果没有那可以解压该包,会发现一个叫  MANIFEST.MF 的文件,

这个文件就有描述该包的版本信息。

比如 Specification-Version: 2.2 可以知道该包的版本了。 上传成功后,在 nexus 界面点击 3rd party 仓库可以看到这包。

猜你喜欢

转载自blog.csdn.net/qq_35029061/article/details/126827465