最近在做一个Struts2上传功能的模块,需求很明确
- 能控制上传文件类型
- 能根据上传文件类型控制上文件大小
- 所有要界面友好(容错,给予足够的提示)
一、开工前准备
1、了解struts2 上传原理
打开struts-default.xml我们发现,struts2在做文件上传时首先定义了struts.multipart.parser这一个专门用于解析上传文件的解析器,默认由JakartaMultiPartRequest实现,并且使用了fileUpload这个拦截器在请求尚未进入Action之前将文件从客户端浏览器读入服务器缓冲区,等待处理,也就是说在Action还未对文件作出处理之前Struts已经将文件上传完成,后续工作(主要是文件转移和存档)则交给开发者去完成(强大),FileUpload这个拦截器对应的类的名字就叫作FileUploadInterceptor.java,
<interceptor-stack name="defaultStack"> <interceptor-ref name="exception"/> <interceptor-ref name="alias"/> <interceptor-ref name="servletConfig"/> <interceptor-ref name="i18n"/> <interceptor-ref name="prepare"/> <interceptor-ref name="chain"/> <interceptor-ref name="scopedModelDriven"/> <interceptor-ref name="modelDriven"/> <interceptor-ref name="fileUpload"/> <interceptor-ref name="checkbox"/> ...<!-- 此处省略其他拦截器配置 --> </interceptor-stack>
在这个类的intercept()方法中,它首先是拿到了此次请求的对象主体HttpServletRequest
ActionContext ac = invocation.getInvocationContext(); HttpServletRequest request = (HttpServletRequest) ac.get(ServletActionContext.HTTP_REQUEST);
然后再把它强制转换成MultiPartRequestWrapper,也就是在request的外面再包裹一层,通过HttpServletRequestWrapper包装文件上传请求,模块化文件上传处理,提高代码复用率。MultiPartRequestWrapper持有被装饰者(HttpServletRequest对象)引用,初始化用于存放MultipartRequest的参数的Map,同时也持有MultiPartRequest的一个引用(其中的parse()方法)方便于解析上传和文件,而MultiPartRequest是一个接口,由JakartaMultiPartRequest来具体实现。
多媒体请求到达->进行包裹,转换成commons-fileupload能够接受的MultipartRequest对象->交由ServletFileUpload处理(建立连接管道等)
二、整体思路
监听上传状态并保存到Session中,在上传过程中客户端定时向服务器询问这个状态
好,问题来了,既然Struts在Action前已经将文件上传这一步的工作完成了,我们怎么去监听文件上传的进度?
--改默认配置!
改之前先创建一个替换对像,上文说过,在Struts中上传解析工作是由JakartaMultiPartRequest中的parse()具体来实现的(解析来自ServletFileUpload的流),可它并没有给提供定时更新上传状态的功能,所以我们要给它加一个监听器,监听其状态,监听器要实现apache的ProgressListener接口,这样可以让每一次状态的改变都能被这个监听器监听到。
开始着手做:
监听上传状态
复制一份JakartaMultiPartRequest.java取名:DerrickMultiPartRequest.java放到自己的一个包中,重写其parseRequest()方法如下:
private List<FileItem> parseRequest(HttpServletRequest servletRequest, String saveDir) throws FileUploadException { UploadStatus ups = new UploadStatus(); //UploadStatus自己新建的类 UploadingListener upadlistener = new UploadingListener(ups);//UploadingListener实现ProgressListener接口 DiskFileItemFactory fac = createDiskFileItemFactory(saveDir); ServletFileUpload upload = new ServletFileUpload(fac); upload.setSizeMax(maxSize); // 设置进度监听器 upload.setProgressListener(upadlistener); System.out.println("====================parseRequest setting listener completed ================="); return upload.parseRequest(createRequestContext(servletRequest)); }
//UploadStatus.java public class UploadStatus { private long readbytes; private long contentLengh; private int item; //getters and setters are begin here ... }
将状态保存到Session里
//UploadingListener.java public class UploadingListener implements ProgressListener{ UploadStatus ups ; public UploadingListener(UploadStatus ups){ this.ups = ups; } /* (non-Javadoc) * @see org.apache.commons.fileupload.ProgressListener#update(long, long, int) */ @Override public void update(long readbytes, long contentLengh, int itemIndex) { ups.setContentLengh(contentLengh); ups.setReadbytes(readbytes); ups.setItem(itemIndex); Map<String,Object> session = ServletActionContext.getContext().getSession(); session.put("processStatus", ups); }
替换准备工作完成,下面着手编写Action
FileUploadAction 完成两个工作,文件转移和响应状态询问
//FileUploadAction.java public class FileUploadAction extends BaseAction{ private static final long serialVersionUID = 1L; private List<File> upload; private List<String> uploadFileName; private List<String> uploadContentType; private IFileService fileService; /* * 文件上传分发 */ public String upload() throws AuthorizationException, IOException{ String flag = "decline"; for (int i=0;i<upload.size();i++){ if(this.getUploadContentType().get(i).startsWith("image")){ flag = imgupload(); }else if(this.getUploadContentType().get(i).startsWith("application")){ flag = fileupload(); }else{ flag = "fileupload"; } } return flag; } /* (non-Javadoc) * 除图片外其他类型文件上传 */ public String fileupload() throws AuthorizationException ,IOException{ String root = ServletActionContext.getServletContext().getRealPath("/uploads"); InputStream is = null; OutputStream os = null; List<String> list = new ArrayList<String>(); for(int i = 0 ; i < upload.size(); i++){ String str = uploadFileName.get(i).substring(uploadFileName.get(i).lastIndexOf("\\")+1); File f = Common.CreateFile(root, str); is = new FileInputStream(upload.get(i)); os = new FileOutputStream(f); int len = 0; byte[] buffer = new byte[1024]; while(len != -1){ len = is.read(buffer, 0, buffer.length); os.write(buffer); } is.close(); os.close(); list.add(root.substring(root.lastIndexOf("\\")+1)+"\\"+str); } getSession().put("uploadList", list); return SUCCESS; } /* (non-Javadoc) * 上传图片方法 */ public String imgupload() throws AuthorizationException ,IOException{ String root = ServletActionContext.getServletContext().getRealPath("/uploads/img"); InputStream is = null; OutputStream os = null; List<String> list = new ArrayList<String>(); for(int i = 0 ; i < upload.size(); i++){ String str = uploadFileName.get(i).substring(uploadFileName.get(i).lastIndexOf("\\")+1); File f = Common.CreateFile(root, str); is = new FileInputStream(upload.get(i)); os = new FileOutputStream(f); int len = 0; byte[] buffer = new byte[1024]; while(len != -1){ len = is.read(buffer, 0, buffer.length); os.write(buffer); } is.close(); os.close(); list.add(root.substring(root.lastIndexOf("\\")+1)+"\\"+str); } getSession().put("uploadList", list); return SUCCESS; } public void uploadStatus() throws Exception{ BigDecimal read ; BigDecimal total; BigDecimal bdpercent; double percent = 0.00; HttpServletResponse response = ServletActionContext.getResponse(); response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); UploadStatus ups = (UploadStatus) getSession().get("processStatus"); if(null!=ups){ if(0 != ups.getReadbytes()){ read = new BigDecimal(ups.getReadbytes()); total = new BigDecimal(ups.getContentLengh()); bdpercent = read.divide(total, 2, BigDecimal.ROUND_UP); percent = bdpercent.doubleValue(); } }else{ System.out.println("ups is null"); } out.print((int)(percent*100)); out.flush(); out.close(); //return null; }
至此后台就改造完成了,配置一下:
//struts.xml定义要替换的MultiPartRequest的实现并让struts应用更改的实现而不使用其自带的Jakatra <bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="derrick" class="com.llb.base.impl.DerrickMultiPartRequest" scope="default" /> <constant name="struts.multipart.parser" value="derrick" />
//定义自己的拦截器栈,注意一定要追加defaultStack这个栈,不然struts的其他拦截器是会在自己的这个栈之后执行,后果不堪设想 <interceptors> <interceptor-stack name="imageUploadStack"> <interceptor-ref name="fileUpload"> <param name="allowedTypes"> image/bmp,image/png,image/gif,image/jpeg,image/pjpeg,image/x-png </param> <param name="maximumSize">5242880</param><!-- 50M --> </interceptor-ref> <interceptor-ref name="defaultStack" /> </interceptor-stack> <interceptor-stack name="attachedUploadStack"> <interceptor-ref name="fileUpload"> <param name="allowedTypes"> application/octet-stream,application/zip,application/x-zip-compressed,application/x-rar-compressed </param> <param name="maximumSize">209715200</param><!-- 200M --> </interceptor-ref> <interceptor-ref name="defaultStack" /> </interceptor-stack> </interceptors>
//配置Action <action name="upload" class="fileUploadAction" method="upload" > <result>${appContext}/upload/form.jsp</result> <result name="input">${appContext}/upload/form.jsp</result> <result name="decline" type="redirect">${appContext}/login.jsp</result> </action> <action name="fileupload" class="fileUploadAction" method="fileupload" > <interceptor-ref name="attachedUploadStack" /> <result>${appContext}/upload/form.jsp</result> <result name="input">${appContext}/upload/form.jsp</result> <result name="error">${appContext}/upload/error.jsp</result> <result name="decline">${appContext}/login.jsp</result> <!-- <exception-mapping result="error" exception="java.io.FileNotFoundException" /> --> </action> <!-- imgupload action 略 --> <!--页面定时刷新的后台接收Action--> <action name="fileuploadstatus" class="fileUploadAction" method="uploadStatus" />
客户端定时向服务器询问
程序页面的主体部分:
JS脚本
<script type="text/javascript"> $(document).ready(function(){ $("#btn_submit").click(function(){ //updateStatus(); setInterval(updateStatus, 1000); }); function updateStatus(){ $('.div_process').show('slow'); $.ajax({ type:'get', url: "fileuploadstatus.action", success: function(percent){ $(".bar").css('width',percent+'%'); $(".txt_percent").text(percent+'%'); } }); } }); $(document).ajaxComplete(function (){ $('.bar').add("<span>Ajax Complete trigger on</span>"); }) </script>
HTML
<div class="container"> <div class="content"> <div class="main"> <div class="progress progress-striped active hide div_process"> <div class="bar" style="width:2px;"> <span class="txt_percent">0%</span> </div> </div> <s:fielderror name="tooLarge"></s:fielderror> <!--<s:actionerror />--> <div class="file-box"> <s:form enctype="multipart/form-data" class="form-inline" action="upload.action" method="post" > <input id="textfield" type="text" name="fileName" style="width:180px; margin-bottom:0px;" /> <input class="btn" type="button" value="浏览..." /> <input id="fileField" class="file" type="file" style="width:260px; cursor:pointer;" onchange="document.getElementById('textfield').value=this.value" name="upload" /> <input id ="btn_submit" class="btn" type="submit" value="上传" name="submit" /> </s:form> </div> </div> </div> <!-- end .container --> </div>
好了,一切就绪,跑起来吧:
首先是上传表单页面
上传中
相关推荐
1.struts2 带进度条文件上传 源码 2.源码中有lib 下载后部署马上就能用 3.代码中有详细的注释信息 4.对关键点有详细的解释说明 5.如果谁用起来觉得有问题可在评论留言,留联系方式,我会联系你的 6.非常感谢原创作者...
总之,这个项目实例为使用Struts2和Uploadify实现带进度条的多文件上传及下载功能提供了一个基础模板,对于学习和实践此类功能的开发者来说是一个有价值的参考。通过深入研究和理解这个项目的代码,可以提升对Struts...
基于eclipse + easyUi1.2.6+common-fileupload + struts2实现带进度条的文件上传DEMO,具体效果跟思路可见我的博客:http://blog.csdn.net/jun55xiu/article/details/22042279
这个"struts2(ssh)带进度条文件上传 demo 的jar包1"可能是为了演示如何实现这一功能,但由于描述中提到权限问题,jar包被分成了三次上传,这里是第一部分。 在实现带进度条的文件上传时,通常需要以下步骤: 1. ...
总的来说,实现Struts1文件上传带进度条的功能,需要前端与后端的紧密配合,利用现代浏览器的API,以及对Struts1框架的深入理解。这不仅可以提升用户体验,也是技术能力的一种体现。在实际开发中,我们还需要考虑...
Struts2.1是一个流行的Java Web框架,它提供了一种结构化的方式来开发MVC(Model-View-Controller)应用程序。...通过查看这些文件,你可以更好地理解如何在实际项目中实现Struts2.1的带进度条文件上传功能。
在这个项目中,SSH2框架与Ajax技术结合,实现了一个带进度条的文件上传功能,并且这个功能已经被封装成了自定义标签,方便在页面上直接使用。 首先,让我们深入理解SSH框架的每个组件: 1. **Struts2**:Struts2是...
标题 "ssh2(struts2+spring2.5+hibernate3.3+ajax)带进度条文件上传(封装成标签)" 涉及到的是一个基于Java Web的项目,利用了Struts2、Spring2.5、Hibernate3.3和Ajax技术,实现了文件上传并带有进度条显示的功能...
在Struts中,可以实现单文件和多文件的上传,并且为了提升用户体验,我们还可以添加进度条来显示文件上传的状态。本文将详细介绍如何在Struts中实现这两个功能,并带上传进度条。 首先,我们需要了解Struts中处理...
本教程将详细介绍如何在Struts2中实现带进度条的文件上传。 首先,我们需要在Struts2的配置文件(struts.xml)中添加一个用于处理文件上传的Action。这个Action通常会有一个接收文件的表单字段,并且需要设置`...
这个【标题】"struts2带进度条的异步上传"指的是使用Struts2框架,结合JSON和jQuery技术来实现在用户界面上展示文件上传进度的功能。 【描述】中的关键信息点解构如下: 1. **Struts2.2.3**:这是Struts2的一个...
"Struts2文件上传带进度条页面无刷新"的实现涉及多个技术点,包括Struts2的文件上传插件、AJAX异步通信以及前端进度条展示。 首先,Struts2的文件上传依赖于`struts2-upload-plugin`。这个插件扩展了Struts2的核心...
在Java Struts2框架中实现文件上传进度条显示,主要涉及到的技术点包括Struts2的文件上传、Ajax异步通信以及前端进度条组件的使用。下面将详细讲解这些知识点。 首先,Struts2的文件上传功能是通过Struts2提供的`...
在本主题中,“struts文件带进度条上传,文件下载”指的是在Struts框架下实现带有进度条的文件上传与下载功能,同时解决中文乱码问题,并确保兼容各种浏览器。 **文件上传** 在Struts中,文件上传通常使用`struts2...
在Struts2中实现文件上传功能,通常会涉及到处理大文件、用户体验优化等问题,如显示文件上传进度条。这个场景下,我们结合Ajax技术,可以创建一个实时反馈文件上传进度的动态界面,提升用户交互体验。 首先,我们...
在Struts2中实现文件上传并展示进度条是一项常见的需求,它能提升用户体验,尤其是在处理大文件时。以下将详细解释如何在Struts2中实现这一功能。 首先,我们需要在Struts2配置中开启文件上传的支持。在`struts.xml...
在Struts2中,实现文件上传功能是非常常见的需求,而带进度条的文件上传则可以提供更好的用户体验,让用户了解文件上传的进度,增加交互性和可靠性。 文件上传在Web开发中扮演着重要角色,尤其是在处理大文件或者...
这是根据uploadify3 2结合struts2搭建的文件上传环境 可以直接导入eclipse运行 每步实现基本都加了注释 以下是我碰到的问题: 1 判断session是否失效 本实例没测试这个问题 但在工作项目中碰到了 但原因在这里...