vue-simple-uploader之后端(ssm)实现(补坑
2018-10-20 本文已影响87人
陨石坠灭
实现说一下心得:太坑了,接下来就让我描述一下我的填坑之路,顺便附上代码。
坑的地方说一下,以免读者错过精彩部分:要按照vue-simple-uploader
的要求实现断点续传!!!那么普通的文件上传以及博客上的断点续传就只能借鉴,无法抄袭,坑!!!!
环境说明
前端
- 工具:VSCode
- 框架:vue
后端
- IDE: eclipse
- 开发语言:java
- 框架:ssm、maven
资源说明
vue-uploader: https://github.com/simple-uploader/vue-uploader
操作
将vue-uploader
加入前端项目
npm install vue-simple-uploader --save
然后配置main.js
import Vue from 'vue'
import uploader from 'vue-simple-uploader'
import App from './App.vue'
...
Vue.use(uploader)
...
使用
<template>
<uploader :options="options" class="uploader-example">
<uploader-unsupport></uploader-unsupport>
<uploader-drop>
<p>Drop files here to upload or</p>
<uploader-btn>select files</uploader-btn>
<uploader-btn :attrs="attrs">select images</uploader-btn>
<uploader-btn :directory="true">select folder</uploader-btn>
</uploader-drop>
<uploader-list></uploader-list>
</uploader>
</template>
<script>
export default {
data () {
return {
options: {
//nodejs服务器代码 https://github.com/simple-uploader/Uploader/tree/develop/samples/Node.js
target: '//localhost:8080/example/test/upload'
},
attrs: {
accept: 'video/*'
}
}
}
}
</script>
<style>
...
然后就是服务器代码,创建TestController
,添加upload
方法
...
@Controller
@RequestMapping("test/")
public class TestController{
...
@ResponseBody
@RequestMapping(path = "/upload", method = RequestMethod.POST)
public void upload(HttpServletRequest request, HttpServletResponse response){
UploadUtils.upload(request);
this.success(response, "上传成功!");
}
...
}
其中success
方法
...
@Controller
@RequestMapping("test/")
public class TestController{
...
public void success(HttpServletResponse response, Object obj){
PrintWriter writer = null;
try {
writer = response.getWriter();
writer.write(obj.toString());
} catch(Exception e){} finally{
if( writer != null ){
writer.close();
}
}
}
...
}
UploadUtils
内容
...
public class UploadUtils{
public void upload(HttpServletRequest request){
String path = "E:/tmp/";
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
request.getSession().getServletContext());
if (multipartResolver.isMultipart(request)) {
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
Iterator<String> iter = multiRequest.getFileNames();
while (iter.hasNext()) {
// 一次遍历所有文件
MultipartFile file = multiRequest.getFile(iter.next().toString());
if (file != null) {
String p = path + "/" + file.getOriginalFilename();
// 上传
try {
file.transferTo(new File(p));
return p;
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return null;
}
}
}
按照道理,这里就应该讲完了,但是,但是!上传超过10M的文件就会有问题,原因是你没有实现断点续传!!!
关键是你知道了,也无从下手,不过还好提供了Nodejs
版的服务端代码,就当了一回翻译君
Nodejs
版代码: https://github.com/simple-uploader/Uploader/tree/develop/samples/Node.js
接下来就是本人写的Uploader
类了,对应的js
代码是uploader-node.js
额,代码太多,就先放在最后面了。
先讲一下用法吧。
使用
- 定义
service
@Service
public UploadService extends Uploader{
public UploadService(){
super("E:/tmp/","file");
}
}
- 调用
@Controller
@RequestMapping("test/")
public class TestController{
@Autowired
private UploadService uploadService;
...
@ResponseBody
@RequestMapping(path = "/upload", method = RequestMethod.POST)
public void upload(HttpServletRequest request, HttpServletResponse response){
try{
uploadService.post(request, new Uploader.UploadListener() {
@Override
public void callback(String status, String filename, String original_filename, String identifier, String fileType) {
if(status != null){
this.sucess(status);
}
}
}
}catch(Excetion e){
e.printStackTrace();
}
}
...
}
最后,把success
方法里边的write.close()
给注释掉,不然会报错,具体原因还不知,但是坑定是与异步有关,这也是一大坑呐。。。
好了,改关门放代码了:
//Uploader.java
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
//https://github.com/simple-uploader/Uploader/blob/develop/samples/Node.js/uploader-node.js
/**
* 断点续传
*
* @author 陨石坠灭
*
*/
public class Uploader {
/**
* 临时文件夹
*/
private String temporaryFolder;
/**
* 最大文件大小
*/
private Integer maxFileSize = 52428800;
// private String fileParameterName;
public Uploader(String temporaryFolder, String fileParameterName) {
this.temporaryFolder = temporaryFolder;
File file = new File(temporaryFolder);
if (!file.exists()) {
file.mkdirs();
}
// if (fileParameterName == null) {
// this.fileParameterName = "file";
// } else {
// this.fileParameterName = fileParameterName;
// }
}
public String cleanIdentifier(String identifier) {
return identifier.replaceAll("[^0-9A-Za-z_-]", "");
}
public String getChunkFilename(int chunkNumber, String identifier) {
identifier = cleanIdentifier(identifier);
return new File(temporaryFolder, "uploader-" + identifier + '.' + chunkNumber).getAbsolutePath();
}
public String validateRequest(int chunkNumber, int chunkSize, int totalSize, String identifier, String filename,
Integer fileSize) {
identifier = cleanIdentifier(identifier);
if (chunkNumber == 0 || chunkSize == 0 || totalSize == 0 || identifier.length() == 0
|| filename.length() == 0) {
return "non_uploader_request";
}
int numberOfChunks = (int) Math.max(Math.floor(totalSize / (chunkSize * 1.0)), 1);
if (chunkNumber > numberOfChunks) {
return "invalid_uploader_request1";
}
if (this.maxFileSize != null && totalSize > this.maxFileSize) {
return "invalid_uploader_request2";
}
if (fileSize != null) {
if (chunkNumber < numberOfChunks && fileSize != chunkSize) {
return "invalid_uploader_request3";
}
if (numberOfChunks > 1 && chunkNumber == numberOfChunks
&& fileSize != ((totalSize % chunkSize) + chunkSize)) {
return "invalid_uploader_request4";
}
if (numberOfChunks == 1 && fileSize != totalSize) {
return "invalid_uploader_request5";
}
}
return "valid";
}
public int getParamInt(HttpServletRequest req, String key, int def) {
String value = req.getParameter(key);
try {
return Integer.parseInt(value);
} catch (Exception e) {
}
return def;
}
public String getParamString(HttpServletRequest req, String key, String def) {
String value = req.getParameter(key);
try {
return value == null ? def : value;
} catch (Exception e) {
}
return def;
}
public void get(HttpServletRequest req, UploadListener listener) {
int chunkNumber = this.getParamInt(req, "chunkNumber", 0);
int chunkSize = this.getParamInt(req, "chunkSize", 0);
int totalSize = this.getParamInt(req, "totalSize", 0);
String identifier = this.getParamString(req, "identifier", "");
String filename = this.getParamString(req, "filename", "");
if (validateRequest(chunkNumber, chunkSize, totalSize, identifier, filename, null).equals("valid")) {
String chunkFilename = getChunkFilename(chunkNumber, identifier);
if (new File(chunkFilename).exists()) {
listener.callback("found", chunkFilename, filename, identifier, null);
} else {
listener.callback("not_found", null, null, null, null);
}
} else {
listener.callback("not_found", null, null, null, null);
}
}
public void post(HttpServletRequest req, UploadListener listener) throws IllegalStateException, IOException {
int chunkNumber = this.getParamInt(req, "chunkNumber", 0);
int chunkSize = this.getParamInt(req, "chunkSize", 0);
int totalSize = this.getParamInt(req, "totalSize", 0);
String identifier = this.getParamString(req, "identifier", "");
String filename = this.getParamString(req, "filename", "");
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(req.getSession().getServletContext());
if (multipartResolver.isMultipart(req)) {
// 将request变成多部分request
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) req;
// 获取multiRequest 中所有的文件名
Iterator<String> iter = multiRequest.getFileNames();
while (iter.hasNext()) {
String name = iter.next().toString();
// if (!this.fileParameterName.equals(name)) {
// continue;
// }
MultipartFile file = multiRequest.getFile(name);
if (file != null && file.getSize() > 0) {
String original_filename = file.getOriginalFilename();
// String original_filename =
// files[this.fileParameterName]['originalFilename'];
String validation = validateRequest(chunkNumber, chunkSize, totalSize, identifier, filename,
(int) file.getSize());
if ("valid".equals(validation)) {
String chunkFilename = getChunkFilename(chunkNumber, identifier);
File f = new File(chunkFilename);
if (!f.exists()) {
file.transferTo(f);
}
int currentTestChunk = 1;
int numberOfChunks = (int) Math.max(Math.floor(totalSize / (chunkSize * 1.0)), 1);
currentTestChunk = this.testChunkExists(currentTestChunk, chunkNumber, numberOfChunks,
chunkFilename, original_filename, identifier, listener,"file");
} else {
listener.callback(validation, filename, original_filename, identifier,"file");
}
} else {
listener.callback("invalid_uploader_request", null, null, null, null);
}
}
}
}
private void pipeChunk(int number, String identifier, UploadOptions options, OutputStream writableStream)
throws IOException {
String chunkFilename = getChunkFilename(number, identifier);
if (new File(chunkFilename).exists()) {
FileInputStream inputStream = new FileInputStream(new File(chunkFilename));
int maxlen = 1024;
int len = 0;
try {
byte[] buff = new byte[maxlen];
while ((len = inputStream.read(buff, 0, maxlen)) > 0) {
writableStream.write(buff, 0, len);
}
} finally {
inputStream.close();
}
pipeChunk(number + 1, identifier, options, writableStream);
} else {
if (options.end)
writableStream.close();
if (options.listener != null)
options.listener.onDone();
}
}
public void write(String identifier, OutputStream writableStream, UploadOptions options) throws IOException {
if (options == null) {
options = new UploadOptions();
}
if (options.end == null) {
options.end = true;
}
pipeChunk(1, identifier, options, writableStream);
}
/**
*
* @param currentTestChunk
* @param chunkNumber 当前上传块
* @param numberOfChunks 总块数
* @param filename 文件名称
* @param original_filename 源文件名称
* @param identifier 文件
* @param listener 监听
* @param fileType
* @return
*/
private int testChunkExists(int currentTestChunk, int chunkNumber, int numberOfChunks, String filename,
String original_filename, String identifier, UploadListener listener, String fileType) {
String cfile = getChunkFilename(currentTestChunk, identifier);
if (new File(cfile).exists()) {
currentTestChunk++;
if (currentTestChunk >= chunkNumber) {
if (chunkNumber == numberOfChunks) {
try {
System.out.println("done");
// 文件合并
UploadOptions options = new UploadOptions();
File f = new File(this.temporaryFolder,
identifier + File.pathSeparator + FilenameUtils.getExtension(original_filename));
options.listener = new UploadDoneListener() {
@Override
public void onError(Exception err) {
listener.callback("invalid_uploader_request", f.getAbsolutePath(), original_filename,
identifier, fileType);
clean(identifier, null);
}
@Override
public void onDone() {
listener.callback("done", f.getAbsolutePath(), original_filename, identifier, fileType);
clean(identifier, null);
}
};
this.write(identifier, new FileOutputStream(f), options);
} catch (FileNotFoundException e) {
e.printStackTrace();
listener.callback("invalid_uploader_request", filename, original_filename, identifier,
fileType);
} catch (IOException e) {
e.printStackTrace();
listener.callback("invalid_uploader_request", filename, original_filename, identifier,
fileType);
}
} else {
listener.callback("partly_done", filename, original_filename, identifier, fileType);
}
} else {
return testChunkExists(currentTestChunk, chunkNumber, numberOfChunks, filename, original_filename,
identifier, listener, fileType);
}
} else {
listener.callback("partly_done", filename, original_filename, identifier, fileType);
}
return currentTestChunk;
}
public void clean(String identifier, UploadOptions options) {
if (options == null) {
options = new UploadOptions();
}
pipeChunkRm(1, identifier, options);
}
private void pipeChunkRm(int number, String identifier, UploadOptions options) {
String chunkFilename = getChunkFilename(number, identifier);
File file = new File(chunkFilename);
if (file.exists()) {
try {
file.delete();
} catch (Exception e) {
if (options.listener != null) {
options.listener.onError(e);
}
}
pipeChunkRm(number + 1, identifier, options);
} else {
if (options.listener != null)
options.listener.onDone();
}
}
public static interface UploadListener {
public void callback(String status, String filename, String original_filename, String identifier,
String fileType);
}
public static interface UploadDoneListener {
public void onDone();
public void onError(Exception err);
}
public static class UploadOptions {
public Boolean end;
public UploadDoneListener listener;
}
}