整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

常用MAVEN打包方式总结

种常用的maven打包插件总结:

一、自带插件:

maven自带的核心插件为Build plugins和Reporting plugins。

mvn compile编译源码实际上就利用到了maven-compiler-plugin,其他phase也类似用到了相应的插件

关于maven自带的核心插件见:http://maven.apache.org/plugins/index.html

核心插件 maven-compiler-plugin

参考地址 http://maven.apache.org/plugins/maven-compiler-plugin/

从3.0版本开始,编译工具默认使用的是 javax.tools.JavaCompiler(从JDK 1.6开始) 如果要强制使用javac来进行编译,需要添加参数forceJavacCompilerUse

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-compiler-plugin</artifactId>

<version>3.6.1</version>

<configuration>

<encoding>utf-8</encoding>

<source>1.7</source>

<!-- 默认1.5 -->

<target>1.7</target>

<!-- 默认1.5 -->

<compilerArgs>

<!-- 传递编译参数 -->

<arg>-verbose</arg>

<arg>-Xlint:all,-options,-path</arg>

</compilerArgs>

<fork>true</fork>

<!-- 配置编译内存参数 -->

<meminitial>128m</meminitial>

<!-- 初始内存 -->

<maxmem>512m</maxmem>

<!-- 最大内存 -->

<executable>${JAVA_1_4_HOME}/bin/javac</executable>

<!-- 指定编译的java库 -->

<compilerVersion>1.3</compilerVersion>

<!-- 指定编译版本 -->

</configuration>

</plugin>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

配置source 和target时,也可以这样配置 实际上这是javac指令可以接受的参数

<properties>

<maven.compiler.source>1.8</maven.compiler.source>

<maven.compiler.target>1.8</maven.compiler.target>

</properties>

  • 1
  • 2
  • 3
  • 4

二、直接打成可执行的jar包。

这种打包方式比较粗暴,将应用的依赖包和程序包打成一个全量包。包会相对较大,但是好处也很明显,不用管依赖包。所以这种方式只适用于比较小的项目,比如搭建微服务这种方式可以适用。

附上关键的服务器执行代码

java -jar dataCleaner.jar 1>/home/credit/app/tracefile 2>/home/credit/app/errorfile &

说明: 最后面的& 表明后台执行。

1> 将运行日志输出到tracefile

2> 将错误日志输出到errorfile

具体参数很多,参考官网页面

官网页面 http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html

<plugin>

<artifactId>maven-assembly-plugin</artifactId>

<configuration>

<descriptorRefs>

<descriptorRef>jar-with-dependencies</descriptorRef>

</descriptorRefs>

</configuration>

</plugin>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

还一种方式,可以使用spring-boot的打包插件进行打包。一般是跟spring boot一起使用的,但是也可以单独利用出来打成可执行的整包。

<plugin>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-maven-plugin</artifactId>

<version>1.3.5.RELEASE</version>

<configuration>

<mainClass>com.ftoul.dataCleaner.DataCleanServiceProvider</mainClass>

<layout>ZIP</layout>

</configuration>

<executions>

<execution>

<goals>

<goal>repackage</goal>

</goals>

</execution>

</executions>

</plugin>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

补充一下,还有一个shade插件也是比较常用的打fat jar包的方式

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-shade-plugin</artifactId>

<version>3.0.0</version>

<executions>

<execution>

<phase>package</phase>

<goals>

<goal>shade</goal>

</goals>

<configuration>

<transformers>

<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">

<manifestEntries>

<Main-Class>org.sonatype.haven.ExodusCli</Main-Class>

<Build-Number>123</Build-Number>

</manifestEntries>

</transformer>

</transformers>

</configuration>

</execution>

</executions>

</plugin>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

三 将依赖包与代码包分开打包

这种打包方式更普遍适用。毕竟依赖的jar包在项目发展中变动会相对较小。一般可配合maven-dependency-plugin 和 maven-jar-plugin 两个插件打包。前者负责依赖包,后者负责程序包。

另外,附上服务器可用的执行脚本。

more runapp.sh

#!/bin/sh

#执行jar包

RUN_LIBS=""

#依赖jar包

SUPPORT_LIBS=""

RUN_LIB_PATH="$HOME/app/lib"

SUPPORT_LIB_PATH="$HOME/app/support"

#加载程序包

