1. 关于 Maven 打 war 包
《 》详细介绍了如何在 Eclipse 使用 Maven 新建一个 JEE 项目并对其进行断点跟踪调试,但是没有介绍如何对 JEE 项目打 war 包。其实很简单,你只需要把 pom.xml 中的 <packaging>jar</packaging> 换成 <packaging>war</packaging> 就可以使用 mvn package 命令对其打 war 包了,而不需要添加任何 maven 插件。只要你遵循了 maven 规范(比如照着《 》所述做了),那你打成的 war 包就肯定包含了第三方依赖包:
把这个 war 包丢进 tomcat 的 webapps 目录,重启 tomcat 即可完成了该项目的部署。你唯一需要注意的是,在重启 tomcat 之前把你的 war 重命名为 项目访问路径.war。比如作者打成的 war 包是为 swifton-1.0.0.war,对该项目定义的访问路径是 /swifton,那么我在重启 tomcat 之前需要将其重命名为 swifton.war。
2. 可执行程序打 jar 包
关于可执行程序(需要指定一个 main 类)打 jar 包就没这么方便了,我们需要考虑以下几个问题:- 配置文件需要打进 jar 包;
- 需要指定 main 入口类;
- 所依赖的第三方库也要打进 jar 包;
为了让讨论不那么抽象,我们在 Eclipse 下新建一个 maven 项目 swiftonrsa:

其中,com.defonds.RsaEncryptor 是入口 main 类,其源码如下:
- package com.defonds;
-
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- import com.defonds.service.LinkPayAntharService;
-
- public class RsaEncryptor {
-
- public static void main(String[] args) {
- ApplicationContext context = new ClassPathXmlApplicationContext( "applicationContext.xml");
- LinkPayAntharService linkPayAntharService = (LinkPayAntharService) context.getBean( "linkPayAntharService");
- linkPayAntharService.dealWithYearData();
- }
- }
2.1 配置文件打包不需要额外关注
只要你项目所依赖的配置文件都按照 maven 规范放对位置(src/main/resources),那么打好的 jar 包就会把它们一起打包:
但是这样打好的 jar 包既没有指定 main 入口类,也没有将依赖包打进来,我们运行它:

提示"swiftonrsa-1.0.0.jar中没有主清单属性",我们查看打好 jar 包下 META-INF 目录中的 MANIFEST.MF,其内容如下:
Manifest-Version: 1.0
Built-By: Defonds
Build-Jdk: 1.7.0_67
Created-By: Apache Maven 3.2.3
Archiver-Version: Plexus Archiver
确实没有指出 main 入口类。
2.2 maven-assembly-plugin 插件
于是我们引入了 maven-assembly-plugin 插件,pom.xml 中加入如下代码:- <build>
- <plugins>
- <plugin>
- <artifactId>maven-assembly-plugin </artifactId>
- <configuration>
- <appendAssemblyId>false </appendAssemblyId>
- <descriptorRefs>
- <descriptorRef>jar-with-dependencies </descriptorRef>
- </descriptorRefs>
- <archive>
- <manifest>
- <mainClass>com.defonds.RsaEncryptor </mainClass>
- </manifest>
- </archive>
- </configuration>
- <executions>
- <execution>
- <id>make-assembly </id>
- <phase>package </phase>
- <goals>
- <goal>assembly </goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
执行 mvn assembly:assembly,成功构建 swiftonrsa-1.0.0.jar,查看其打包目录,各种配置文件以及第三方依赖包也都有:

然后查看 META-INF 目录中的 MANIFEST.MF,内容如下:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: Defonds
Build-Jdk: 1.7.0_67
Main-Class: com.defonds.RsaEncryptor
怀着兴奋的心情执行之:

maven-assembly-plugin 插件没有给我们带来惊喜。错误信息如下:
Exception in thread "main" org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/context]
原来这是 assembly 插件的一个 bug: ,它在对第三方打包时,对于 META-INF 下的 spring.handlers,spring.schemas 等多个同名文件进行了覆盖,遗漏掉了一些版本的 xsd 本地映射。
2.3 maven-shade-plugin 插件
有破必有立。 跟帖中有网友推荐了 maven-shade-plugin 插件。于是我们使用 maven-shade-plugin 将 maven-assembly-plugin 替代:- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins </groupId>
- <artifactId>maven-shade-plugin </artifactId>
- <version>1.4 </version>
- <executions>
- <execution>
- <phase>package </phase>
- <goals>
- <goal>shade </goal>
- </goals>
- <configuration>
- <transformers>
- <transformer
- implementation= "org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
- <mainClass>com.defonds.RsaEncryptor </mainClass>
- </transformer>
- <transformer
- implementation= "org.apache.maven.plugins.shade.resource.AppendingTransformer">
- <resource>META-INF/spring.handlers </resource>
- </transformer>
- <transformer
- implementation= "org.apache.maven.plugins.shade.resource.AppendingTransformer">
- <resource>META-INF/spring.schemas </resource>
- </transformer>
- </transformers>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
对于多个第三方包 META-INF 下的同名的 spring.handlers 文件它采取的态度是追加而不是覆盖。执行 maven clean package,成功构建 swiftonrsa-1.0.0.jar,查看其打包目录,各种配置文件以及第三方依赖包也都有,以及 META-INF 目录中的 MANIFEST.MF 的内容,基本如 maven-assembly-plugin 打包后的样子,执行之:

