Struts2 文件上传进度条的实现
感谢:http://blog.itpub.net/30066956/viewspace-1773697/,本文参考了很多这篇博文中的内容。
最近在写我们大三项目的一个视频文件上传的页面,实现后台对上传的进度进行监听,然后将监听的信息返回给前台页面。
前台的页面效果图:
前台进度条控件选择使用easyui 的progressbar控件。
详细的使用说明参考官网文档:http://www.jeasyui.com/documentation/index.php
所有需要引入jquery-1.11.1.min.js 以及jquery.easyui.min.js
一.前台的代码:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'uploadVideo.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"> <link rel="stylesheet" href="demo.css" /> <link rel="stylesheet" href="easyui.css" /> <link rel="stylesheet" href="icon.css" /> <script type="text/javascript" src="jquery.min.js" ></script> <script type="text/javascript" src="jquery.easyui.min.js" ></script> <link rel="stylesheet" href="videoCss/upload.css" /> <script> $(function() { var pro=0; $("#save").click(function(){ saveDate(); setinterval=setInterval(showUploadProgress, 100); }); function saveDate(){ var form = new FormData(document.getElementById("form")); $.ajax({ type:"POST", url:"uploadfile.action", data:form, async:false, cache:false, processData:false, contentType:false, success:function(result){ var msg=result.msg; $(".msg").text(msg); }, error:function(){ alert("file异步提交失败"); } }); } function showUploadProgress(){ $.ajax({ type:"GET", url:"uploadProgress.action", dataType:"json", async:false, cache:false, success:function(result){ var progressInfo=result.progressInfo; pro=progressInfo.percent; if(pro==100){ clearInterval(setinterval); } $('#progress').progressbar('setValue', progressInfo.percent); $('progress-bar-status').find(".speed").text(progressInfo.velocity); $('progress-bar-status').find(".finished").text("已上传:"+progressInfo.length+"/"+progressInfo.totalLength); $('progress-bar-status').find(".remain").text(progressInfo.timeLeft); }, error:function(result){ alert("error1"); } }); } }); </script> </head> <body> <div class="main_wrapper"> <div class="head_wrapper"> <div class="headinside"> <ul> <li><a href="">主站</a></li> <li><a href="">视频栏</a></li> <li><a href="">资源区</a></li> <li><a href="">个人中心</a></li> </ul> </div> </div><!--head_wrapper结束--> <div class="upload_box"> <p id="error"> <s:fielderror name="struts.messages.error.content.type.not.allowed"></s:fielderror> <s:actionerror/> <font color="red" class="msg">${msg }</font> </p> <div class="uploadInfo"> <span class="title"> 当前上传: <span class="filename">文件名</span> </span> <div id="progress" class="easyui-progressbar" style="width:400px;"></div> <div class="progress-bar-status"> <span class="speed" style="display: none;">当前上传的速度:80.23k/s</span> <span class="finished">已上传:10.86M/10.86M</span> <span class="remain" style="display:none">剩余时间:00秒</span> </div> <div class="videoInfo"> <form method="post" enctype="multipart/form-data" id="form"> <ul> <li> <div> <label for="video1">文件上传</label> <input type="file" id="btn_file" name="video"/> </div> </li> <li> <label for="name">标题</label> <input type="text" name="name" id="name" title="标题" placeholder="给你的视频七个标题名吧"/> </li> <li> <div> <label for="cate">分类</label> <select class="cate" id="cate" name="cate"> <option value ="1">传统文学</option> <option value ="2">民间手工艺</option> <option value="3">节假日常</option> </select> </div> </li> <li> <div> <label for="tag">标签</label> <input type="text" name="tag" id="tag" placeholder="请给您的视频添加相应的标签"/> </div> </li> <li> <div> <label for="desc" id="label_desc">描述</label> <textarea name="videoDesc" id="desc" placeholder="请添加相应的视频描述" > </textarea> </div> </li> <input id="save" type="button" value="保存"/> <!-- <button id="save">保存</button> --> </ul> </form> </div> </div> </div> </div> <div style="width: 100%;"> <div class="footer" style="width: 100%;"> <div class="inner"> <p class="a_menu"> <a target="_blank" rel="nofollow" href="#">关于我们</a> <i class="line">|</i> <a target="_blank" rel="nofollow" href="#">联系合作</a> <i class="line">|</i> <a target="_blank" rel="nofollow" href="#">帮助中心</a> <i class="line">|</i> <a target="_blank" rel="nofollow" href="#">合伙人计划</a> <i class="line">|</i> <a target="_blank" rel="nofollow" href="#">版权声明</a> </p> <p class="center"> <span>江西师范大学瑶湖校区</span> <span>java工作室</span> <br> copyright© 大白 </p> </div> </div> </div> </body> </html>
二.点击上传后,如何获得文上传的进度信息。
1.自定义一个UploadListener类实现org.apache.commons.fileupload中的ProgressListener接口,从而获得当前上传的文件的已读取的数据长度,文件总长度,正在保存第几个文件;
2.重写一个MyMultiPartRequest类,覆盖org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest,改写parseRequest方法,在其中为上传添加监听器;
3.定义一个UploadStatus bean类存放上传的状态信息,并将获得上传进度信息的UploadStatus对象存在在Session域中;
4.编写UploadListenAction,获取Session域中的UploadStatus对象,进行相应的数据处理,然后将需要的数据放入Map中以json的形式返回给jsp;
5.编写UploadFile.action,实现文件的上传存储;
三.相对应的代码。
package video.action; import org.apache.commons.fileupload.ProgressListener; public class UploadListener implements ProgressListener { private UploadStatus status; public UploadListener(UploadStatus status) { this.status = status; } public void update(long bytesRead, long contentLength, int items) { // 上传组件会调用该方法 status.setBytesRead(bytesRead); // 已读取的数据长度 status.setContentLength(contentLength); // 文件总长度 status.setItems(items); // 正在保存第几个文件 } }
对于步骤2中MyMultiPartRequest修改后的方法代码。
protected List<FileItem> parseRequest(HttpServletRequest servletRequest, String saveDir) throws FileUploadException { UploadStatus status = new UploadStatus(); // 上传状态 UploadListener listner = new UploadListener(status); // 监听器 servletRequest.getSession().setAttribute("uploadStatus", status);//将上传的进度状态存放进Session; DiskFileItemFactory fac = createDiskFileItemFactory(saveDir); ServletFileUpload upload = createServletFileUpload(fac); upload.setProgressListener(listner);// 添加监听器 return upload.parseRequest(createRequestContext(servletRequest)); }
package video.action; public class UploadStatus { private long bytesRead; // 已经上传的字节数,单位:字节 private long contentLength; // 所有文件的总长度,单位:字节 private int items; // 正在上传第几个文件 private long startTime = System.currentTimeMillis(); // 开始上传的时间,用于计算上传速度等 public long getBytesRead() { return bytesRead; } public void setBytesRead(long bytesRead) { this.bytesRead = bytesRead; } public long getContentLength() { return contentLength; } public void setContentLength(long contentLength) { this.contentLength = contentLength; } public int getItems() { return items; } public void setItems(int items) { this.items = items; } public long getStartTime() { return startTime; } public void setStartTime(long startTime) { this.startTime = startTime; } }
package video.action; import java.util.HashMap; import java.util.Map; import org.apache.struts2.interceptor.SessionAware; import com.opensymphony.xwork2.ActionSupport; public class UploadListenAction extends ActionSupport implements SessionAware{ private UploadStatus status; Map<String,Object> session; Map<String,String> progressInfo=new HashMap<>(); @Override public String execute() throws Exception { // TODO Auto-generated method stub status=(UploadStatus)session.get("uploadStatus"); if(status!=null){ long startTime = status.getStartTime(); //上传开始时间 long currentTime = System.currentTimeMillis(); //现在时间 long time = (currentTime - startTime)/ 1000 + 1; //已传输的时间 单位:s //传输速度单位:byte/s double velocity = ((double)status.getBytesRead()/1000) / (double)time; //估计总时间 double totalTime = status.getContentLength()/velocity; //估计剩余时间 double timeLeft = totalTime - time; //已经完成的百分比 int percent = (int)(100 * (double)status.getBytesRead() / (double)status.getContentLength()); //已经完成数单位:m double length = ((double) status.getBytesRead())/1024/1024; //总长度 单位:m double totalLength = ((double) status.getContentLength())/1024/1024; progressInfo.put("percent", String.valueOf(percent)); progressInfo.put("velocity", String.valueOf(velocity)); progressInfo.put("totalTime", String.valueOf(totalTime)); progressInfo.put("timeLeft", String.valueOf(timeLeft)); progressInfo.put("length", String.valueOf(length)); progressInfo.put("totalLength", String.valueOf(totalLength)); } return super.execute(); } @Override public void setSession(Map<String, Object> session) { // TODO Auto-generated method stub this.session=session; } public Map<String, String> getProgressInfo() { return progressInfo; } /*public UploadStatus getStatus() { return status; }*/ }
package video.action; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import javax.servlet.ServletContext; import org.apache.commons.io.FileUtils; import org.apache.struts2.ServletActionContext; import org.apache.struts2.interceptor.SessionAware; import video.dao.UploadDao; import video.daoimpl.UploadDaoImpl; import videomodel.VideoInfo; import cn.history.pojo.User; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; public class UploadFile extends ActionSupport{ private static final long serialVersionUID = 4182168930616232826L; private String name; //标题名 private File video; private String videoFileName; private String videoContentType; private String videoDesc; //描述 private int cate; //类型 private String tag; //标签 /*private VideoInfo videoInfo=new VideoInfo();*/ private String msg; private UploadDao uploadDao=new UploadDaoImpl(); public String upload() throws Exception{ //完成上传 ServletContext sc=ServletActionContext.getServletContext(); String directory=sc.getRealPath("/video");//得到存放文件的真是目录 //根据视频的不同类型,存放在不同的目录下 if(cate==1){ //如果是传统文学 directory=directory+"/guoxue"; }else if(cate==2){ directory=directory+"/minjian"; }else{ directory=directory+"/jiari"; } SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmssS");//格式化时间输出 String Rname=null; if(name!=null&&!name.equals("")){ Rname=name+"_"+sdf.format(new Date())+".mp4"; }else{ Rname=videoFileName; } System.out.println(Rname); //构建目标文件 File target=new File(directory,Rname); FileUtils.copyFile(video, target); System.out.println(Rname+"\n"+videoFileName+"\n"+videoDesc+"\n"+videoContentType); //将成功上传的视频基本信息保存至数据库m String filePath=target.getPath(); filePath=filePath.substring(filePath.indexOf("video")).replace("\\", "/"); System.out.println(filePath); VideoInfo videoInfo=new VideoInfo(); videoInfo.setVideoName(Rname); videoInfo.setVideoDesc(videoDesc); videoInfo.setVideoUrl(filePath); videoInfo.setCate(cate); videoInfo.setTag(tag); //ActionContext.getContext().getSession().get("name"); if(ActionContext.getContext().getSession().get("user")!=null){ User user=(User) ActionContext.getContext().getSession().get("user"); videoInfo.setAuthorId(user.getUser_id()); }else{ //设置为管理员的id,默认是管理员上传的 videoInfo.setAuthorId(1); } int tag=uploadDao.saveVideo(videoInfo); if(tag==0){ msg="上传失败(存储数据库过程出错)"; return INPUT; }else{ msg="视频上传成功"; } return SUCCESS; } /* public VideoInfo getVideoInfo() { return videoInfo; } public void setVideoInfo(VideoInfo videoInfo) { this.videoInfo = videoInfo; }*/ /*public String getName() { return name; }*/ public void setName(String name) { this.name = name; } // public File getVideo() { // return video; // } public void setVideo(File video) { System.out.println(video); this.video = video; } // public String getVideoDesc() { // return videoDesc; // } public void setVideoDesc(String videoDesc) { this.videoDesc = videoDesc; } /*public int getCate() { return cate; }*/ public void setCate(int cate) { this.cate = cate; } /*public String getTag() { return tag; }*/ public void setTag(String tag) { this.tag = tag; } // public String getVideoFileName() { // return videoFileName; // } public void setVideoFileName(String videoFileName) { this.videoFileName = videoFileName; } /*public String getVideoContentType() { return videoContentType; }*/ public void setVideoContentType(String videoContentType) { this.videoContentType = videoContentType; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }