使用struts2和AJAX实现文件上传并显示进度条

这个是刚进入公司,技术总监叫我做的东西,开始的确没有什么头绪,以前做的项目里只做过上传,下载。而且也只是方法调用。这个方法涉及到对common.fileupload.jar里一个方法的重写,并且要实现进度条。经过两天的奋斗,再浏览了各位前辈们的佳作,终于实现了以下的代码

需要导入的jar包如下:

使用struts2和AJAX实现文件上传并显示进度条
jsp页面:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
   <head>
     
       <title>My JSP 'upload.jsp' starting page</title>
     
  <meta http-equiv="pragma" content="no-cache">
  <meta http-equiv="cache-control" content="no-cache">
  <meta http-equiv="expires" content="0">     
  <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
  <meta http-equiv="description" content="This is my page">
       <style type="text/css"> 
               iframe{   
                       border:none;   
                       width:0;   
                       height:0;   
               }   
                   
               #p_out{   
                   width:200px;   
                   height:12px;   
                   margin:10px 0 0 0;   
                   padding:1px;   
                   font-size:10px;   
                   border:solid #6b8e23 1px;   
               }   
                   
               #p_first{   
                   width:0%;   
                   height:100%;   
                   background-color:red;   
                   margin:0;   
                   padding:0;   
               }   
             
                     #p_second{   
                   width:0%;   
                   height:100%;   
                   background-color:blue;   
                   margin:0;   
                   padding:0;   
               }   
             
                   
               #dis{   
                   margin:0;   
                   padding:0;   
                   text-align:center;   
                   font-size:12px;   
                   height:12px;   
                   width:200px;   
               }   
                   
</style>
       </head> 
       <body> 
               <div class="main"> 
               <div style="width: 250px; margin: 0 auto;"> 
                   
               
                     <div class="errorbox"> 
                               <s:actionerror/> 
                     </div> 
                           
                     <form id="uploadfile_form" name="uploadfile_form" enctype="multipart/form-data"       
                                 method="post" target="uploadfile_iframe">       
                         
                               <input type="file" name="file" /> 
                               <br><br>       
                               <button οnclick="progress()">提交</button>       
                         
                               <div id="p_out">
                               <div id="p_first"></div>
                               </div>       
                               <div id="dis"></div>       
     
                       </form>       
                         
                     <iframe frameborder="0" id="uploadfile_iframe" name="uploadfile_iframe" ></iframe>       
                     <iframe frameborder="0" id="progress_iframe" name="progress_iframe"   ></iframe>       
               </div> 
                   
               </div> 
       </body> 
           
       <script type="text/javascript">
       //上传文件   
       function uploadFile(key){   
               document.forms[0].action = 'uploadfile.action?callback=parent.upload&key='+key;   
               document.forms[0].submit();   
               document.getElementByIdx_x_x('dis').innerHTML = "开始传送数据...";         
       }   
     
       //获取文件上传进度   
       function progress(){   
               document.getElementByIdx_x_x('progress_iframe').src = 'progress.action?callback1=parent.uploadFile&callback2=parent.upload';   
               document.getElementByIdx_x_x('dis').innerHTML = '初始化数据...';   
               document.getElementByIdx_x_x('p_first').style.width = "0%";   
       }   
     
       //更新进度   
       function upload(len, total){   
               document.getElementByIdx_x_x('p_first').style.width = (Math.round(len/total*100))+'%';     
                     
               document.getElementByIdx_x_x('dis').innerHTML = len + '/' + total + ' Byte';   
               if(len === total) {   
                       document.getElementByIdx_x_x('dis').innerHTML = "文件上传完成!";   
               }   
       }               
</script> 
</html> 
 
STRUTS配置文件: 
 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
" http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
  <!-- 设置编码 -->
  <constant name="struts.i18n.encoding" value="gbk" />
 
  <!-- 设置struts2文件上传最大值 -->
  <constant name="struts.multipart.maxSize" value="209715200" />
 
  <!-- 文件上传临时文件保存路径 -->
  <constant name="struts.multipart.saveDir" value="c:\"></constant>
  <bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest"
    name="myRequestParser" class="com.upload.MyRequestParseWrapper" scope="default" />
  <!-- 改成自己定义的文件上传方式 -->
  <constant name="struts.multipart.handler" value="myRequestParser" />
 
  <package name="struts" extends="struts-default" namespace="/">
    <action name="progress" class="com.upload.FileAction" method="progress">
      <result>/file_box_upload.jsp</result>
    </action>
    <action name="uploadfile" class="com.upload.FileAction" method="uploadfile">
      <result>/file_box_upload.jsp</result>
    </action>
  </package>
