前端使用UI封装好的upload组件
1.单文件上传
<a-upload
:disabled="!editpersonflag"
name="avatar"
listType="picture-card"
class="avatar-uploader"
:showUploadList="false"
:beforeUpload="beforeUpload"
@change="handleAvatar"
>
<img v-if="imageUrl" :src="imageUrl" alt="avatar" style="width:204px;height:164px">
</a-upload>
// 处理文件上传
handleUpload(file) {
axios({
url: "http://127.0.0.1:9898/filemodule/file/upload",
method: "post",
headers: {
"Content-Type": "multipart/form-data",
token:
localStorage.getItem("token") === null
? ""
: localStorage.getItem("token")
},
data: {
file: file
},
transformRequest: [
function(oldData) {
var form = new FormData();
for (let item in oldData) {
form.append(item, oldData[item]);
}
return form;
}
]
}).then(response => {
if (response.data.code === 200) {
this.$message.success("上传成功");
this.imageUrl = response.data.data.url;
} else {
this.$message.error("上传失败");
}
});
},
beforeUpload() {
return false;
},
2.多文件上传
<!-- 预览图 -->
<b-row class="evaluate-row">
<span class="evaluate-span">预览图</span>
<a-upload multiple :fileList="fileList" :remove="handleRemove" :beforeUpload="beforeUpload">
<a-button>
<a-icon type="upload"/>选择文件
</a-button>
</a-upload>
<a-button
type="primary"
@click="handlePreviewAvatar"
:disabled="fileList.length === 0"
:loading="uploading"
style="margin-left: 16px"
>{{uploading ? '上传中' : '开始上传' }}</a-button>
</b-row>
handleRemove(file) {
const index = this.fileList.indexOf(file);
const newFileList = this.fileList.slice();
newFileList.splice(index, 1);
this.fileList = newFileList;
},
beforeUpload1(file) {
this.fileList = [...this.fileList, file];
return false;
},
// 预览图
handlePreviewAvatar() {
const previewurls = [];
for (var i = 0; i < this.fileList.length; i++) {
axios({
url: "http://127.0.0.1:9898/filemodule/file/upload",
method: "post",
headers: {
"Content-Type": "multipart/form-data",
token:
localStorage.getItem("token") === null
? ""
: localStorage.getItem("token")
},
data: {
file: this.fileList[i]
},
transformRequest: [
function(oldData) {
var form = new FormData();
for (let item in oldData) {
form.append(item, oldData[item]);
}
return form;
}
]
}).then(response => {
if (response.data.code === 200) {
this.$message.success("上传成功");
previewurls.push(response.data.data.url);
this.previewurls = previewurls;
console.log(previewurls);
} else {
this.$message.error("上传失败");
}
});
}
},
3.分片上传(使用blob切片对文件进行切割)
//文件预上传
handlePrepareUpload() {
this.uploading = "上传中";
var file = this.fileList[0];
const fileSize = file.size; // 文件大小
this.filesize = fileSize;
const chunkSize = 1024 * 1024 * 10; // 切片的大小
const chunks = Math.ceil(fileSize / chunkSize); // 获取切片个数
const fileReader = new FileReader();
const spark = new SparkMD5.ArrayBuffer();
const bolbSlice =
File.prototype.slice ||
File.prototype.mozSlice ||
File.prototype.webkitSlice;
let currentChunk = 0;
fileReader.onload = e => {
const res = e.target.result;
spark.append(res);
currentChunk++;
if (currentChunk < chunks) {
loadNext();
} else {
const md5 = spark.end();
this.getMd5Checked(md5);
}
};
const loadNext = () => {
const start = currentChunk * chunkSize;
const end =
start + chunkSize > file.size ? file.size : start + chunkSize;
fileReader.readAsArrayBuffer(bolbSlice.call(file, start, end));
};
loadNext();
},
getMd5Checked(value) {
this.fileMD5 = value;
HttpService.getFileCheckByMd5({ md5: value }).then(response => {
if (response.data.data.md5 !== value) {
const { fileList } = this;
HttpService.getFilePrepare({
extension: fileList[0].name.slice(
fileList[0].name.lastIndexOf(".") + 1
),
chunks: Math.ceil(this.fileList[0].size / 1024 / 1024 / 10)
})
.then(response => {
const downloadaddress = response.data.data.url;
this.downloadaddress = downloadaddress;
const contextId = response.data.data.contextId;
this.filecontextId = contextId;
this.handleUpload(response);
})
.catch(error => {
});
} else {
// 如果文件之前上传过 则返回数据
this.uploading = "上传完成";
this.fileMD5 = response.data.data.md5;
this.filecontextId = response.data.data.contextId;
this.downloadaddress = response.data.data.url;
this.filesize = response.data.data.length;
}
});
},
// 文件上传
handleUpload(res) {
var type = this.fileList[0].type; // 文件类型
var chunk = 1024 * 1024 * 10; // 每个文件切片大小定为10MB .
var blobs = [];
var start = 0;
//文件切割
for (var i = 0; i < Math.ceil(this.fileList[0].size / chunk); i++) {
var end = start + chunk;
blobs[i] = this.fileList[0].slice(start, end, type);
start = end;
}
var uploads = res.data.data.uploads;
var count = 0;
for (var i = 0; i < uploads.length; i++) {
var params = uploads[i].params;
var url = uploads[i].host;
axios({
url: url,
method: "post",
headers: {
"Content-Type": "multipart/form-data"
},
data: {
appKey: params.appKey,
contextId: params.contextId,
expires: params.expires,
token: params.token,
file: blobs[i]
},
transformRequest: [
function(oldData) {
var form = new FormData();
for (let item in oldData) {
form.append(item, oldData[item]);
}
return form;
}
]
})
.then(response => {
count++;
if (count === i) {
HttpService.getFileComplete({
contextId: this.filecontextId,
md5: this.fileMD5
}).then(response => {
this.uploading = "上传完成";
});
}
})
.catch(error => {
});
}
},
服务端代码
web端上传文件后,后端读取文件并存储到静态资源存储位置,并将地址存进数据库,这样通过地址就能访问到资源了,在这之前我们需要配置服务端存储文件的本地文件夹。
# 配置静态文件夹,这是我的图片服务器(可以直接端口地址加文件夹内的名称可以直接访问该文件)
resources:
static-locations: classpath:/META-INF/resources/,classpath:/resources/,\
classpath:/static/,classpath:/public/,file:D:\workspace\imgs
处理上传
@Service(value = "fileSerice")
public class FileService implements IFileService {
@Autowired
private FileMapper fileMapper;
// 当前时间戳
SimpleDateFormat dformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
@Override
public Map<String,Object> insertfile(MultipartFile file,long uploader) {
// 文件本地存储位置
String filepath = "D:\\workspace\\imgs";
// 文件后缀名
String extension = file.getOriginalFilename().substring(file.getOriginalFilename().indexOf('.') + 1);
// 文件前缀名
String suffix = MD5Utils.md5(file.getOriginalFilename());
// 拼接成新的文件名
String fileName = suffix + "." + extension;
// 文件存储到数据库的地址
String url = "http://127.0.0.1:9898/" + fileName;
File dest = new File(filepath + "/" + fileName);
try {
file.transferTo(dest);
} catch (IOException e) {
e.printStackTrace();
}
String md5 = FileUtils.getFileMD5(dest);
Map<String, Object> filemaps = new HashMap<>();
filemaps.put("filename",file.getOriginalFilename());
filemaps.put("length",dest.length());
filemaps.put("md5",md5);
filemaps.put("url",url);
filemaps.put("uploader",uploader);
filemaps.put("uploadDate", dformat.format(new Date()));
Integer num = fileMapper.insertFile(url, md5, file.getOriginalFilename(), dest.length(), uploader,0,uploader, dformat.format(new Date()));
if (num != 1) {
throw new OperationFailException();
}
return filemaps;
}
}
接口部分代码
/**
*文件上传
* zpwan
* 2019/3/25
*/
@RestController
@CrossOrigin
public class FileController {
@Autowired
private FileService fileService;
/**
* 文件上传
* @param file
* @return
*/
@PostMapping(value="/filemodule/file/upload")
public ResultResponse handleUpload(
@RequestParam(value = "file", required = true) MultipartFile file,
HttpServletRequest request
) {
String token = request.getHeader("token");
Long userId = JsonWebTokenUtils.getAppUID(token);
if (file.isEmpty()) {
return new ResultResponse(501, "文件为空,请重新上传");
} else {
Map<String, Object> fileMaps = fileService.insertfile(file,userId);
return new ResultResponse(200, "上传成功", fileMaps);
}
}
}
最近又对之前代码进行了封装,封装成一个函数,实现复用性:
import axios from 'axios'
import { AxiosResponse } from 'axios'
export const handleFileUpload = async (file: File, callback: Function) => {
const res: AxiosResponse<ApiResponse<FileInfo>> = await axios({
url: "http://127.0.0.1:9898/blogManage/filemodule/upload",
method: "post",
headers: {
"Content-Type": "multipart/form-data",
'token': localStorage.getItem('token') === null ? '' : localStorage.getItem('token')
},
data: {
file: file
},
transformRequest: [
function (oldData) {
var form = new FormData();
for (let item in oldData) {
form.append(item, oldData[item]);
}
return form;
}
]
})
callback(res.data);
}