大家在做項目的時候如果是web項目,項目又不大的情況下上傳圖片一般都是上傳到項目的webapp目錄下面,webapp下面會有一個upload的文件夾,今天給大家分享的是在項目中如何把圖片上傳到其他服務器,由於java比較笨重,故我用GO語言寫了一個小型的上傳文件的服務,下面給大家講解具體怎麼使用。
微雲鏈接:鏈接:https://share.weiyun.com/5Uqsa4l 密碼:9wpied
下載後是一個ufserver.exe文件,打開cmd,在命令行中執行ufserver.exe 就可以了,或者直接雙擊運行。執行成功如下:
如上界面,就一定啓動成功啦。
下面附上一個測試的html文件。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form action="http://localhost:9876/upload" enctype="multipart/form-data" method="post">
<input type="file" name="upload-file" />
<input type="submit" value="提交" />
</form>
</body>
</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後面加參數
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form action="http://localhost:9876/upload?filePath=static/img/2019" enctype="multipart/form-data" method="post">
<input type="file" name="upload-file" />
<input type="submit" value="提交" />
</form>
</body>
</html>
在URL後面可以通過filePath參數去傳自定義目錄http://localhost:9876/upload?filePath=static/images/2019,發現有filepath參數後程序會自動創建你傳過的目錄路徑,注意,這裏的filePath的路徑是相對於static目錄的,就是啓動程序後會生成static目錄,你傳的不管目錄是什麼,最後都會在static目錄下面創建相對目錄。如果傳的是上面的路徑,最後在static目錄下面生成的目錄結構爲
static/static/images/2019
如果不傳filePath的話,那麼就採取默認的路徑規則。
關於自定義文件名
細心的同學可能發現上傳後的文件名都是經過重新編制的,那麼有些情況下我就想上傳原來的文件名並且讓程序不要修改,怎麼做呢,其實可以在url後面加rename=false參數,具體如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form action="http://localhost:9876/upload?rename=false" enctype="multipart/form-data" method="post">
<input type="file" name="upload-file" />
<input type="submit" value="提交" />
</form>
</body>
</html>
這樣一來的話上傳的時候是什麼文件名,返回的就是什麼文件名稱了,不過這樣不建議用,因爲如果文件重複的話會進行覆蓋,比較危險,不建議這樣去傳。
關於WebUploader上傳案例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" type="text/css" href="css/webuploader.css" />
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/webuploader.min.js"></script>
</head>
<body>
<div id="uploader" class="wu-example">
<!--用來存放文件信息-->
<div id="thelist" class="uploader-list"></div>
<div class="btns">
<div id="picker">選擇文件</div>
</div>
</div>
<script>
var uploader = WebUploader.create({
auto:true,
// swf文件路徑
swf:'js/Uploader.swf',
// 文件接收服務端。
server: 'http://localhost:9876/upload',
/* fileVal:"upload-file", */
fileVal:"upload-file",
// 選擇文件的按鈕。可選。
// 內部根據當前運行是創建,可能是input元素,也可能是flash.
pick: '#picker',
// 不壓縮image, 默認如果是jpeg,文件上傳前會壓縮一把再上傳!
resize: false
})
uploader.on( 'uploadSuccess', function( file ) {
console.log(file)
});
</script>
</body>
</html>
可以看到,上傳成功了。
關於WebUploader分片上傳案例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" type="text/css" href="css/webuploader.css" />
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/webuploader.min.js"></script>
</head>
<body>
<div id="uploader" class="wu-example">
<!--用來存放文件信息-->
<div id="thelist" class="uploader-list"></div>
<div class="btns">
<div id="picker">選擇文件</div>
</div>
</div>
<script>
var uploader = WebUploader.create({
auto:true,
// swf文件路徑
swf:'js/Uploader.swf',
// 文件接收服務端。
server: 'http://localhost:9876/upload/part?filePath=doc&rname=false&cfname=stn.zip',
/* fileVal:"upload-file", */
fileVal:"upload-file",
// 選擇文件的按鈕。可選。
// 內部根據當前運行是創建,可能是input元素,也可能是flash.
pick: '#picker',
chunked:true, //開啓分配上傳
chunkSize:3000000, //默認1M
chunkRetry:2, //允許自動重試的次數
threads:3, //上傳的併發數
formData:{"fileId":"xvvx"},
// 不壓縮image, 默認如果是jpeg,文件上傳前會壓縮一把再上傳!
resize: false
})
uploader.on( 'uploadSuccess', function( file,resp ) {
console.log(file,resp)
});
// 文件上傳過程中創建進度條實時顯示。
uploader.on( 'uploadProgress', function( file, percentage ) {
console.log(file,percentage)
});
</script>
</body>
</html>
chunked:true, //開啓分配上傳
chunkSize:3000000, //默認1M
chunkRetry:2, //允許自動重試的次數
threads:3, //上傳的併發數
formData:{"fileId":"xvvx"},
可以看到,比較重要的就是這幾個配置了,前面四個用於開啓和配置webuploader的分片上傳
可以看到,我上傳了一個將近10M左右的,webuploader自動分成了四個分片,瀏覽器發了8個請求,其中四個是options請求,四個是POST請求,(截圖只截了個七個請求),瀏覽器把10M的文件分成四次分別提交給ufserver,ufserver收到後會在臨時目錄下爲每個chunk創建一個文件,最後把各個小文件合併成一個大文件。
關於ufserver的命令行參數
在命令行輸入 ufserver.exe --help
可以看到上面有幾個參數選項,
- -sp 是source path
- -dp 是 dpath,生成縮略圖後保存的文件名(全路徑哦)
- -w 寬度
- -h 高度
- -m 模式
以上的選項是在生成縮略圖的時候需要用到,注意,如果只傳-sp 的話,那麼生成後的縮略圖的路徑是和sp在同目錄下,命名是原文件名_w_h.後綴
- -s start 用於啓動服務器
- -v 查看當前的版本號
關於用Java代碼上傳文件到ufserver
需要用到jar包如下:
- org.apache.httpcomponents:httpclient:4.5.3
- org.apache.httpcomponents:httpmime:4.5.3
jar包微雲地址如下:鏈接:https://share.weiyun.com/5Lz7Ego 密碼:j5rqgz
pom文件依賴:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.3</version>
</dependency>
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全部的配置和使用方式了,如果您在使用中有什麼問題的話可以在評論區留言哦。