</struts>
 
upload.java类:该类是采用servlet方法来存放文件
 
package com.upload;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.log4j.Logger;
public class UploadFile {
  private static final Logger LOG = Logger.getLogger(UploadFile.class);// LOG日志
 
  @SuppressWarnings("unchecked")
  public static void upload(HttpServletRequest request,
      HttpServletResponse response) throws IOException {
     LOG.info("客户端提交类型: " + request.getContentType());
     //判断文件类型,为空则报异常
    if (request.getContentType() == null) {
      throw new IOException(
          "the request doesn't contain a multipart/form-data stream");
    }
    String key = request.getParameter("key");
    Progress p = (Progress) request.getSession().getAttribute(key);
    // 设置上传文件总大小
    p.setLength(request.getContentLength());
     LOG.info("上传文件大小为 : " + p.getLength());
    // 上传临时路径
    String path = request.getSession().getServletContext().getRealPath("/file");
     LOG.info("上传临时路径 : " + path);
    // 设置上传工厂
    DiskFileItemFactory factory = new DiskFileItemFactory();
    factory.setRepository(new File(path));
    // 阀值,超过这个值才会写到临时目录
    factory.setSizeThreshold(1024 * 1024 * 10);
    ServletFileUpload upload = new ServletFileUpload(factory);
    // 最大上传限制 200M
    upload.setSizeMax(1024 * 1024 * 200);
    // 设置监听器监听上传进度
    upload.setProgressListener(p);
    try {
       LOG.info("解析上传文件....");
      List<FileItem> items = upload.parseRequest(request);
       LOG.info("上传数据...");
      for (FileItem item : items) {
        // File destFile = new File(path,item.getFieldName());
        // 非表单域
        if (!item.isFormField()) {
           LOG.info("上传路径   : " + path );
          FileOutputStream fos = new FileOutputStream(path
              + item.getName().substring(
                  item.getName().lastIndexOf("\\"),
                  item.getName().length()));
          // 文件全在内存中
          if (item.isInMemory()) {
            fos.write(item.get());
            p.setComplete(true);
          } else {
            InputStream is = item.getInputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) > 0) {
              fos.write(buffer, 0, len);
            }
            is.close();
          }
          fos.close();
           LOG.info("完成上传文件!");
          item.delete();
           LOG.info("删除临时文件!");
          p.setComplete(true);
           LOG.info("更新progress对象状态为完成状态!");
        }
      }
    } catch (Exception e) {
       LOG.error("上传文件出现异常, 错误原因 : " + e.getMessage());
      // 发生错误,进度信息对象设置为完成状态
      p.setComplete(true);
      request.getSession().removeAttribute(key);
    }
  }
 
  public static void execClientScript(HttpServletResponse resposne,
      String script) throws IOException {
    PrintWriter out = resposne.getWriter();
    out.println("<script type='text/javascript'>" + script + "</script>");
    // fix ie problem
    out.println("------------------------------------------------------");
    out.println("------------------------------------------------------");
    out.println("------------------------------------------------------");
    out.println("------------------------------------------------------");
    out.println("------------------------------------------------------");
    out.flush();
  }
 
  public static class Progress implements ProgressListener {
    // 文件总长度
    private long length = 0;
    // 已上传的文件长度
    private long currentLength = 0;
    // 上传是否完成
    private boolean isComplete = false;
   
    @Override
    public void update(long bytesRead, long contentLength, int items) {
      this.currentLength = bytesRead;
    }

    public long getLength() {
      return length;
    }

    public long getCurrentLength() {
      return currentLength;
    }

    public boolean isComplete() {
      return isComplete;
    }

    public void setLength(long length) {
      this.length = length;
    }

    public void setCurrentLength(long currentLength) {
      this.currentLength = currentLength;
    }

    public void setComplete(boolean isComplete) {
      this.isComplete = isComplete;
    }
  }
}
MyRequestParseWrapper.java重写源文件方法,不要其一次上传
package com.upload;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest;

public class MyRequestParseWrapper extends JakartaMultiPartRequest {
 
  @Override
  public void parse(HttpServletRequest servletRequest, String saveDir)
      throws IOException {
    // 什么也不做---
  }
}
 
FileService.java类:这个类是一些方法提取出来写了,在action里直接调用
 
package com.upload;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import javax.activation.DataHandler;

