SSM框架+Plupload实现分块上传大文件示例_java

spring+SpringMVC+MyBatis的框架集合,是关于一个社交平台的网站,类似于facebook,twitter,微博等,起了一个名字叫YouAndMe。我大胆地构想了这个项目应该有一个用户资料共享的平台,或是一部好看的电影,或是一套电视剧,或是居家必备的食谱,也有可能是好看的风景图,各式各样。用户可以搜索想要的资料并下载。因此首先要解决的就是各式各样(大)文件的上传。

文章转载自:http://www.piaodoo.com/ 嗨学网

一:下载Plupload插件并引入相应文件

值得一提的是这个插件只是前端的,后台怎么获取怎么将一个个小块合并等代码是要自己写的。

下载地址:http://www.plupload.com/download,我下的是Plupload 2.1.9 GPLv2版本的,里面有要用到的css以及js。

在项目中需要引入:jQuery.plupload.queue.css,jquery-2.0.0.min.js,plupload.full.min.js,jquery.plupload.queue.js,zh_CN.js这些文件。

二:前端准备

1.首先在html中写入如下代码:

Your browser doesn't have Flash, Silverlight or HTML5 support.

暂停一下 再次开始 注意div的id必须是uploader,这在插件源码里是有规定的;id为toStop与toStart的按钮是我自己加的,目的是为了实现暂停上传与暂停过后的继续上传。

2.页面加载后通过js初始化组件

关于这部分的功能可以查看pluploadQueue的文档:http://www.plupload.com/docs/pluploadQueue。也很容易看懂,这里简单地说说部分参数的意义。

url就是服务器处理该上传的地址。filters是过滤器的意思,规定哪些格式的文件可以上传。dragdrop:true设置了可以拖拽文件至选定框。

注意:在暂停与继续上传时要用到uploader.stop()与uploader.start(),这个uploader实例由KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲uploader").plup…(this[0]).attr(‘id’)]。这样,点击暂停按钮时,当前上传会暂停,点击开始按钮时,又继续。

三:Controller映射

@Autowired
private PluploadService pluploadService;

/*Plupload文件上传处理方法/
@RequestMapping(value="/pluploadUpload")
public void upload(Plupload plupload,HttpServletRequest request,HttpServletResponse response) {

String FileDir = "pluploadDir";//文件保存的文件夹
plupload.setRequest(request);//手动传入Plupload对象HttpServletRequest属性

int userId = ((User)request.getSession().getAttribute("user")).getUserId();

//文件存储绝对路径,会是一个文件夹,项目相应Servlet容器下的"pluploadDir"文件夹,还会以用户唯一id作划分
File dir = new File(request.getSession().getServletContext().getRealPath("/") + FileDir+"/"+userId);
if(!dir.exists()){
  dir.mkdirs();//可创建多级目录,而mkdir()只能创建一级目录
}
//开始上传文件
pluploadService.upload(plupload, dir);

}

在这里,我规定不同用户上传的资料会根据唯一id分开不同的文件夹,基于注释代码很容易看懂,你或许会困惑于Plupload与PluploadService,下面就会给出。

四:Plupload类

package web.plupload;

import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;

/**

  • Plupload实体类固定格式,属性名不可修改
  • 因为MultipartFile要用到Spring web的依赖,而该依赖在web模块中才引入,所以不把该实体类放在entity模块
    /
    public class Plupload {
    /*文件原名/
    private String name;
    /*用户上传资料被分解总块数/
    private int chunks = -1;
    /**当前块数(从0开始计数)
    /
    private int chunk = -1;
    /*HttpServletRequest对象,不会自动赋值,需要手动传入/
    private HttpServletRequest request;
    /*保存文件上传信息,不会自动赋值,需要手动传入/
    private MultipartFile multipartFile;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getChunks() {
return chunks;
}

public void setChunks(int chunks) {
this.chunks = chunks;
}

public int getChunk() {
return chunk;
}

public void setChunk(int chunk) {
this.chunk = chunk;
}

public HttpServletRequest getRequest() {
return request;
}

public void setRequest(HttpServletRequest request) {
this.request = request;
}

public MultipartFile getMultipartFile() {
return multipartFile;
}

public void setMultipartFile(MultipartFile multipartFile) {
this.multipartFile = multipartFile;
}
}

再次提醒类名与属性名不可随意改变。通过规定好的正确的属性名,客户端通过Http发送块文件至服务端Controller,得到的plupload对象才能传入正确的文件信息。
关于属性的说明代码注释已经说得很清楚了,可以自行研究学习。

五:PluploadService类

package web.plupload;

import entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import java.io.*;
import java.sql.Timestamp;
import java.util.Iterator;
import java.util.List;

import service.youandmeService;

/**

  • Plupload Service模块,同Plupload实体类一样,因为要用到Spring web相关依赖,所以不将其放在Service模块
    */
    @Component //将写好的类注入SpringIOC容器中让Controller自动装载
    public class PluploadService {

@Autowired
private youandmeService youandmeService;

public void upload(Plupload plupload,File pluploadDir){
String fileName = “”+System.currentTimeMillis()+plupload.getName();//在服务器内生成唯一文件名
upload(plupload, pluploadDir, fileName);
}

private void upload(Plupload plupload,File pluploadDir,String fileName){

int chunks = plupload.getChunks();//用户上传文件被分隔的总块数
int nowChunk = plupload.getChunk();//当前块,从0开始

//这里Request请求类型的强制转换可能出错,配置文件中向SpringIOC容器引入multipartResolver对象即可。
MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest)plupload.getRequest();
//调试发现map中只有一个键值对
MultiValueMap<String,MultipartFile> map = multipartHttpServletRequest.getMultiFileMap();

if(map!=null){
  try{
    Iterator<String> iterator = map.keySet().iterator();
    while(iterator.hasNext()){

      String key = iterator.next();
      List<MultipartFile> multipartFileList = map.get(key);

      for(MultipartFile multipartFile:multipartFileList){//循环只进行一次

        plupload.setMultipartFile(multipartFile);//手动向Plupload对象传入MultipartFile属性值
        File targetFile = new File(pluploadDir+"/"+fileName);//新建目标文件,只有被流写入时才会真正存在
        if(chunks>1){//用户上传资料总块数大于1,要进行合并

          File tempFile = new File(pluploadDir.getPath()+"/"+multipartFile.getName());
          //第一块直接从头写入,不用从末端写入
          savePluploadFile(multipartFile.getInputStream(),tempFile,nowChunk==0?false:true);

          if(chunks-nowChunk==1){//全部块已经上传完毕,此时targetFile因为有被流写入而存在,要改文件名字
            tempFile.renameTo(targetFile);

            //每当文件上传完毕,将上传信息插入数据库
            Timestamp now = new Timestamp(System.currentTimeMillis());
            youandmeService.uploadInfo(fileName,((User)(plupload.getRequest().getSession().getAttribute("user"))).getUsername(),now);
          }
        }
        else{
          //只有一块,就直接拷贝文件内容
          multipartFile.transferTo(targetFile);

          //每当文件上传完毕,将上传信息插入数据库
          Timestamp now = new Timestamp(System.currentTimeMillis());
          youandmeService.uploadInfo(fileName, ((User) (plupload.getRequest().getSession().getAttribute("user"))).getUsername(), now);
        }
      }
    }
  }
  catch (IOException e){
    e.printStackTrace();
  }
}

}
private void savePluploadFile(InputStream inputStream,File tempFile,boolean flag){
OutputStream outputStream = null;
try {
if(flag==false){
//从头写入
outputStream = new BufferedOutputStream(new FileOutputStream(tempFile));
}
else{
//从末端写入
outputStream = new BufferedOutputStream(new FileOutputStream(tempFile,true));
}
byte[] bytes = new byte[1024];
int len = 0;
while ((len = (inputStream.read(bytes)))>0){
outputStream.write(bytes,0,len);
}
}
catch (FileNotFoundException e){
e.printStackTrace();
}
catch (IOException e){
e.printStackTrace();
}
finally {
try{
outputStream.close();
inputStream.close();
}
catch (IOException e){
e.printStackTrace();
}
}
}
}

