`

Struts 2 带进度条的文件上传

 
阅读更多

最近在做一个Struts2上传功能的模块,需求很明确

  1. 能控制上传文件类型
  2. 能根据上传文件类型控制上文件大小
  3. 所有要界面友好(容错,给予足够的提示)

一、开工前准备

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>

 好了,一切就绪,跑起来吧:

 首先是上传表单页面

 上传中

 

 

 

 

 

  • 大小: 6 KB
  • 大小: 15 KB
分享到:
评论

相关推荐

    struts2带进度条文件上传

    1.struts2 带进度条文件上传 源码 2.源码中有lib 下载后部署马上就能用 3.代码中有详细的注释信息 4.对关键点有详细的解释说明 5.如果谁用起来觉得有问题可在评论留言,留联系方式,我会联系你的 6.非常感谢原创作者...

    struts2_uploadify带进度条的多文件上传下载

    总之,这个项目实例为使用Struts2和Uploadify实现带进度条的多文件上传及下载功能提供了一个基础模板,对于学习和实践此类功能的开发者来说是一个有价值的参考。通过深入研究和理解这个项目的代码,可以提升对Struts...

    easyUi+jquery+common-file-upload +struts2带进度条的文件上传DEMO

    基于eclipse + easyUi1.2.6+common-fileupload + struts2实现带进度条的文件上传DEMO,具体效果跟思路可见我的博客:http://blog.csdn.net/jun55xiu/article/details/22042279

    struts2(ssh)带进度条文件上传 demo 的jar包1

    这个"struts2(ssh)带进度条文件上传 demo 的jar包1"可能是为了演示如何实现这一功能,但由于描述中提到权限问题,jar包被分成了三次上传,这里是第一部分。 在实现带进度条的文件上传时,通常需要以下步骤: 1. ...

    struts1上传文件带进度条

    总的来说,实现Struts1文件上传带进度条的功能,需要前端与后端的紧密配合,利用现代浏览器的API,以及对Struts1框架的深入理解。这不仅可以提升用户体验,也是技术能力的一种体现。在实际开发中,我们还需要考虑...

    struts2.1 带进度条上传

    Struts2.1是一个流行的Java Web框架,它提供了一种结构化的方式来开发MVC(Model-View-Controller)应用程序。...通过查看这些文件,你可以更好地理解如何在实际项目中实现Struts2.1的带进度条文件上传功能。

    ssh2(struts2+spring2.5+hibernate3.3+ajax)带进度条文件上传(封装成标签

    在这个项目中,SSH2框架与Ajax技术结合,实现了一个带进度条的文件上传功能,并且这个功能已经被封装成了自定义标签,方便在页面上直接使用。 首先,让我们深入理解SSH框架的每个组件: 1. **Struts2**:Struts2是...

    ssh2(struts2+spring2.5+hibernate3.3+ajax)带进度条文件上传(封装成标签)

    标题 "ssh2(struts2+spring2.5+hibernate3.3+ajax)带进度条文件上传(封装成标签)" 涉及到的是一个基于Java Web的项目,利用了Struts2、Spring2.5、Hibernate3.3和Ajax技术,实现了文件上传并带有进度条显示的功能...

    struts 单文件上传和多文件上传带进度条

    在Struts中,可以实现单文件和多文件的上传,并且为了提升用户体验,我们还可以添加进度条来显示文件上传的状态。本文将详细介绍如何在Struts中实现这两个功能,并带上传进度条。 首先,我们需要了解Struts中处理...

    struts2带进度条上传文件

    本教程将详细介绍如何在Struts2中实现带进度条的文件上传。 首先,我们需要在Struts2的配置文件(struts.xml)中添加一个用于处理文件上传的Action。这个Action通常会有一个接收文件的表单字段,并且需要设置`...

    struts2带进度条的异步上传

    这个【标题】"struts2带进度条的异步上传"指的是使用Struts2框架,结合JSON和jQuery技术来实现在用户界面上展示文件上传进度的功能。 【描述】中的关键信息点解构如下: 1. **Struts2.2.3**:这是Struts2的一个...

    Struts2文件上传带进度条页面无刷新

    "Struts2文件上传带进度条页面无刷新"的实现涉及多个技术点,包括Struts2的文件上传插件、AJAX异步通信以及前端进度条展示。 首先,Struts2的文件上传依赖于`struts2-upload-plugin`。这个插件扩展了Struts2的核心...

    java struts2实现文件上传进度条显示

    在Java Struts2框架中实现文件上传进度条显示,主要涉及到的技术点包括Struts2的文件上传、Ajax异步通信以及前端进度条组件的使用。下面将详细讲解这些知识点。 首先,Struts2的文件上传功能是通过Struts2提供的`...

    struts文件带进度条上传,文件下载

    在本主题中,“struts文件带进度条上传,文件下载”指的是在Struts框架下实现带有进度条的文件上传与下载功能,同时解决中文乱码问题,并确保兼容各种浏览器。 **文件上传** 在Struts中,文件上传通常使用`struts2...

    struts2+ajax文件进度条的实现

    在Struts2中实现文件上传功能,通常会涉及到处理大文件、用户体验优化等问题,如显示文件上传进度条。这个场景下,我们结合Ajax技术,可以创建一个实时反馈文件上传进度的动态界面,提升用户交互体验。 首先,我们...

    struts2上传文件进度条显示

    在Struts2中实现文件上传并展示进度条是一项常见的需求,它能提升用户体验,尤其是在处理大文件时。以下将详细解释如何在Struts2中实现这一功能。 首先,我们需要在Struts2配置中开启文件上传的支持。在`struts.xml...

    struts2(ssh)带进度条文件上传 demo 的jar包2

    在Struts2中,实现文件上传功能是非常常见的需求,而带进度条的文件上传则可以提供更好的用户体验,让用户了解文件上传的进度,增加交互性和可靠性。 文件上传在Web开发中扮演着重要角色,尤其是在处理大文件或者...

    uploadify3与struts2结合实现有进度条文件上传实例

    这是根据uploadify3 2结合struts2搭建的文件上传环境 可以直接导入eclipse运行 每步实现基本都加了注释 以下是我碰到的问题: 1 判断session是否失效 本实例没测试这个问题 但在工作项目中碰到了 但原因在这里...

Global site tag (gtag.js) - Google Analytics