错误信息如下:
java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
这是由于一些包重复引用,打包后的 META-INF 目录多出了一些 *.SF 等文件所致。
有破必有立。博客 给出了解决方案,pom.xml 添加:
- <configuration>
- <filters>
- <filter>
- <artifact>*:* </artifact>
- <excludes>
- <exclude>META-INF/*.SF </exclude>
- <exclude>META-INF/*.DSA </exclude>
- <exclude>META-INF/*.RSA </exclude>
- </excludes>
- </filter>
- </filters>
- </configuration>
于是我们对 maven-shade-plugin 的配置变成这样:
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins </groupId>
- <artifactId>maven-shade-plugin </artifactId>
- <version>1.4 </version>
- <executions>
- <execution>
- <phase>package </phase>
- <goals>
- <goal>shade </goal>
- </goals>
- <configuration>
- <filters>
- <filter>
- <artifact>*:* </artifact>
- <excludes>
- <exclude>META-INF/*.SF </exclude>
- <exclude>META-INF/*.DSA </exclude>
- <exclude>META-INF/*.RSA </exclude>
- </excludes>
- </filter>
- </filters>
- <transformers>
- <transformer
- implementation= "org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
- <mainClass>com.defonds.RsaEncryptor </mainClass>
- </transformer>
- <transformer
- implementation= "org.apache.maven.plugins.shade.resource.AppendingTransformer">
- <resource>META-INF/spring.handlers </resource>
- </transformer>
- <transformer
- implementation= "org.apache.maven.plugins.shade.resource.AppendingTransformer">
- <resource>META-INF/spring.schemas </resource>
- </transformer>
- </transformers>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
再次执行 maven clean package,再次执行成功构建后的 swiftonrsa-1.0.0.jar:

最后两行是具体业务实现类 com.defonds.service.LinkPayAntharServiceImpl 成功执行打印出的 log 日志。
2.4 示例项目
本文示例项目 swiftonrsa 已上传至 CSDN 资源,有兴趣的朋友可以下载下来参考实验,下载地址: 。本文示例项目最终 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>settle </groupId>
- <artifactId>swiftonrsa </artifactId>
- <version>1.0.0 </version>
- <packaging>jar </packaging>
-
- <name>swiftonrsa </name>
- <url>http://maven.apache.org </url>
-
- <properties>
- <project.build.sourceEncoding>UTF-8 </project.build.sourceEncoding>
- </properties>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins </groupId>
- <artifactId>maven-shade-plugin </artifactId>
- <version>1.4 </version>
- <executions>
- <execution>
- <phase>package </phase>
- <goals>
- <goal>shade </goal>
- </goals>
- <configuration>
- <filters>
- <filter>
- <artifact>*:* </artifact>
- <excludes>
- <exclude>META-INF/*.SF </exclude>
- <exclude>META-INF/*.DSA </exclude>
- <exclude>META-INF/*.RSA </exclude>
- </excludes>
- </filter>
- </filters>
- <transformers>
- <transformer
- implementation= "org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
- <mainClass>com.defonds.RsaEncryptor </mainClass>
- </transformer>
- <transformer
- implementation= "org.apache.maven.plugins.shade.resource.AppendingTransformer">
- <resource>META-INF/spring.handlers </resource>
- </transformer>
- <transformer
- implementation= "org.apache.maven.plugins.shade.resource.AppendingTransformer">
- <resource>META-INF/spring.schemas </resource>
- </transformer>
- </transformers>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
-
-
- <dependencies>
-
- <!-- logs -->
- <dependency>
- <groupId>log4j </groupId>
- <artifactId>log4j </artifactId>
- <version>1.2.17 </version>
- </dependency>
-
- <dependency>
- <groupId>commons-logging </groupId>
- <artifactId>commons-logging </artifactId>
- <version>1.2 </version>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j </groupId>
- <artifactId>slf4j-api </artifactId>
- <version>1.7.10 </version>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j </groupId>
- <artifactId>slf4j-log4j12 </artifactId>
- <version>1.7.10 </version>
- </dependency>
-
- <!-- spring -->
- <dependency>
- <groupId>org.springframework </groupId>
- <artifactId>spring-core </artifactId>
- <version>3.2.3.RELEASE </version>
- </dependency>
-
- <dependency>
- <groupId>org.springframework </groupId>
- <artifactId>spring-orm </artifactId>
- <version>3.2.3.RELEASE </version>
- </dependency>
-
- <dependency>
- <groupId>org.springframework </groupId>
- <artifactId>spring-context </artifactId>
- <version>3.2.3.RELEASE </version>
- </dependency>
-
- <!-- ibatis -->
- <dependency>
- <groupId>org.apache.ibatis </groupId>
- <artifactId>ibatis-sqlmap </artifactId>
- <version>2.3.4.726 </version>
- </dependency>
-
- <!-- connector -->
- <dependency>
- <groupId>mysql </groupId>
- <artifactId>mysql-connector-java </artifactId>
- <version>5.1.19 </version>
- </dependency>
-
- <!-- dbcp -->
- <dependency>
- <groupId>commons-dbcp </groupId>
- <artifactId>commons-dbcp </artifactId>
- <version>1.4 </version>
- </dependency>
-
- <dependency>
- <groupId>commons-pool </groupId>
- <artifactId>commons-pool </artifactId>
- <version>1.6 </version>
- </dependency>
-
- <!-- rsa encrypt -->
- <dependency>
- <groupId>org.bouncycastle </groupId>
- <artifactId>bcprov-jdk15on </artifactId>
- <version>1.51 </version>
- </dependency>
-
- <!-- commons-codec -->
- <dependency>
- <groupId>commons-codec </groupId>
- <artifactId>commons-codec </artifactId>
- <version>1.6 </version>
- </dependency>
-
- </dependencies>
- </project>