在平時的業務場景中,避免不了,要搭建文件上傳服務器,做爲公共服務。通常狀況,只作了單個文件的上傳,實際業務場景中,卻發現單個文件上傳,並不能知足一些業務需求,所以咱們須要解決如何寫一個同時上傳多個文件的接口,並返回可下載的文件地址;javascript
廢話很少講,再也不從頭創建一個Spring boot
項目,若是不知道的話,請直接前往官網查看實例。html
下面咱們以上傳圖片爲例,示例相對簡單,僅供參考:前端
UploadController.javajava
package com.zz.controllers.fileUpload;
import com.zz.Application;
import com.zz.model.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.UUID;
import static com.zz.config.ConfigConstants.getFileDir;
@RestController
@Configuration
public class UploadController {
private static final Logger log = LoggerFactory.getLogger(Application.class);
@Value("${server.port}")
private String port;
//獲取當前IP地址
public String getIp() {
InetAddress localhost = null;
try {
localhost = Inet4Address.getLocalHost();
} catch (Exception e) {
log.error(e.getMessage());
e.printStackTrace();
}
return localhost.getHostAddress();
}
@PostMapping(value = "/upload", consumes = {"multipart/form-data"})
public Response upload(@RequestParam("file") MultipartFile[] files, Response response) {
log.info("上傳多個文件");
StringBuilder builder = new StringBuilder();
// file address
String fileAddress ="http://"+ getIp()+ ":" + port + File.separator;
ArrayList<String> imgUrls = new ArrayList<String>();
try {
for (int i = 0; i < files.length; i++) {
// old file name
String fileName = files[i].getOriginalFilename();
// new filename
String generateFileName = UUID.randomUUID().toString().replaceAll("-", "") + fileName.substring(fileName.lastIndexOf("."));
// store filename
String distFileAddress = fileAddress + generateFileName;
builder.append(distFileAddress+",");
imgUrls.add(distFileAddress);
// generate file to disk
files[i].transferTo(new File(getFileDir() + generateFileName));
}
} catch (Exception e) {
e.printStackTrace();
}
response.setMsg("success");
log.info(builder.toString());
response.setData(imgUrls);
return response;
}
}
複製代碼
相對於單個文件的接收,咱們這裏直接接受多個file
對象,而後遍歷生成每一個對應的地址。web
其中:spring
getFileDir 設置存放圖片的地址,我選擇存在項目外的其餘地方sql
com.zz.config.ConfigConstants.getFileDir後端
package com.zz.config;
public class ConfigConstants {
public static String fileDir;
public static String getFileDir() {
fileDir = "/Users/wz/projects/blog/uploadFile/";
return fileDir;
}
}
複製代碼
當咱們把文件生成到指定的文件夾後,咱們如何配置在當前server下訪問項目外的靜態文件圖片資源並能夠下載呢?tomcat
這個咱們就要利用spring boot配置文件 application.yml,
當前還有其餘方法好比 WebMvcConfigurer
這裏再也不贅述。bash
application.yml
pring:
jpa:
show-sql: true
hibernate:
ddl-auto: update
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
profiles:
active: dev
# 靜態資源配置
mvc:
static-path-pattern: /**
resources:
static-locations: file:/Users/wz/projects/blog/uploadFile/,classpath:/static/,classpath:/resources/,classpath:/file/,classpath:/templates/
server:
use-forward-headers: true
tomcat:
remote-ip-header: X-Real-IP
protocol-header: X-Forwarded-Proto
#自定義
my:
tokenURL: "55555"
authURL: "88888"
複製代碼
這樣以後咱們在生成的結果中的 http://192.168.31.77:8080/a7ef32e3922b46aea256a93dd53de288.png
,這樣的地址就能夠把文件實質性的指向了file:/Users/wz/projects/blog/uploadFile/
,這樣大體就是一個簡單文件服務器的配置了,固然遠不及此,還有壓縮一類的功能,後續再聊。
後端邏輯已經很清晰;
那前端如何向後端同時發送多個file
對象呢?
html
<input type="file" multiple class="el-upload" accept="image/*" name="file">
複製代碼
js
//upload
var uploadBtn = document.querySelector('.el-upload');
uploadBtn.onchange = function (e) {
let files = this.files;
console.log(this.files);
const xhr = new XMLHttpRequest();
xhr.open("post", "/upload", true);
// xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function () {
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
console.log(JSON.parse(this.responseText));
const {data} = JSON.parse(this.responseText);
if(!data) return;
const imageList = data.slice(0);
let imageStr = '';
imageList.forEach(img=>{
imageStr += `<img src="${img}" />`;
});
document.getElementById("result").innerHTML = imageStr;
}
};
const formData = new FormData();
// 多個file 同時上傳
if(files && files.length){
for (let i=0;i<files.length;i++) {
formData.append("file", files[i])
}
}
console.log(formData);
xhr.send(formData);
};
複製代碼
前端經過FormData
傳參數發送POST請求;
區別於以前的單個formData.append();
這裏咱們能夠同時append
多個相同名字的文件二進制文件流;
如圖結果正常顯示,當咱們部署到服務器的時候,這個就能夠看成一個web服務器供你們使用。
本章完結!