第4章--Maven

Maven实战

Java Web应用的部署:

手动式:

编译:javac -cp $CATALINA_HOME/lib/servlet-api.jar web-inf/classes/package/NoodlesServlet.java

打包:jar cvf Restaurant.war .

移动:mv Restaurant.war .../webapps/

项目复杂时:比如项目文件很多 -- IDE如eclipse -->

IDE式:(如eclipse)

下载第三方依赖包,去哪里下载?

目录结构怎么定?

编译、测试、打包、发行,构建流程怎么统一?

项目代码共享和依赖,怎么做?

版本如何管理?

--> 常用工具解决以上问题

Maven:

Java Web的项目构建和依赖管理工具

Apache基金会,开源,由Java写的

选择Maven的理由:

默认对于目录结构进行了限定(约定/惯例优先原则)

提供了三方依赖的管理--解决了依赖的维护问题

提供了一致的项目构建管理方式--减少了构建工作量,降低学习成本

插件式的架构,大量可重用插件

很方便集成了IDE

 

Maven的安装:

依赖JDK

官网:http://maven.apache.org/

$ brew install maven3

配置环境变量:

M2_HOME=/dir to maven/

PATH=$PATH:$M2_HOME/bin

 

Maven在构建项目的时候使用的配置:pom.xml

Maven项目的坐标:定位唯一项目(不可重复)

groupId:组织

artifactId:项目标识符

version:版本号(i.e. <version>1.0.0-SNAPSHOT</version>) (SNAPSHOT表示为开发版本)

其他属性:

packaging:类型,i.e. war

dependencies:依赖的项目

 

基本命令:

mvn archetype:generate:使用模板生成项目

mvn compile:编译

mvn test:单元测试

mvn package:打包War

mvn deploy:部署

mvn site:生成项目相关站点,在线文档之类

mvn clean:清理

mvn install:把包安装到本地仓库,可对其进行依赖

 

Tomcat插件:Tomcat官方提供的Maven插件:实现在Maven中内嵌启动一个Tomcat

mvn  help:describe -Dplugin=tomcat7

常见命令:

mvn tomcat7:run:启动一个嵌入的Tomcat实例

mvn tomcat7:deploy;mvn tomcat7:undeploy等

 

如何使用Maven管理Tomcat项目:

mkdir 创建目录

mvn archetype:generate -DgroupId=com.netease.restaurant -DartifactId=Restaurant -Dpackage=com.netease -Dversion=1.0.0-SNAPSHOT -DarchetypeArtifactId=maven-archetype-webapp 创建项目

 

生成的目录结构:

生成pom.xml:

缺少对servlet的依赖:在<dependencies></dependencies>中添加依赖

配置插件:编译器的插件和tomcat插件

在main下建立java/com/netease文件夹,并把上节课的Java文件拷贝到该文件夹下

拷贝静态资源到webapp文件夹下

替换WEB-INF下的web.xml为上节课写的web.xml

删除webapp下的index.jsp

运行项目:(注意,在Restaurant目录下运行,否则报错)

mvn tomcat7:run

and it is running

open another terminal tab and curl http://localhost:8080/Restaurant/noodles

it works.

 

多个项目之间的依赖问题:

Extend Noodle case:

Add a Kitchen for the purpose of handling with vegetable

Noodle is depended on Kitchen‘s vegetable

Solution:

Add a Kitchen project:

mvn archetype:generate -DgroupId=com.netease.restaurant -DartifactId=Kitchen -Dpackage=com.netease -Dversion=1.0.0-SNAPSHOT -DarchetypeArtifactId=maven-archetype-quickstart

// -DarchetypeArtifactId=maven-archetype-quickstart means its a java program rather than a web app

 

change App.java to Kitchen.java

package com.netease;

public class Kitchen {
    public static String makeNoodles(String vegetable) {
        if (vegetable == null) {
            vegetable = "Tomato";
        }
        StringBuffer s = new StringBuffer();
        s.append("<html><body>\n")
        .append("<h1> Noodles with ")
        .append(vegetable)
        .append("</h1>\n")
        .append("</body></html>");
        return s.toString();
    }
}

为了管理这两个子项目,在顶上创建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.netease.restaurant</groupId>
    <artifactId>restaurant-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name> Multi modules demo </name>

    <modules>
        <module>Restaurant</module>
      <module>Kitchen</module>
    </modules>
</project> 

 

修改Kitchen子项目和Restaurant子项目的pom.xml文件(添加parent)

 

修改NoodleServlet.java:

加入对Kitchen的依赖:import com.netease.Kitchen;

修改vegetable部分的代码

由于NoodleServlet.java对Kitchen有了依赖,所以在Restaurant的pom.xml中加入dependency

NB:不要加入<packaging>jar</packaging>

在main目录下创建resources文件夹

 

修改完成,试一试:

mvn install (在最顶端的pom.xml所在目录下)

install成功,进入Restaurant目录,运行mvn tomcat7:run,成功

 

抛开bash,使用IDE试一试:

打开eclipse,安装maven插件

Help->Install New Software->...cannot find it:

solution -> https://stackoverflow.com/questions/8620127/maven-in-eclipse-step-by-step-installation

import the project:

import->Maven->Existing Maven Projects

Root Directory: maven-restaurant (with pom.xml)

How to run:

右键Restaurant->Run Configuration->Maven Build

Name: Restaurant

Base directory: ${workspace_loc:/Restaurant}

Goals: tomcat7:run

Run.

curl works.

 

Maven核心概念

约定(惯例)优先于配置:对于一些配置,给予默认值,就无需用户进行配置

约定有:

标准的目录结构:

*.java位于src/main/java目录下

