大家在做项目的时候如果是web项目,项目又不大的情况下上传图片一般都是上传到项目的webapp目录下面,webapp下面会有一个upload的文件夹,今天给大家分享的是在项目中如何把图片上传到其他服务器,由于java比较笨重,故我用GO语言写了一个小型的上传文件的服务,下面给大家讲解具体怎么使用。
下载后是一个ufserver.exe文件,打开cmd,在命令行中执行ufserver.exe 就可以了,或者直接双击运行。执行成功如下:
如上界面,就一定启动成功啦。
下面附上一个测试的html文件。
默认的端口是9876,当然你也可以在配置文件中修改成自己的端口,配置文件下面会详细讲,
这是上传成后返回的信息如下:
{
"absolutePath": "http://192.168.0.103:9876/2019/09/06/150405-B7z3v113.jpg",
"createTime": "2019-09-06T11:58:42.0186458+08:00",
"fileSize": 3047,
"msg": "successfully",
"originalFileName": "2.jpg",
"relativePath": "/2019/09/06/150405-B7z3v113.jpg",
"statusCode": 200,
"thums": [
"http://localhost:9876/2019/09/08/150405-kj0s66Xa_200_200_3.png"
"http://localhost:9876/2019/09/08/150405-kj0s66Xa_120_120_3.png"
] //>= v6版本中新增,缩略图
}
一些具体的信息都在里边,有绝对路径,相对路径,源文件名等,大家注意了,一般数据库里边保存的相对路径哦,千万不要保存绝对路径,除非是富文本编辑器里边上传图片的时候会保存成绝对路径。不过后面如果静态资源迁移,那就是灾难性的。
上面已经演示了如何上传,下面我们来说说它具体的配置。
第一次运行只会生成static目录,logs目录为服务的请求日志,cfg.json是配置文件,默认可以不需要cfg.json,可以直接运行
cfg.json具体配置如下:
{
"url":"http://localhost", //url为访问的路径,如果不是本电脑,可以配置其他IP或者域名
"port":9876, //访问的端口,默认为9876
"indexFolder":true, //是否开启目录索引,默认为true
"logEnable":true //是否开启访问日志,默认为false,
"staticDirs":["xxx","D:\\tmp\\vvv"], //v2版本中新增
"rewriteUrls": [
{"/resource":"img"}
], //v3新增
"defStaticDir":"static", //默认文件存放的目录为static目录
"enableRate":false, //是否开启限流,开启后默认为1s/10000
"capacity":10000, //限流采用令牌桶算法,桶的容量
"rate":10000, //限流采用令牌桶算法,每秒的速率,建议和capacity一样
"tempPartDir":"C:\\users\\xx", 分片上传时临时文件目录,默认为用户的TMP目录
"isDelSearchDir": false, // v9新增 删除的时候是否开去多目录检索
"delSearchDir":["img","static"] // v9新增 删除文件要检索哪些目录,会去这些文件夹下找对应的文件删除
"webHookEnabled": false, // v10版本新增 启用webhook
"webHookUrl": "http://localhost:9876/webhook", // v10版本新增 webhook地址,默认POST请求
"encrypt":false, //[>=v11]是否开启访问效验
"encryptSalt":"abcdefg1234567a1b2c3d4f5g6", //[>=v11]效验混合加密盐值
"encryptMethod":"md5", //[>=v11]加密方式
"encryptType":"dynamic" //[>=v11] dynamic 、 server ,默认dynamic类型
"encryptUrl" : "http://www.xxxxx.com/vs" //[>=12] 验证sign的url,一般为应用服务器自己的
}
////////////staticDirs参数说明///////////////////
假如您现在的根目录是 D:/tmp,upload-server启动后会生成D:/tmp/static,staticDirs可以让ufserver增加搜索目录,数组中的xxx是相对D:/tmp目录,数组里边可以传相对路径,也可以传绝对路径。
假如有xxx目录下有aa.js ,vvv目录下面bb.js ,那么在浏览器中访问http://localhost:9876/aa.js去会xxx
目录下查找,访问bb.js会去vvv目录下面查找,数组中越靠前优先级越大。
//////////////////rewriteUrls参数说明//////////////
rewriteUrls是一个数组,数组里边是map,键值对形式,他的作用主要是用来url重写,现在配置的有
/resource,img 意思是当我访问/resource/xxx.js 的时候,upload-server会去img目录下面找xxx.js
访问/resource/js/jq.js 会去img目录下面的js目录找jq.js
//////////////////encrypt参数说明//////////////
encrypt表示是否开启效验模式,如果开启后,默认会拦截/upload和/delete请求,会对请求进行判断是否带有加密后的sign值。
效验需要参数
-randomstr(随机字符串)
-timestamp(unix时间戳10为)
-sign(加密后的值)
客户端在上传的时候需要把这个三个值在URL参数中传过来,其中randomstr建议生成uuid,
保证每次不一致,timestamp为时间戳,但是不是当前时间的时间戳,比如说当前的这个sign值有效期是3分
钟,那么timestamp就是3分钟后的时间戳,sign是在应用服务器的服务端加密后的值,sign的加密方式为:
String result = sign+randomstr+timestamp+salt
在对result进行ASCII按从小到大的顺序排序,把排序后的结果进行md5加密
注意上面提到的salt值是在ufserver配置文件中配置,在应用服务器中保存一份,不可泄露。
/upload?sign=61f93003d3b104876558b7064a0ce40b&randomstr=sdf
×tamp=1569826200
====================ufserver处理结果如下=======================
timestamp:1569826200
sign:61f93003d3b104876558b7064a0ce40b
salt:abcdefg1234567a1b2c3d4f5g6
method:md5
encryptStr:00111222233445556666789aabbccdddefffggs
result:5e269c3040a6c16d038a9b9e79719b45
从这个结果中我们可以看到,客户端传过来的是 timestamp、randomstr在加上配置的salt,排序后的结果
为encryptStr,在用encryptStr进行md5加密,加密后的值和传过的sign值进行比对,如果一致,就通过。如果返回错误信息。
//////////////////encryptUrl参数说明//////////////
encryptType如果为server的时候,说明客户端传过来的sign,ufserver会回调encryptUrl并且带上sign参
数和action类型,去请求应用服务器,由应用服务器验证并且返回状态,如果成功返回字符串successfully,
如果sign已经失效,返回非successfully就可以。
server的验证模式为应用服务器生成sign值,sign可以是UUID也可以是其他信息加密而成返回给客户端,客户
端上传文件到ufserver的时候,在url后面带上sign值,ufserver接受到后会以POST请求去请求在ufserver
中配置的encryptUrl,并会在encryptUrl后面以问号参数拼接sign值还有action请求,应用服务器收到后验
证sign是否有效,并且返回对应的状态值。
//////////////////encryptType参数说明//////////////
dynamic:动态加密,可以设置过期时间,一并传递给ufserver,调试相对来说麻烦一些,ufserver参与
加密,按照一定的加密方式来加密验证。
server:服务器验证加密,应用服务器生成sign传递给客户端,客户端传递给ufserver,ufserver发起
回调URL去应用服务器验证,ufserver不参与验证,全部交给应用服务器。
//////////////////IsDelSearchDir参数说明//////////////
如果IsDelSearchDir为true,返回的格式为
{
"msg": "successfully",
"notFiles": [
"img:/2019/09/21/150405-16237U35.png",
"static:/2019/09/21/150405-16237U35.png"
],
"statusCode": 200,
"successs": [
"img:/2019/09/21/150405-7914ZGwv.png"
]
}
如果IsDelSearchDir为false,返回的格式为
{
"msg": "successfully",
"notFiles": [
],
"statusCode": 200,
"successs": [
"/2019/09/21/150405-7B3ZxiR5.png"
]
}
如果文件在对应的目录下没有找到,则在notFiles中返回,删除成功会在successs中返回。
如果开启多目录检索,"img:/2019/09/21/150405-16237U35.png",会在前面加目录名,如果未开启,直接
返回对应的路径。
URL参数详解
上传文件的URL为:/upload
[URL可选参数]
filePath -- 如果自定义路径的话可以传这个参数,格式为 image/xxxx ,不以斜杠开头哦
sign [>=12] -- (可选)加密参数值
rename -- 是否需要重命名,默认为true,建议为true
cfname[>=v8] -- 自定义文件名称,比如文件上传后名称为 xxx.jpg
thum [>=v6] -- 是否需要生成缩略图,参数为true和false,默认为false
async [>=v6] -- 生成缩略图异步生成还是同步执行,默认为true,经测试1s能生成>1000张以上的缩略图
mode [>=v6] -- 生成缩略图模式,参数有1、2、3,2为调整大小,会缩放图片,1和3位裁剪和等比缩放,具体可以传不同的参数来看效果
q [>=v6] -- 生成缩略图的参数,传参形式为:width,height或者width,height|width,height,例如
http://localhost:9876?thum=true&q=300,200这个url会成300*200大小的缩略图,
http://localhost:9876?thum=true&q=300,200|500,600会生成2个缩略图,分别是300*200和500*600
http://localhost:9876?thum=true&q=300,200|500,600|xx,xx|xx,xx 可以生成多重
http://localhost:9876?thum=true&q=300|500|xx|如果是正方形,可以传一个参数
http://localhost:9876?thum=true&q=300,0|200,0高度传0会按照宽度等比缩放
**cfname自定义名称必须要在rname=true的情况下才生效哦**
---------------------------------------------------
分片上传URL为:/upload/part
[URL可选参数]
filePath -- 如果自定义路径的话可以传这个参数,格式为 image/xxxx ,不以斜杠开头哦
rname -- 是否需要重命名,默认为true,建议为true
cfname -- 自定义文件名称,比如文件上传后名称为 xxx.jpg
rpart -- 是否需要对part文件进行检测重写,建议为false
sign [>=12] 加密参数值
[POST参数]
fileId -- 文件ID,必传,由客户端保持唯一,可以使用UUID,ufserver根据fileId来生成临时目录
chunks -- 分块数,总共有多少个块 采用webuploader 参数引用
chunk -- 当前的块索引,采用webuploader 参数引用
size -- 文件的大小字节数
[分配上传成功后返回结果]
{
absolutePath: "http://localhost:9876"
createTime: "2019-09-10T14:25:49.90321+08:00"
fileSize: 3000000
msg: "part successfully"
originalFileName: "syncthing-windows-amd64-v1.2.1.zip"
relativePath: ""
statusCode: 200
thums: null
}
[最后一个分片上传成功后返回结果]
{
absolutePath: "http://localhost:9876/doc/stn.zip"
createTime: "2019-09-10T14:25:50.5484782+08:00"
fileSize: 404187
msg: "successfully"
originalFileName: "syncthing-windows-amd64-v1.2.1.zip"
relativePath: "/doc/stn.zip"
statusCode: 200
thums: null
}
---------------------------------------------------
刪除文件URL为:/delete
[URL可选参数]
fp[>=v9] -- 要删除文件的相对路径,上传成功后返回的相对路径,如果要删除多个,用逗号分隔,比如
http://localhost:9876/delete?fp=/2019/09/21/150405-7B3ZxiR5.png,/2019/09/21/150405-7B3ZxiR2.png
http://localhost:9876/delete?fp=/2019/09/21/150405-7B3ZxiR5.png
各种URL效果图如下:https://blog.csdn.net/qq_24434671/article/details/100625771
大家可能对目录索引不太了解,下面我们来看一下,不开启目录索引的情况下,访问http://localhost:9876,如下:
会出现拒绝访问,下面我们开启目录索引在访问:
可以看到出来了2019,这个2019是怎么来的呢,是static中的目录,static下面有多少目录,在这里都会一一列举出来,大家如果在apache网站上下载过一些jar包之类的,应该就对这类目录索引很熟悉了。
默认上传文件后保存的路径是 yy/mm/dd/hhmmss-8位随机数.后缀
如果想自定义路径怎么办呢,可以这么做:
在form中上传的url后面加参数
在URL后面可以通过filePath参数去传自定义目录http://localhost:9876/upload?filePath=static/images/2019,发现有filepath参数后程序会自动创建你传过的目录路径,注意,这里的filePath的路径是相对于static目录的,就是启动程序后会生成static目录,你传的不管目录是什么,最后都会在static目录下面创建相对目录。如果传的是上面的路径,最后在static目录下面生成的目录结构为
static/static/images/2019
如果不传filePath的话,那么就采取默认的路径规则。
关于自定义文件名
细心的同学可能发现上传后的文件名都是经过重新编制的,那么有些情况下我就想上传原来的文件名并且让程序不要修改,怎么做呢,其实可以在url后面加rename=false参数,具体如下:
这样一来的话上传的时候是什么文件名,返回的就是什么文件名称了,不过这样不建议用,因为如果文件重复的话会进行覆盖,比较危险,不建议这样去传。
关于WebUploader上传案例
选择文件
可以看到,上传成功了。
关于WebUploader分片上传案例
选择文件
chunked:true, //开启分配上传
chunkSize:3000000, //默认1M
chunkRetry:2, //允许自动重试的次数
threads:3, //上传的并发数
formData:{"fileId":"xvvx"},
可以看到,比较重要的就是这几个配置了,前面四个用于开启和配置webuploader的分片上传
可以看到,我上传了一个将近10M左右的,webuploader自动分成了四个分片,浏览器发了8个请求,其中四个是options请求,四个是POST请求,(截图只截了个七个请求),浏览器把10M的文件分成四次分别提交给ufserver,ufserver收到后会在临时目录下为每个chunk创建一个文件,最后把各个小文件合并成一个大文件。
在命令行输入 ufserver.exe --help
可以看到上面有几个参数选项,
以上的选项是在生成缩略图的时候需要用到,注意,如果只传-sp 的话,那么生成后的缩略图的路径是和sp在同目录下,命名是原文件名_w_h.后缀
需要用到jar包如下:
jar包微云地址如下:链接:https://share.weiyun.com/5Lz7Ego 密码:j5rqgz
pom文件依赖:
org.apache.httpcomponents
httpclient
4.5.3
org.apache.httpcomponents
httpmime
4.5.3
Java上传代码如下:
import java.io.File;
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class UploadTest {
public static void main(String[] args) {
String URL = "http://localhost:9876/upload";
String filePath = "C:\\Users\\xxx\\Desktop\\HW\\tp\\TCP.png";
System.out.println(upload(URL,filePath));
}
/**
* 上传文件
*/
public static String upload(String url,String filePath) {
String res = "";
CloseableHttpClient httpclient = HttpClients.createDefault();
try {
HttpPost httppost = new HttpPost(url);
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(200000).setSocketTimeout(200000)
.build();
httppost.setConfig(requestConfig);
FileBody bin = new FileBody(new File(filePath));
StringBody comment = new StringBody("This is comment", ContentType.TEXT_PLAIN);
//这里的name值为upload-file
HttpEntity reqEntity = MultipartEntityBuilder.create().addPart("upload-file", bin)
.addPart("comment", comment).build();
httppost.setEntity(reqEntity);
System.out.println("executing request " + httppost.getRequestLine());
CloseableHttpResponse response = httpclient.execute(httppost);
try {
System.out.println(response.getStatusLine());
HttpEntity resEntity = response.getEntity();
if (resEntity != null) {
String responseEntityStr = EntityUtils.toString(response.getEntity());
System.out.println(responseEntityStr);
res = responseEntityStr;
System.out.println("Response content length: " + resEntity.getContentLength());
}
EntityUtils.consume(resEntity);
} finally {
response.close();
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return res;
}
}
控制台结果如下:
executing request POST http://localhost:9876/upload HTTP/1.1
HTTP/1.1 200 OK
{"absolutePath":"http://localhost:9876/2019/09/20/150405-43ehh0Sb.png","createTime":"2019-09-20T16:44:20.0764262+08:00","fileSize":233095,"msg":"successfully","originalFileName":"TCP.png","relativePath":"/2019/09/20/150405-43ehh0Sb.png","statusCode":200,"thums":null}
Response content length: 267
上面说了这么多,如果您是一般使用,没有特殊要求的话就不需要cfg.json文件,直接把ufserver下载下来运行就行。不需要其他的配置。上传文件时候的name名称是upload-file
上面就是关于ufserver.exe全部的配置和使用方式了,如果您在使用中有什么问题的话可以在评论区留言哦。