for i in ${RUN_LIB_PATH}/* ; do

RUN_LIBS=${RUN_LIBS}:$i

done

#加载依赖包

for i in ${SUPPORT_LIB_PATH}/* ; do

SUPPORT_LIBS=${SUPPORT_LIBS}:$i

done

#整合classpath

CLASSPATH=${RUN_LIBS}:${SUPPORT_LIBS}

export CLASSPATH

#调用java指令执行。-D输入参数 java中可以用 System.getProperties读取。同时指定执行入口类 SpringBootApplication 这是一个典型的Springboot的执行方式。

java -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,address=27899,suspend=n -cp $CLASSPATH -Dspring.profiles.active=prod com.app.SpringBootApplication -D

user.timezone=GMT+08 1>/home/credit/ftoulcloud/bin/tracefile 2>/home/credit/ftoulcloud/bin/errorfile &

echo Start App Success!

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

assembly官网的其他几个示例使用项目的依赖包进行打包

<build>

<plugins>

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-dependency-plugin</artifactId>

<version>3.0.0</version>

<executions>

<execution>

<id>src-dependencies</id>

<phase>package</phase>

<goals>

<!-- use copy-dependencies instead if you don't want to explode the sources -->

<goal>unpack-dependencies</goal>

</goals>

<configuration>

<classifier>sources</classifier>

<failOnMissingClassifierArtifact>false</failOnMissingClassifierArtifact>

<outputDirectory>${project.build.directory}/sources</outputDirectory>

</configuration>

</execution>

</executions>

</plugin>

</plugins>

</build>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

将指定的包打入依赖包

<build>

<plugins>

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-dependency-plugin</artifactId>

<version>3.0.0</version>

<executions>

<execution>

<id>copy</id>

<phase>package</phase>

<goals>

<goal>copy</goal>

</goals>

</execution>

</executions>

<configuration>

<artifactItems>

<artifactItem>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>3.8.1</version>

<type>jar</type>

<overWrite>false</overWrite>

<outputDirectory>${project.build.directory}/alternateLocation</outputDirectory>

<destFileName>optional-new-name.jar</destFileName>

</artifactItem>

</artifactItems>

<outputDirectory>${project.build.directory}/wars</outputDirectory>

<overWriteReleases>false</overWriteReleases>

<overWriteSnapshots>true</overWriteSnapshots>

</configuration>

</plugin>

</plugins>

</build>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

一个可用的示例

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-dependency-plugin</artifactId>

<!-- <version>2.10</version> -->

<executions>

<execution>

<id>copy-dependencies</id>

<phase>package</phase>

<goals>

<goal>copy-dependencies</goal>

</goals>

<configuration>

<outputDirectory>export</outputDirectory> <!-- 将依赖包放入export文件夹 -->

<excludeTransitive>false</excludeTransitive>

<stripVersion>true</stripVersion>

</configuration>

</execution>

</executions>

</plugin>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

四、maven-jar-plugin 将指定的一些文件打包成jar包

这个比较简单。就将指定的文件打成jar包

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-jar-plugin</artifactId>

<version>3.0.2</version>

<configuration> <!-- manifest配置信息 主要是可以配置主执行类。有主执行类,可以用java-jar直接执行。没有的话就需要指定执行类 -->

<archive>

<manifest>

<addClasspath>true</addClasspath>

<classpathPrefix>support/</classpathPrefix>

<mainClass>com.myapp.MyAppApplication</mainClass>

<!-- 可以按上面的方式自己配置,也可以指定MF文件打包。 -->

<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>

</manifest>

</archive>

</configuration>

<executions>

<execution>

<id>myapp1-jar</id>

<phase>package</phase>

<goals>

<goal>jar</goal>

</goals>

<configuration>

<classifier>myapp</classifier>

<includes>

<include>com/myapp/**</include>

<include>mybatis/**</include>

<include>templates/**</include>

<include>*.properties</include>

<include>dubbo.xml</include>

</includes>

</configuration>

</execution>

<execution>

<id>myapp2-jar</id>

<phase>package</phase>

<goals>

<goal>jar</goal>

</goals>

<configuration>

<classifier>myapp2</classifier>

<includes>

<include>com/myapp2/crawler/*</include>

<include>com/myapp2/crawler/*</include>

<include>com/myapp2/utils/**</include>

<include>log4j.properties</include>

</includes>

</configuration>

</execution>

</executions>

</plugin>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

五、其他丰富的三方插件

PMD打包插件。 PMD一个很好用的静态代码检查插件, eclipse可以直接安装插件使用

生成PMD报告

http://maven.apache.org/plugins/maven-pmd-plugin/

只能用于3.3.3以后的maven版本

分析JSP页面

<reporting>

<plugins>

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-pmd-plugin</artifactId>

<version>3.8</version>

<configuration>

<language>jsp</language>

<rulesets>

<ruleset>jsp-basic</ruleset>

</rulesets>

<includes>

<include>**/*.jsp</include>