public class FileService {
  // 使用byte[]类型参数上传二进制文件
  public boolean uploadWithByte(byte[] file, String filename) {
    FileOutputStream fos = null;
    try {
      fos = new FileOutputStream(filename);
      fos.write(file);
      fos.close();
    } catch (Exception e) {
      return false;
    } finally {
      if (fos != null) {
        try {
          fos.close();
        } catch (Exception e) {
        }
      }
    }
    return true;
  }
 
  private void writeInputStreamToFile(InputStream is, OutputStream os)
      throws Exception {
    int n = 0;
    byte[] buffer = new byte[8192];
    while ((n = is.read(buffer)) > 0) {
      os.write(buffer, 0, n);
    }
  }
  // 使用DataHandler类型参数上传文件
  public boolean uploadWithDataHandler(DataHandler file, String filename) {
    FileOutputStream fos = null;
    try {
      fos = new FileOutputStream(filename);
      // 可通过DataHandler类的getInputStream方法读取上传数据
      writeInputStreamToFile(file.getInputStream(), fos);
      fos.close();
    } catch (Exception e) {
      return false;
    } finally {
      if (fos != null) {
        try {
          fos.close();
        } catch (Exception e) {
        }
      }
    }
    return true;
  }
}
FileAction.java 这个实现进度条的action,我认为是最重要的一个类
package com.upload;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.upload.UploadFile;
import com.upload.UploadFile.Progress;

public class FileAction extends ActionSupport {
 
  private static final long serialVersionUID = 6649027352616232244L;
  private FileService fileService;
 
  public String preupload() {
    return SUCCESS;
  }
 
  public String uploadfile() {
    try {
      LOG.info("文件上传操作开始");
      HttpServletResponse response = ServletActionContext.getResponse();
      HttpServletRequest request = ServletActionContext.getRequest();
      UploadFile.upload(request, response);
    } catch (IOException e) {
      // LOG.error("上传文件发生异常,错误原因 : " + e.getMessage());
     
    return null;
  }
 
 
  public String progress() {
    System.out.println("begin");
    LOG.info("文件上传进度监测开始");
    HttpServletResponse response = ServletActionContext.getResponse();
    HttpServletRequest request = ServletActionContext.getRequest();
    String callback1 = request.getParameter("callback1");
    String callback2 = request.getParameter("callback2");
    // 缓存progress对象的key值
    String key = Integer.toString(request.hashCode());
    // 新建当前上传文件的进度信息对象
    Progress p = new Progress();
    // 缓存progress对象
    request.getSession().setAttribute(key, p);
    response.setContentType("text/html;charset=UTF-8");
    response.setHeader("pragma", "no-cache");
    response.setHeader("cache-control", "no-cache");
    response.setHeader("expires", "0");
    try {
      LOG.info("文件上传进度监测开始--------");
      UploadFile.execClientScript(response, callback1 + "(" + key + ")");
      long temp = 0l;
      while (!p.isComplete()) {
        if (temp != p.getCurrentLength()) {
          temp = p.getCurrentLength();
          // 向客户端显示进度
          UploadFile.execClientScript(response, callback2 + "("
              + p.getCurrentLength() + "," + p.getLength() + ")");
           //LOG.info("progress的状态 :" + p.isComplete());
        } else {
           //LOG.info("progress的状态 :" + p.isComplete());
           //LOG.info("progress上传的数据量 :+ " + p.getCurrentLength());
          // 上传进度没有变化时候,不向客户端写数据,写数据过于频繁会让chrome没响应
          Thread.sleep(100);
        }
      }
    } catch (Exception e) {
       LOG.error("调用客户端脚本错误,原因 :" + e.getMessage());
      p.setComplete(true);
    }
    try {
      UploadFile.execClientScript(response, callback2 + "("
          + p.getCurrentLength() + "," + p.getLength() + ")");
    } catch (Exception e) {
      p.setComplete(true);
    }
    request.getSession().removeAttribute(key);
     LOG.info("删除progress对象的session key");
    return null;
  }
  public FileService getFileService() {
    return fileService;
  }
  public void setFileService(FileService fileService) {
    this.fileService = fileService;
  }
}
download.action:这类是从临时文件中下载文件给我们实际上传的目录
package com.upload;
import java.io.InputStream;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class DownloadAction extends ActionSupport
{
  private static final long serialVersionUID = 3350848163772547204L;
 
  public InputStream getDownloadFile()
  {
    return ServletActionContext.getServletContext().getResourceAsStream(
        "/file/aa.txt");
  }
  @Override
  public String execute() throws Exception
  {
    return SUCCESS;
  }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值