// 存放文件位置的绝对路径
@Value("${d1.upload.file.path}")
private String filePath;
// 存放临时文件位置的绝对路径
@Value("${d1.upload.file.temp}")
private String filePathTemp;
/**
* @Author: Admin_X
* @Date: 2022/4/26 15:35
* @Param request 请求
* @Param chunk 每一块
* @Description: 上传每一块到临时目录
*/
@RequestMapping(method = RequestMethod.POST)
public String upload(HttpServletRequest request, Chunk chunk) throws IOException {
System.out.println("开始时间:"+System.currentTimeMillis());
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
MultipartFile file = chunk.getFile();
if (file == null) {
return "参数校验失败";
}
Integer chunkNumber = chunk.getChunkNumber();
if (chunkNumber == null) {
chunkNumber = 0;
}
File outFile = new File(filePathTemp + File.separator + chunk.getIdentifier(), chunkNumber + ".part");
InputStream inputStream = file.getInputStream();
FileUtils.copyInputStreamToFile(inputStream, outFile);
}
System.out.println("结束时间:"+System.currentTimeMillis());
return "上传成功";
}
/**
* @Author: Admin_X
* @Date: 2022/4/26 15:35
* @Param filename 文件名
* @Param guid 每一块的唯一id
* @Description: 合并所有分片
*/
@GetMapping("/merge")
public String mergeFile(String filename, String guid) throws Exception {
File file = new File(filePathTemp + File.separator + guid);
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null && files.length > 0) {
File partFile = new File(filePath + File.separator + filename);
for (int i = 1; i <= files.length; i++) {
File s = new File(filePathTemp + File.separator + guid, i + ".part");
FileOutputStream destTempfos = new FileOutputStream(partFile, true);
FileUtils.copyFile(s, destTempfos);
destTempfos.close();
}
// 删除文件夹下的所有内容
FileUtils.deleteDirectory(file);
// 删除当前文件夹
FileUtils.deleteDirectory(new File(filePathTemp));
}
}
return "上传失败";
}
上传页面 uploader.vue
<template>
<div class="uploader">
<slot :files="files" :file-list="fileList" :started="started">
<uploader-unsupport>uploader-unsupport>
<uploader-drop>
<p>将文件拖放到此处以上传或p>
<uploader-btn>上传文件uploader-btn>
<uploader-btn :directory="true">上传文件夹uploader-btn>
uploader-drop>
<uploader-list>uploader-list>
slot>
div>
template>
<script>
import Uploader from 'simple-uploader.js'
import { kebabCase } from '../common/utils'
import UploaderBtn from './btn.vue'
import UploaderDrop from './drop.vue'
import UploaderUnsupport from './unsupport.vue'
import UploaderList from './list.vue'
import UploaderFiles from './files.vue'
import UploaderFile from './file.vue'
const COMPONENT_NAME = 'uploader'
const FILE_ADDED_EVENT = 'fileAdded'
const FILES_ADDED_EVENT = 'filesAdded'
const UPLOAD_START_EVENT = 'uploadStart'
export default {
name: COMPONENT_NAME,
provide () {
return {
uploader: this
}
},
props: {
options: {
type: Object,
default () {
return {}
}
},
autoStart: {
type: Boolean,
default: true
},
fileStatusText: {
type: [Object, Function],
default () {
return {
success: 'success',
error: 'error',
uploading: 'uploading',
paused: 'paused',
waiting: 'waiting'
}
}
}
},
data () {
return {
started: false,
files: [],
fileList: []
}
},
methods: {
uploadStart () {
this.started = true
},
fileAdded (file) {
this.$emit(kebabCase(FILE_ADDED_EVENT), file)
if (file.ignored) {
// is ignored, filter it
return false
}
},
filesAdded (files, fileList) {
this.$emit(kebabCase(FILES_ADDED_EVENT), files, fileList)
if (files.ignored || fileList.ignored) {
// is ignored, filter it
return false
}
},
fileRemoved (file) {
this.files = this.uploader.files
this.fileList = this.uploader.fileList
},
filesSubmitted (files, fileList) {
this.files = this.uploader.files
this.fileList = this.uploader.fileList
if (this.autoStart) {
this.uploader.upload()
}
},
allEvent (...args) {
const name = args[0]
const EVENTSMAP = {
[FILE_ADDED_EVENT]: true,
[FILES_ADDED_EVENT]: true,
[UPLOAD_START_EVENT]: 'uploadStart'
}
const handler = EVENTSMAP[name]
if (handler) {
if (handler === true) {
return
}
this[handler].apply(this, args.slice(1))
}
args[0] = kebabCase(name)
this.$emit.apply(this, args)
}
},
created () {
this.options.initialPaused = !this.autoStart
const uploader = new Uploader(this.options)
this.uploader = uploader
this.uploader.fileStatusText = this.fileStatusText
uploader.on('catchAll', this.allEvent)
uploader.on(FILE_ADDED_EVENT, this.fileAdded)
uploader.on(FILES_ADDED_EVENT, this.filesAdded)
uploader.on('fileRemoved', this.fileRemoved)
uploader.on('filesSubmitted', this.filesSubmitted)
},
destroyed () {
const uploader = this.uploader
uploader.off('catchAll', this.allEvent)
uploader.off(FILE_ADDED_EVENT, this.fileAdded)
uploader.off(FILES_ADDED_EVENT, this.filesAdded)
uploader.off('fileRemoved', this.fileRemoved)
uploader.off('filesSubmitted', this.filesSubmitted)
this.uploader = null
},
components: {
UploaderBtn,
UploaderDrop,
UploaderUnsupport,
UploaderList,
UploaderFiles,
UploaderFile
}
}
script>
<style>
.uploader {
position: relative;
}
style>
```html
主页面 App.vue
```html
<template>
<uploader :options="options" :file-status-text="statusText" class="uploader-example" ref="uploader" @file-complete="fileComplete" @complete="complete">uploader>
template>
<script>
export default {
data () {
return {
options: {
target: '//localhost:3000/upload', // '//jsonplaceholder.typicode.com/posts/',
testChunks: false, //上传前判断块是否已经存在
simultaneousUploads: 5, //并发数
chunkSize: 8 * 1024 * 1024 //块大小
},
attrs: {
accept: 'image/*'
},
statusText: {
success: '成功了',
error: '出错了',
uploading: '上传中',
paused: '暂停中',
waiting: '等待中'
}
}
},
methods: {
complete () {
console.log('complete', arguments)
},
fileComplete () {
console.log('file complete', arguments)
const file = arguments[0].file
let url = 'http://localhost:3000/upload/merge?filename=' + file.name + '&guid=' + arguments[0].uniqueIdentifier
this.$axios.get(url).then(function(response) {
}).catch(function (error) {
})
}
},
mounted () {
this.$nextTick(() => {
window.uploader = this.$refs.uploader.uploader
})
}
}
script>
<style>
.uploader-example {
width: 880px;
padding: 15px;
margin: 40px auto 0;
font-size: 12px;
box-shadow: 0 0 10px rgba(0, 0, 0, .4);
}
.uploader-example .uploader-btn {
margin-right: 4px;
}
.uploader-example .uploader-list {
max-height: 440px;
overflow: auto;
overflow-x: hidden;
overflow-y: auto;
}
style>