</includes>

<compileSourceRoots>

<compileSourceRoot>${basedir}/src/main/webapp</compileSourceRoot>

</compileSourceRoots>

</configuration>

</plugin>

</plugins>

</reporting>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

分析JS

<reporting>

<plugins>

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-pmd-plugin</artifactId>

<version>3.8</version>

<configuration>

<language>javascript</language>

<rulesets>

<ruleset>ecmascript-basic</ruleset>

<ruleset>ecmascript-braces</ruleset>

<ruleset>ecmascript-unnecessary</ruleset>

</rulesets>

<includes>

<include>**/*.js</include>

</includes>

<compileSourceRoots>

<compileSourceRoot>${basedir}/src/main/javascript</compileSourceRoot>

</compileSourceRoots>

</configuration>

</plugin>

</plugins>

</reporting>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

代码非法检查

<build>

<plugins>

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-pmd-plugin</artifactId>

<version>3.8</version>

<executions>

<execution>

<goals>

<goal>check</goal>

<goal>cpd-check</goal>

</goals>

</execution>

</executions>

</plugin>

</plugins>

</build>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

制定JDK

<reporting>

<plugins>

<plugin>

<artifactId>maven-pmd-plugin</artifactId>

<version>3.8</version>

<configuration>

<targetJdk>1.6</targetJdk>

</configuration>

</plugin>

</plugins>

</reporting>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

删除PMD报告

<reporting>

<plugins>

<plugin>

<artifactId>maven-pmd-plugin</artifactId>

<version>3.8</version>

<reportSets>

<reportSet>

<reports>

<report>pmd</report>

<report>cpd</report>

</reports>

</reportSet>

</reportSets>

</plugin>

</plugins>

</reporting>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

没事可以经常去官网转转,时不时有些新的打包插件出来。 比如PDF插件 GPG签名插件 TOMCAT插件 JETTY插件 等。 好多好多。用时慢慢去了解。

言:

其他资源可以有两种解读:

  1. 其他资源指除了html,"css","js"等资源
  2. 也可以是通过exclude排除已经配置完的资源,其他一些没有配置的资源


1. webpack打包其他资源流程


1.1 webpack打包其他资源说明

  1. 打包除了html,css,js外的其他资源
  2. 利用exclude来排除已经配置处理文件
  3. 处理所有不是exclude排除的文件
  4. 利用file-loader来处理其他资源文件

这里以图标为例:


1.2 下载字体图标

阿里图标官网: https://www.iconfont.cn/

在阿里图标官网下载你想要的字体图标


1.3 使用字体图标

<span class="iconfont icon-weixin"></span>
<span class="iconfont icon-ziyuan"></span>
<span class="iconfont icon-wodejianying"></span>
<span class="iconfont icon-shouyejianying"></span>
<span class="iconfont icon-sirendingzhi"></span>


1.4 字体图标的打包配置

说明:

  1. 在webpack.config.js中配置css文件的打包
  2. 在webpack.config.js中配置字体图标的打包

代码如下:



在前面

今年国庆假期终于可以憋在家里了不用出门了,不用出去看后脑了,真的是一种享受。这么好的光阴怎么浪费,睡觉、吃饭、打豆豆这怎么可能(耍多了也烦),完全不符合我们程序员的作风,赶紧起来把文章写完。

这篇文章比较基础,在国庆期间的业余时间写的,这几天又完善了下,力求把更多的前端所涉及到的关于文件上传的各种场景和应用都涵盖了,若有疏漏和问题还请留言斧正和补充。

自测读不读

以下是本文所涉及到的知识点,break or continue ?

  • 文件上传原理
  • 最原始的文件上传
  • 使用 koa2 作为服务端写一个文件上传接口
  • 单文件上传和上传进度
  • 多文件上传和上传进度
  • 拖拽上传
  • 剪贴板上传
  • 大文件上传之分片上传
  • 大文件上传之断点续传
  • node 端文件上传

原理概述

原理很简单,就是根据 http 协议的规范和定义,完成请求消息体的封装和消息体的解析,然后将二进制内容保存到文件。

我们都知道如果要上传一个文件,需要把 form 标签的enctype设置为multipart/form-data,同时method必须为post方法。

那么multipart/form-data表示什么呢?

multipart互联网上的混合资源,就是资源由多种元素组成,form-data表示可以使用HTML Forms 和 POST 方法上传文件,具体的定义可以参考RFC 7578。

multipart/form-data 结构

看下 http 请求的消息体



  • 请求头:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDCntfiXcSkPhS4PN 表示本次请求要上传文件,其中boundary表示分隔符,如果要上传多个表单项,就要使用boundary分割,每个表单项由———XXX开始,以———XXX结尾。

  • 消息体- Form Data 部分

每一个表单项又由Content-Type和Content-Disposition组成。

Content-Disposition: form-data 为固定值,表示一个表单元素,name 表示表单元素的 名称,回车换行后面就是name的值,如果是上传文件就是文件的二进制内容。

Content-Type:表示当前的内容的 MIME 类型,是图片还是文本还是二进制数据。

解析

客户端发送请求到服务器后,服务器会收到请求的消息体,然后对消息体进行解析,解析出哪是普通表单哪些是附件。

可能大家马上能想到通过正则或者字符串处理分割出内容,不过这样是行不通的,二进制buffer转化为string,对字符串进行截取后,其索引和字符串是不一致的,所以结果就不会正确,除非上传的就是字符串。

不过一般情况下不需要自行解析,目前已经有很成熟的三方库可以使用。

至于如何解析,这个也会占用很大篇幅,后面的文章在详细说。

最原始的文件上传

使用 form 表单上传文件

在 ie时代,如果实现一个无刷新的文件上传那可是费老劲了,大部分都是用 iframe 来实现局部刷新或者使用 flash 插件来搞定,在那个时代 ie 就是最好用的浏览器(别无选择)。

DEMO



这种方式上传文件,不需要 js ,而且没有兼容问题,所有浏览器都支持,就是体验很差,导致页面刷新,页面其他数据丢失。

HTML

 <form method="post" action="http://localhost:8100" enctype="multipart/form-data">

        选择文件:
            <input type="file" name="f1"/> input 必须设置 name 属性,否则数据无法发送<br/>
<br/>
            标题:<input type="text" name="title"/><br/><br/><br/>

        <button type="submit" id="btn-0">上 传</button>

</form>

复制代码

文件上传接口

服务端文件的保存基于现有的库koa-body结合 koa2实现服务端文件的保存和数据的返回。

在项目开发中,文件上传本身和业务无关,代码基本上都可通用。

在这里我们使用koa-body库来实现解析和文件的保存。

koa-body 会自动保存文件到系统临时目录下,也可以指定保存的文件路径。



然后在后续中间件内得到已保存的文件的信息,再做二次处理。

  • ctx.request.files.f1 得到文件信息,f1为input file 标签的 name
  • 获得文件的扩展名,重命名文件

NODE

/**
 * 服务入口
 */