*.class位于target目录下

配置文件 如web.xml 及静态文件 如SoyMilk.html 位于src/main/webapp目录下

etc.

项目描述符:pom.xml

Project Object Model 项目对象模型

一个pom.xml定义了一个maven项目

一个构建(artifact)等价于一个项目(project)

配置:

项目类型<packaging>:pom, jar, war

坐标:groupId, artifactId, version

属性:${property}

依赖 <dependency>:详见下

构建配置:i.e. maven-compiler插件的配置项

多项目、继承:<parent> <module>

项目总体信息:name, author等

 

问题:

多个项目配置重复

修改繁琐,比如依赖关系等

依赖版本不一致

配置管理混乱

怎么办?

借助OO思想:pom.xml的继承或覆盖 <parent>

常用继承项:

坐标属性,如groupId;依赖关系的配置;插件配置;一般性信息,如开发者信息等

继承的根在哪?

Super POM:所有的Maven项目的POM都继承Super POM(默认继承于Super POM)

Super POM是Maven的组成部分,定义了一组被所有项目共享的默认设置

如默认的文件位置,统一的插件配置,默认的中央仓库配置等

mvn help:effective-pom:把所有的继承项都继承下来之后的pom内容

i.e. in Restaurant, run mvn help:effective-pom --> tons of contexts are shown.

 

多模块构建中:

有一个parent项目,类型是pom,在该pom中定义<modeles><module>

子模块中配置<parent>以继承

NB: 统一配置提到parent项目中

 

依赖配置:

依赖坐标:groupId, artifactId, version

scope:依赖的范围,常见compile(default): 编译的时候用,打包的时候也会打包 / provided:编译时需要,打包时不需要

用于继承的pom配置:<dependencyManagement>

i.e. 

<project>
    <dependencyManagement>
        <dependencies>
            <dependency>
            ...            

 

 

依赖如何寻找呢?

仓库:

用于统一存储所有maven项目,并提供共享的空间

仓库分类:

本地仓库:在本地目录内,很多时候用于缓存,下次使用无需重新从远程仓库下载。

          默认路径 ~/.m2/repository

远程仓库:本地仓库查找优先,若找不到,到远程仓库查找并下载构件至本地仓库

项目在远程仓库中的路径 /<groupId>/<artifactId>/<version>/<artifactId>-<version>.<packaging>

远程仓库分类:

中央仓库:The Central Repository (自带仓库,有大部分项目,但在中国访问速度较慢)

其他公共仓库:如开源中国社区的maven镜像(oschina.net)

私服:比如公司内部(artifactory),相当于做一个代理

远程仓库的配置:

配置文件settings.xml(对所有依赖而言)

在pom.xml为依赖指定repositories(对单个依赖而言)

 

 

maven的架构:

 

插件(Plugin)式架构:很小的一个引擎+很多插件

 

所有的插件本身也是一个maven构件,由maven仓库管理

 

每一个插件提供多个目标(Goal)。调用目标的格式:mvn <Plugin>:<Goal>

 

 

maven的构建生命周期:

一组有序的阶段:编译,打包,部署等

会根据项目类型来确定每个阶段的动作

三套独立的生命周期:

一些命令:mvn clean/ mvn clean install /mvn package/

clean (删除项目的构建):pre-clean (预处理工作) --> clean (移出构建过程中生成的文件) --> post-clean (善后)

site (生成站点文档):pre-site --> site --> post-site -->site-deploy

default (详解):... -> process-resources -> compile -> ... -> test -> package -> install -> deploy

默认生命周期:整个项目构建的模型

validate:验证项目是否正确,是否拥有构建所需的完整信息

process-resources:复制资源文件到目录下,方便之后打包

compile:编译源代码

test:单元测试

package:打包编译好的代码,比如jar包、war包等

install:把调用的包安装到本地仓库

deploy:最后一个阶段,将包上传到远程仓库

 

maven的生命周期阶段是与目标绑定的,用户通过制定生命周期阶段会隐式地通过插件执行任务

i.e. mvn compile --> mvn compiler:compile

生命周期阶段 目标
process-resources resources:resources
compile compiler:compile
test surefire:test
install install:install
deploy deploy:deploy

 

 

 

 

 

 

 

对于package阶段,会根据项目类型不同,绑定到不同的目标

 

插件的配置:<plugins><plugin>......</plugin>...

查看configuration配置:mvn help:describe -Dplugin=<plugin_name> -Dgoal=<goal> -Ddetail

对于父pom的继承:pluginManagement

maven的内建插件:

i.e. help:mvn help:help -Ddetail=true

tomcat7将tomcat嵌入到maven的plugin中、exec简单的把一个jar包跑起来

 

maven的全局配置文件${M2_HOME}/conf/settings.xml

本地仓库、远程仓库等

 

pom文件summary:

项目关系配置:坐标、多项目、继承关系、依赖

属性:${property}

构建配置:插件配置、生命周期绑定

普通项目属性:作者信息、使用的开源协议

 

maven项目构建summary:

pom.xml:描述项目构建 -- 项目对象模型

依赖仓库:存放三方依赖 -- 依赖管理(从pom.xml读取配置信息)

构建生命周期,不同的构建阶段,depends on particular plugin

构建产出资源文件、源文件、中间产出文件、class文件、打包文件等

 

课程summary:

默认标准的目录结构

pom继承、Super POM、多项目管理

依赖及依赖配置、依赖配置的继承

仓库

构建生命周期

插件plugin、目标goal

 

Maven单元测验:http://www.itnose.net/detail/6632794.html

Maven单元作业:https://my.oschina.net/hava/blog/738572

    http://www.cnblogs.com/windJcoder/p/5382143.html