struts2实现文件上传进度条(前端JS+Java)(收藏)

来源:互联网 发布:php清空文件内容 编辑:程序博客网 时间:2024/06/10 19:33

步骤如下:

1.重写、自定义JakartaMultiPartRequest类

package com.hikvision.fileUploadProcess.interceptor;import java.io.IOException;import javax.servlet.http.HttpServletRequest;import org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest;public class MyJakartaMultiPartRequest extends JakartaMultiPartRequest  {    @Override      public void parse(HttpServletRequest servletRequest, String saveDir)              throws IOException {              //什么也不做      }   }

原因:

    struts2默认的拦截器中有一个FileUploadInterceptor,它会拦截所有的MultipartRequest,并且将得到的File及相关信息传递给action,因此在action被调用之前,文件上传已经被处理完了,不能引入监听文件写入时文件进度;

    struts2处理文件上传使用的是commons-fileupload,因此我们可以使用ProgressListener。注意我们需要在解析请求的时候加入我们的监听器,我们首先想到的是替换掉FileUploadInterceptor,不幸的是 FileUploadInterceptor并不执行解析的任务,实际在FileUploadInterceptor被调用之前,MultipartRequest已经被解析了,文件上传的工作已经完成。而实际上对于所有的文件上传请求,struts2会为其生成一个MultiPartRequestWrapper进行包装,而它维护着一个 MultiPartRequest接口的实例。MultiPartRequest的实现类只有一个 JakartaMultiPartRequest,JakartaMultiPartRequest有一个方法parseRequest,此方法负责解析 request并生成FileItem,即对文件进行读写操作,因此我们可以重写此方法,添加ProgressListener。不幸的是,JakartaMultiPartRequest的很多方法都是private的,我们不能继承它然后重写parseRequest方法,JakartaMultiPartRequest实现了MultiPartRequest接口,我们可以编写一个类,实现 MultiPartRequest接口,替代JakartaMultiPartRequest类的代码全都拷贝过来,并修改parseRequest方法,完成文件的写入与进度的监听。

2.配置struts2.xml

<!-- 1配置自定义文件类myRequestParser,继承MultiPartRequest重写 --><bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest"name="myRequestParser" class="com.hikvision.fileUploadProcess.interceptor.MyJakartaMultiPartRequest"scope="default" optional="true" /><!-- 注意struts2.3.15.1以前版本这里为struts.multipart.handler, struts2.3.15.1(包含2.3.15.1)这里为struts.multipart.parser--><constant name="struts.multipart.parser" value="myRequestParser" /> <!-- 配置项目所上传文件的最大的Size为1000M --><constant name="struts.multipart.maxSize" value="1048576000"/> 


3.定义文件上传进度信息的类

package com.hikvision.fileUploadProcess.entity;/** * 上传文件进度信息 *  * @author wanglei * @version 0.1 */public class FileUploadProgress {// 文件总长度(设置至少为1字节防止前台出现/0的情况)private long length = 1;// 已上传的文件长度private long currentLength = 0;// 上传是否完成private boolean isComplete = false;public long getLength() {return length;}public void setLength(long length) {this.length = length;}public long getCurrentLength() {return currentLength;}public void setCurrentLength(long currentLength) {this.currentLength = currentLength;}public boolean isComplete() {return isComplete;}public void setComplete(boolean isComplete) {this.isComplete = isComplete;}public FileUploadProgress() {super();}}

4.实现ProgressListener接口

package com.hikvision.fileUploadProcess.impl;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import org.apache.commons.fileupload.ProgressListener;import com.hikvision.fileUploadProcess.entity.FileUploadProgress;/** * 文件上传进度消息 * @author hongchenjin * */public class FileUploadListener implements ProgressListener {private HttpSession session;public FileUploadListener(HttpServletRequest request) {session = request.getSession();FileUploadProgress fileUploadProgress = new FileUploadProgress();fileUploadProgress.setComplete(false); session.setAttribute("fileUploadProgress", fileUploadProgress);}//更新进度情况@Overridepublic void update(long readedBytes, long totalBytes, int currentItem) { //实现文件上传的核心方法Object attribute = session.getAttribute("fileUploadProgress");FileUploadProgress fileUploadProgress  = null;if(null == attribute){ fileUploadProgress = new FileUploadProgress();fileUploadProgress.setComplete(false); session.setAttribute("fileUploadProgress", fileUploadProgress);}else{ fileUploadProgress = (FileUploadProgress)attribute;}fileUploadProgress.setCurrentLength(readedBytes);fileUploadProgress.setLength(totalBytes); if(readedBytes==totalBytes){fileUploadProgress.setComplete(true);}else{ fileUploadProgress.setComplete(false);} session.setAttribute("progress", fileUploadProgress);}}
5.文件上传进度的action

package com.hikvision.modules.guide.action;import java.io.File;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;import javax.servlet.http.HttpServletRequest;import org.apache.struts2.ServletActionContext;import com.hikvision.fileUploadProcess.entity.FileUploadProgress;import com.hikvision.frame.entity.OperateResult;import com.hikvision.modules.guide.entity.NameToLocalFile;import com.hikvision.modules.guide.service.GuideService;import com.hikvision.modules.guide.util.GetSharePathXml;import com.hikvision.util.AjaxUtil;import com.opensymphony.xwork2.ActionSupport;public class GuideUploadAction extends ActionSupport {private GuideService guideService;public GuideService getGuideService() {return guideService;}public void setGuideService(GuideService guideService) {this.guideService = guideService;}//文件格式不支持public void typeNotSupport(){OperateResult result = new OperateResult(false,"");result.setResult(false);result.setMsg("上传文件最大不能超过100M;支持的格式为exe,png,jpg,gif,bmp,doc,docx,xls,rar,txt,zip,js,css,msi,pptx");AjaxUtil.ajaxWrite(result);}/**     * 上传文件     *      * @return     */    public void uploadfile() {    OperateResult result = new OperateResult(false,"");        try {        HttpServletRequest request = ServletActionContext.getRequest();        //获取文件备注        String comments = request.getParameter("comments");        //文件上传            UploadFile.upload(request, ServletActionContext.getResponse());            //将文件名和文件的对应关系存进数据库里 NameToLocalFile nameToLocalFile = new NameToLocalFile();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");String time = sdf.format(new Date());nameToLocalFile.setCreatetime(time);//保存在服务器上的路径nameToLocalFile.setLocalpath("/" +  request.getParameter("variety") + "/" + request.getParameter("name"));nameToLocalFile.setName(request.getParameter("name")); nameToLocalFile.setVariety(request.getParameter("variety"));nameToLocalFile.setComments(comments);guideService.saveOrUpdate(nameToLocalFile);            result.setResult(true);            result.setMsg("上传成功");        } catch (IOException e) {             LOG.error("上传文件发生异常,错误原因 : " + e.getMessage());             result.setMsg("上传文件最大不能超过100M;");             result.setResult(false);        }         AjaxUtil.ajaxWrite(result);     }        /**     * 修改文件     */    public void updateNameToLocalFile(){    OperateResult result = new OperateResult(false,"");    HttpServletRequest request = ServletActionContext.getRequest();    //种类    String variety = request.getParameter("variety");    //名称String name = request.getParameter("name");//文件备注    String comments = request.getParameter("comments");//是否上传了文件Boolean flag = Boolean.parseBoolean(request.getParameter("flag"));//idint id = Integer.parseInt(request.getParameterValues("ids")[0]);//根据id获取数据库的nameToLocalFileByIdNameToLocalFile nameToLocalFileById = guideService.getNameToLocalFileById(id);//分为两种情况,第一种为用户重新上传了文件,第二种是用户只修改了名字和种类if(flag){/** * 用户重新上传文件的情况 *///删除原来文件String localpath = nameToLocalFileById.getLocalpath();String realPath = GetSharePathXml.getShareFolderPath() + localpath;File file = new File(realPath);//用户上传了文件try { if(file.exists()){//删除原来文件(判断是否存在该文件,存在就删除)file.delete();}//文件上传            UploadFile.upload(request, ServletActionContext.getResponse());result.setResult(true);result.setMsg("修改成功");} catch (Exception e) {result.setResult(false);result.setMsg("修改失败");}}//将文件名和文件的对应关系存进数据库里SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");String time = sdf.format(new Date());nameToLocalFileById.setCreatetime(time);if(flag){//保存在服务器上的路径nameToLocalFileById.setLocalpath("/" +  variety + "/" + name);nameToLocalFileById.setName(name);}   nameToLocalFileById.setVariety(variety);nameToLocalFileById.setComments(comments);guideService.saveOrUpdate(nameToLocalFileById);result.setResult(true);result.setMsg("修改成功"); AjaxUtil.ajaxWrite(result);    }    /**     * 显示上传文件进度进度     *      * @return page view     */    public void progress() {        // 新建当前上传文件的进度信息对象        FileUploadProgress p = null;        Object attribute = ServletActionContext.getRequest().getSession().getAttribute("fileUploadProgress");        if(null == attribute){        p = new FileUploadProgress();         // 缓存progress对象            ServletActionContext.getRequest().getSession().setAttribute("fileUploadProgress", p);        }else{        p = (FileUploadProgress)attribute;        }                ServletActionContext.getResponse().setContentType("text/html;charset=UTF-8");        ServletActionContext.getResponse().setHeader("pragma", "no-cache");        ServletActionContext.getResponse().setHeader("cache-control", "no-cache");        ServletActionContext.getResponse().setHeader("expires", "0");          //以下方法为输出json(封装,可根据实际情况修改输出的方式)        AjaxUtil.ajaxWriteObject(p);    }        /**     * 清除session     */    public void clearProgressSession(){    ServletActionContext.getRequest().getSession().setAttribute("fileUploadProgress", null);    }}

6.UploadFile类(文件上传)

package com.hikvision.modules.guide.action;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;import com.hikvision.fileUploadProcess.impl.FileUploadListener;import com.hikvision.modules.guide.util.GetSharePathXml;/** * upload file *  * @author scott.Cgi */public class UploadFile {    private static final Logger LOG = Logger.getLogger(UploadFile.class);    /**     * 上传文件     *      * @param request     *            http request     * @param response     *            htp response     * @throws IOException     *             IOException     */    @SuppressWarnings("unchecked")    public static void upload(HttpServletRequest request,            HttpServletResponse response) throws IOException {        if (request.getContentType() == null) {            throw new IOException(                    "the request doesn't contain a multipart/form-data stream");        }        // 上传临时路径        String path = GetSharePathXml.getShareFolderPath();        // 设置上传工厂        DiskFileItemFactory factory = new DiskFileItemFactory();        factory.setRepository(new File(path));        // 阀值,超过这个值才会写到临时目录        factory.setSizeThreshold(1024 * 1024 * 10);        ServletFileUpload upload = new ServletFileUpload(factory);        // 最大上传限制        upload.setSizeMax(1024 * 1024 * 1000);        // 设置监听器监听上传进度        upload.setProgressListener(new FileUploadListener(request));         try {              List<FileItem> items = upload.parseRequest(request);                         //获取文件类型            String variety = request.getParameter("variety");            for (FileItem item : items) {                                // 非表单域                if (!item.isFormField()) {                    FileOutputStream fos = new FileOutputStream(path + "/"  + variety + "/" + item.getName());                    // 文件全在内存中                    if (item.isInMemory()) {                        fos.write(item.get());                    } 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("删除临时文件!");                                        LOG.info("更新progress对象状态为完成状态!");                }            }        } catch (Exception e) {            LOG.error("上传文件出现异常, 错误原因 : " + e.getMessage());            request.getSession().removeAttribute("percent");        }    }        }

前台部分:点击上传,然后循环调用

//进度条显示var everylisten = function() {//显示进度条 $("#prosbar").parent("div").css({"display":"block"});$.ajax({url : 'http://127.0.0.1/guideUpload!progress.action',method : 'GET', timeout : 120000,   contentType : "application/json; charset=utf-8",dataType : "json",success : function(result) {if(null != result) {if(result.complete) { //将进度条长度设为0并隐藏$("#prosbar").css({"width":"0%"});   clearTimeout(everylisten);  //清除session clearProgressSession();  }else{ var width = result.currentLength * 100 / result.length + "%";$("#prosbar").css({"width": width});   setTimeout(everylisten, 500);      } }else{alert(data.msg);  } }});};   
清除进度条session

//清除sessionfunction clearProgressSession(){$.ajax({url : hik.guide.getContextPath() + '/guideUpload!clearProgressSession.action', method : 'GET', timeout : 120000,   contentType : "application/json; charset=utf-8",dataType : "json",success : function(result) { }});}  
点击文件上传时的js代码(PS:文件上传时相关参数写在路径里,不然后台接收不到(如果不写在路径里,测试时在浏览器调试发现参数确实传了,但在request里这个参数的值为空),因为请求地址是要经过tomcat的,为防止中文乱码的情况,在tomcat路径conf文件夹下找到server.xml文件,找到以下项,添加红色部分的代码 <ConnectorURIEncoding="UTF-8" connectionTimeout="20000" port="80" protocol="HTTP/1.1" redirectPort="8443"/> ,保存后重启tomcat)


$("#GuideForm").submit(function(){everylisten();return false;$.ajaxFileUpload (  {url:'http://127.0.0.1/guideUpload!uploadfile.action?'     + $("#GuideForm").serialize(),secureuri:false,    fileElementId:'upload',  dataType: 'json',    data:{},  success: function (data, status){$(dialogEl).dialog('close');//上传成功后,提示用户上传成功if(data.success){alert("success");  }else{alert("false");} },error: function (data, status, e) {alert("出错了");}})  });

页面代码(红色部分为必须写的地方):
<form id="GuideForm" name="guideForm" action=""onsubmit="return false;"class="form-horizontal five-columns character5 padding-top8px"</span><span style="color:#cc0000;">enctype="multipart/form-data"</span><span style="color:#333333;"> method="post">  <div> <input type="hidden" name="ids" ><div class="control-group five-columns">        <label class="control-label">文件名称:</label>        <div class="controls">          <input class="span4" type="text" name="name" maxlength="20" readonly="readonly"/>          </div>      </div>       <div class="control-group five-columns"><label class="control-label">文件类型:</label>   <div class="controls"> <select name="variety"><option value="tools">开发工具</option><option value="ecliplse_plugin">Eclipse常用插件</option><option value="svn">代码版本控制SVN</option><option value="database">数据库</option> <option value="other">其他</option></select></div>  </div> <div class="control-group five-columns" style="display:none;">   <label class="control-label">文件路径:</label>        <div class="controls">            <a name="path" style="color:blue"></a>           </div>           <div class="controls">           <input type="button" class="btn btn-primary uploadReset" value="重新上传" name="uploadReset">            </div></div> <div class="control-group five-columns"><div class="controls"><label class="control-label">上传文件 :</label><input class="span4" type="file"name="upload" maxlength="20" id="upload" />  </div> </div> <div class="control-group five-columns"><div class="controls"><label class="control-label">文件备注:</label><textarea rows="" cols="" name="comments" maxLength="50"></textarea></div> </div> <div class="progress progress-striped active" >      <div class="bar" style="width: 0%;" id="prosbar"></div> </div></div> <!-- 上传进度条 --> </form>
0 0