vue悅己SSM(Spring+SpringMVC+MyBatis)

vue-simple-uploader之后端(ssm)实现(补坑

2018-10-20  本文已影响87人  陨石坠灭

实现说一下心得:太坑了,接下来就让我描述一下我的填坑之路,顺便附上代码。

坑的地方说一下,以免读者错过精彩部分:要按照vue-simple-uploader的要求实现断点续传!!!那么普通的文件上传以及博客上的断点续传就只能借鉴,无法抄袭,坑!!!!

环境说明

前端

后端

资源说明

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
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;
    }
}

上一篇下一篇

猜你喜欢

热点阅读