1.PluploadService这个类名是我自己起的,还可以吧~

2.在Controller的最后一行PluploadService.upload(plupload, dir);中将客户端提交至服务器生成的plupload对象与规定保存的文件夹目录,以参数的形式传入PluploadService的upload方法中。

3.在upload(Plupload plupload,File pluploadDir)方法中,为文件生成一个唯一的文件名以便存储在服务器中。

4.chunks是用户一次性选中要上传的文件中当前文件被分隔后的总块数;nowChunk是这次上传中块的编号,从0开始,为什么用”这次“呢?前面提到过Plupload就是依次地将块从客户端提交至服务器,因此在文件上传中,会有很多次Http请求,而同一个文件的chunks是不变的,nowChunk会一次次增加。

5.将HttpServletRequest强制转换为MultipartHttpServletRequest时可能会出错,但这个错误可以避免,只需在SpringIOC容器中注入一个名为multipartResolver的对象




104857600


4096



6.通过MultipartHttpServletRequest拿到MultiValueMap(经过调试发现这个map只有一对键值对),其Value类型为MultipartFile,这个MultipartFile其实就是当前的块,也难怪为什么map中只有一个键值对了。

7.plupload.setMultipartFile(multipartFile);手动为plupload对象传入MultipartFile属性值

8.如果总块数chunks大于1,那就要考虑将上传过来的一个个小块合成一个文件,否则那就直接拷贝块文件到目标文件multipartFile.transferTo(targetFile);

9.在chunks大于1时,首先要新建一个临时文件tempFile,用于不断不断将一个个小块写入这个tempFile,等写完后(chunks-nowChunk==1),就将其重命名(tempFile.renameTo(targetFile);)。

10.savePluploadFile(multipartFile.getInputStream(),tempFile,nowChunk==0?false:true);方法用于合并一个个小块文件,如果是第一块的话,就从头开始写入(new FileOutputStream(tempFile)),否则全部从末端写入(new FileOutputStream(tempFile,true))。

写到这里,基于Plupload实现断点续传的代码已经全部给出了,大家要自己整合至项目中,这里没有给出完整的demo,嗯还是那句话,授之于鱼不如授之以渔。

上传项目效果图:

1.选定上传文件:

这里写图片描述

2.开始上传,有进度条显示:

这里写图片描述

3.暂停上传:

这里写图片描述

4.暂停后继续上传:

这里写图片描述

5.上传完毕:

这里写图片描述

6.目标文件夹下有相应的文件:

这里写图片描述

7.上传过程中的网络请求,体现分块上传:

这里写图片描述

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持敏而好学论坛/嗨学网。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值