var http = require('http');
var koaStatic = require('koa-static');
var path = require('path');
var koaBody = require('koa-body');//文件保存库
var fs = require('fs');
var Koa = require('koa2');

var app = new Koa();
var port = process.env.PORT || '8100';

var uploadHost= `http://localhost:${port}/uploads/`;

app.use(koaBody({
    formidable: {
        //设置文件的默认保存目录,不设置则保存在系统临时目录下  os
        uploadDir: path.resolve(__dirname, '../static/uploads')
    },
    multipart: true // 开启文件上传,默认是关闭
}));

//开启静态文件访问
app.use(koaStatic(
    path.resolve(__dirname, '../static') 
));

//文件二次处理,修改名称
app.use((ctx) => {
    var file = ctx.request.files.f1;//得道文件对象
    var path = file.path;
    var fname = file.name;//原文件名称
    var nextPath = path+fname;
    if(file.size>0 && path){
        //得到扩展名
        var extArr = fname.split('.');
        var ext = extArr[extArr.length-1];
        var nextPath = path+'.'+ext;
        //重命名文件
        fs.renameSync(path, nextPath);
    }
    //以 json 形式输出上传文件地址
    ctx.body = `{
        "fileUrl":"${uploadHost}${nextPath.slice(nextPath.lastIndexOf('/')+1)}"
    }`;
});

/**
 * http server
 */
var server = http.createServer(app.callback());
server.listen(port);
console.log('demo1 server start ......   ');
复制代码

CODE

https://github.com/Bigerfe/fe-learn-code/