通过使用maven的assembly插件,可以按照我们自定义的要求生成包,比如将配置文件剥离到独立的目录中,加入sh,bat脚本以便在Linux或Windows上通过执行脚本来启动项目。
首先,在项目的main目录下建立assembly文件夹,在assembly下新建assembly.xml文件,内容如下:
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/3.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/3.1.0 http://maven.apache.org/xsd/assembly-3.1.0.xsd">
<id>standalone</id>
<formats>
<format>zip</format>
</formats>
<dependencySets>
</dependencySets>
<files>
<file>
<source>target/${project.artifactId}-${project.version}.jar</source>
<outputDirectory>/</outputDirectory>
</file>
</files>
<fileSets>
<!-- profile替换实在编译阶段完成的,使用assembly插件打包时,不能再从src/main/resources下查找文件,而应该从target/classes下面查找配置文件 -->
<fileSet>
<directory>${project.build.directory}/classes</directory>
<!-- 过滤 -->
<includes>
<include>*.properties</include>
<include>config/*.xml</include>
</includes>
<outputDirectory>/conf</outputDirectory>
<!-- unix文件权限 -->
<fileMode>0644</fileMode>
</fileSet>
<fileSet>
<directory>src/main/assembly/bin</directory>
<outputDirectory>/bin</outputDirectory>
<includes>
<include>start.sh</include>
</includes>
<fileMode>0755</fileMode>
<lineEnding>unix</lineEnding>
</fileSet>
<fileSet>
<directory>src/main/assembly/bin</directory>
<outputDirectory>/bin</outputDirectory>
<includes>
<include>start.bat</include>
</includes>
</fileSet>
</fileSets>
</assembly>
上面的id将作为打包后的文件名的一部分。
format指定打包的格式。
下面的文件拷贝配置需要注意:profile替换实在编译阶段完成的,使用assembly插件打包时,不能再从src/main/resources下查找文件,而应该从target/classes下面查找配置文件。profile替换指的是maven多环境打包替换占位符的过程。这样就把指定的配置文件剥离到了conf下。
下面的文件权限是针对Linux等类Unix系统的。
再往下则是把两个启动脚本打包到bin目录下。
下面看pom配置:
<!-- assembly打包 -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal><!-- 只运行一次 -->
</goals>
<configuration>
<descriptors> <!--描述文件路径 -->
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
pom中配置assembly插件,并指定描述文件路径即可。
再看一下启动脚本,Linux下:
#!/bin/sh
echo "开始启动jetty..."
baseDirForScriptSelf=$(cd "$(dirname "$0")"; pwd)
echo "full path to currently executed script is : ${baseDirForScriptSelf}"
cd ${baseDirForScriptSelf}
cd ..
pwd
nohup java -jar ihotel-0.0.1-SNAPSHOT.jar & #后台持续运行
echo "jetty启动成功!"
exit
baseDirForScriptSelf=
(
c
d
"
(cd "
(cd"(dirname “$0”)"; pwd) 这句话是在Linux下获得当前脚本执行的完整路径。
后面的内容可以根据自己的需要编写。
再看Windows的:
@echo off
@echo "开始启动jetty..."
cd %~dp0
cd ..
start /b java -jar ihotel-0.0.1-SNAPSHOT.jar #后台持续运行
@echo "jetty启动成功!"
exit
cd %~dp0 这句话则是进入到当前脚本执行的目录。%~dp0是获得当前脚本执行的完整路径。
上面的配置是针对springboot应用的。若是SSM框架,则需要内嵌Servlet引擎(Tomcat或者jetty),然后指定带main函数的class。
先看SSM如何内嵌jetty容器:
/**
* @program: iHotel
* @description: web app启动类
* @author: Zhang Ziming
* @create: 2018-04-25 10:53
* 内嵌jetty配置方法参见 http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java
**/
public class Launcher {
public static final int DEFAULT_PORT = 8083;
public static final int DEFAULT_HTTPS_PORT = 443;
private static final String DEFAULT_APP_CONTEXT_PATH = "src/main/webapp";
private static final String DEFAULT_HTTPS_APP_CONTEXT_PATH = "/iHotel"; //maven-shade-plugin打包后默认webapp路径为 /iHotel
public static void main(String[] args) {
Server server = createJettyServer();
try {
server.start();
server.join();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
server.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* @Description: 创建jetty服务器,用于生产环境,开发中不要调用此方法
* @Param: [port, contextPath]
* @return: org.eclipse.jetty.server.Server
* @Author: Zhang Ziming
* @Date: 2018/4/25
*/
public static Server createJettyServer() {
Server server = new Server();
server.setStopAtShutdown(true);
// HTTP Configuration
HttpConfiguration http_config = new HttpConfiguration();
http_config.setSecureScheme("https");
http_config.setSecurePort(8443);
http_config.setOutputBufferSize(32768);
http_config.setRequestHeaderSize(8192);
http_config.setResponseHeaderSize(8192);
http_config.setSendServerVersion(true);
http_config.setSendDateHeader(false);
// httpConfig.addCustomizer(new ForwardedRequestCustomizer());
// === jetty-http.xml ===
ServerConnector http = new ServerConnector(server,
new HttpConnectionFactory(http_config));
http.setPort(DEFAULT_PORT);
http.setIdleTimeout(30000);
server.addConnector(http);
ProtectionDomain protectionDomain = Launcher.class.getProtectionDomain();
URL location = protectionDomain.getCodeSource().getLocation();
String warFile = location.toExternalForm();
WebAppContext context = new WebAppContext(warFile, DEFAULT_HTTPS_APP_CONTEXT_PATH);
context.setServer(server);
// 设置work dir,war包将解压到该目录,jsp编译后的文件也将放入其中。
String currentDir = new File(location.getPath()).getParent();
File workDir = new File(currentDir, "work");
context.setTempDirectory(workDir);
server.setHandler(context);
return server;
}
/**
* @Description: 开发时调用,启动jetty服务器
* @Param: [contextPath]
* @return: org.eclipse.jetty.server.Server
* @Author: Zhang Ziming
* @Date: 2018/4/27
*/
public static Server createDevServer(String contextPath) {
Server server = new Server();
server.setStopAtShutdown(true);
ServerConnector connector = new ServerConnector(server);
// 设置服务端口
connector.setPort(DEFAULT_PORT);
connector.setReuseAddress(false);
server.setConnectors(new Connector[] {connector});
// 设置web资源根路径以及访问web的根路径
WebAppContext webAppCtx = new WebAppContext(DEFAULT_APP_CONTEXT_PATH, contextPath);
webAppCtx.setDescriptor(DEFAULT_APP_CONTEXT_PATH + "/WEB-INF/web.xml");
webAppCtx.setResourceBase(DEFAULT_APP_CONTEXT_PATH);
webAppCtx.setClassLoader(Thread.currentThread().getContextClassLoader());
server.setHandler(webAppCtx);
return server;
}
}
然后在pom中,需要增加maven-antrun-plugin和maven-shade-plugin两个插件:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>main-class-placement</id>
<phase>prepare-package</phase>
<configuration>
<tasks>
<copy todir="${project.build.directory}/${project.artifactId}/">
<fileset dir="${project.build.directory}/classes/">
<include name="com/krund/hotel/manage/Launcher.class" />
</fileset>
</copy>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.krund.hotel.manage.Launcher</mainClass>
</transformer>
</transformers>
<artifactSet>
<includes>
<include>org.eclipse.jetty:*</include>
<include>*:javax.servlet*</include>
<include>org.glassfish:javax.el*</include>
</includes>
</artifactSet>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
上面maven-antrun-plugin中需要指定编译后Launcher.class的路径。maven-shade-plugin中指定Launcher类的包路径。像上面那样配置后,SSM应用不再需要放到web容器中执行,直接执行编译后的jar即可。然后可以再配合上面的assembly打包插件来打包。