Java DWR Extjs Servlet 文件上传 进度条

本文介绍如何结合Java Servlet、DWR和Extjs实现文件上传功能,并添加进度条显示。通过FileProgressListener、UpLoadServlet等组件,展示了从上传页面到文件上传完成的流程,同时指出了未处理的大文件、文件大小判断和断点续传等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇博文里面详细介绍了Java Servlet 文件上传,这篇博文将为文件上传添加进度条,其中会利用DWR和Extjs。

1、项目的结构图

(1)要导入相应的JAR包和EXTJS文件。

(2)FileProgressListener

package com.fileupload;

import java.util.Collection;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.ProgressListener;
import org.directwebremoting.ScriptBuffer;
import org.directwebremoting.ScriptSession;
import org.directwebremoting.ServerContext;
import org.directwebremoting.ServerContextFactory;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory.WebContextBuilder;
import org.directwebremoting.impl.DefaultWebContextBuilder;

public class FileProgressListener implements ProgressListener {
	private long last_percentage = 0;	
	private long percentage = 0;	
	private HttpServletRequest request;	
	private HttpServletResponse response;
	
	public FileProgressListener(HttpServletRequest request, HttpServletResponse response){
		this.request = request;
		this.response = response;
	}
	
	public void update(long pBytesRead, long pContentLength, int pItems) {
		percentage = (pBytesRead * 100) / pContentLength;
		if(percentage > 0 && percentage % 5 == 0 && percentage > last_percentage){
			last_percentage = percentage;
			System.out.println("已完成"+percentage+"%,文件大小是:"+pContentLength);
			updateProgress(percentage);
		}
	}

	/**
	 * 向页面index.jsp推送文件上传完成的百分比,推送到方法refreshProgress中。
	 * @param percentage
	 */
	public void updateProgress(long percentage){
		ScriptBuffer scriptBuffer = new ScriptBuffer();
		scriptBuffer.appendScript("try{");
		scriptBuffer.appendScript("if(refreshProgress){");
		scriptBuffer.appendScript("refreshProgress");
		scriptBuffer.appendScript("(");
		scriptBuffer.appendData(percentage);
		scriptBuffer.appendScript(")}");
		scriptBuffer.appendScript("} catch(e){alert(e)}");
		
		ServerContext sc = ServerContextFactory.get();
        WebContextBuilder webBuilder = new DefaultWebContextBuilder();
        webBuilder.engageThread(sc.getContainer(), request, response);
		WebContext webContext = webBuilder.get();
		if(webContext == null){
			return;
		}
		
		Collection<ScriptSession> sessions = webContext.getScriptSessionsByPage("/FileUpload/index.jsp");
		if (sessions == null || sessions.isEmpty()) {
			return;
		}

		for (ScriptSession scriptSession : sessions) {
			if (scriptSession != null) {
				scriptSession.addScript(scriptBuffer);
			}
		}
	}
	
	public void setPercentage(long percentage) {
		this.percentage = percentage;
	}

	public long getPercentage() {
		return percentage;
	}

}

(3)UpLoadServlet

package com.fileupload;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class UpLoadServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	//上传文件最大为100M
	private static final int FILE_MAX_SIZE = 100 * 1024 * 1024;
	//设定阀值1M,如果超过这个值,则文件就直接写到临时文件,不会一直占用内存
	//利用这个特性可在上传大文件的时候不会占用大量内存,可以提高并发使用量。
	private static final int THRESHOLD_SIZE = 1024 * 1024;
	
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		DiskFileItemFactory df = new DiskFileItemFactory();
		df.setSizeThreshold(THRESHOLD_SIZE);
		String result = "";
		try {
			File f = new File("E:\\temp");
			if (!f.exists()) {
				f.mkdirs();
			}
			
			df.setRepository(f);
			ServletFileUpload sf = new ServletFileUpload(df);
			sf.setFileSizeMax(FILE_MAX_SIZE);
			
			FileProgressListener fileProgressListener = new FileProgressListener(request, response);
			sf.setProgressListener(fileProgressListener);
			List list = null;
			try {
				list = sf.parseRequest(request);
			} catch (Exception e) {
				e.printStackTrace();
				result = "上传失败:"+e.getMessage();
			}
			
			if(list != null && !list.isEmpty()){
				for (int i = 0; i < list.size(); i++) {
					FileItem fileItem = (FileItem) list.get(i);
					String fileName = fileItem.getName();
					if(fileName == null || "".equals(fileName.trim())){
						continue;
					}
					
					File ff = new File("E:\\files");
					if (!ff.exists()) {
						ff.mkdirs();
					}
					
					File f2 = new File(ff, fileName);
					fileItem.write(f2);
					result = "上传成功";
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			result = "上传失败:"+e.getMessage();
		}

		response.setContentType("text/html");
		response.setCharacterEncoding("UTF-8");
		PrintWriter out = response.getWriter();
		out.println("<script>");
		out.println("alert('"+result+"');");
		out.println("</script>");
		out.flush();
		out.close();
	}

}

(4)log4j.properties

这个是日志配置文件,用来打印系统日志的。

#stdout
log4j.rootLogger=INFO ,stdout

#Console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.Threshold =INFO 
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p %c{1}:%L - %m%n

(5)dwr.xml

这是DWR的配置文件,用于配置BEAN其他业务类,暂时没用到,所以就没配置什么东西,本文使用DWR主要是使用它的推送功能,来动态更新进度条。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN" "http://getahead.org/dwr/dwr30.dtd">
<dwr>
	<allow>
	</allow>
</dwr>

(6)web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>

	<servlet>
		<servlet-name>Upload</servlet-name>
		<servlet-class>com.fileupload.UpLoadServlet</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>Upload</servlet-name>
		<url-pattern>/dwr/fileupload</url-pattern>
	</servlet-mapping>

	<servlet>
		<servlet-name>dwr</servlet-name>
		<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
		<init-param>
			<param-name>debug</param-name>
			<param-value>true</param-value>
		</init-param>
		<init-param>
			<param-name>crossDomainSessionSecurity</param-name>
			<param-value>false</param-value>
		</init-param>
		<init-param>
			<param-name>allowScriptTagRemoting</param-name>
			<param-value>true</param-value>
		</init-param>
		<init-param>
			<param-name>activeReverseAjaxEnabled</param-name>
			<param-value>true</param-value>
		</init-param>
		<init-param>
			<param-name>pollAndCometEnabled</param-name>
			<param-value>true</param-value>
		</init-param>
		<init-param>
			<param-name>initApplicationScopeCreatorsAtStartup</param-name>
			<param-value>true</param-value>
		</init-param>
		<!-- polling方式:在comet方式的基础之上,再配置以下参数 -->
		<init-param>
			<param-name>org.directwebremoting.extend.ServerLoadMonitor</param-name>
			<param-value>org.directwebremoting.impl.PollingServerLoadMonitor</param-value>
		</init-param>
		<!-- 毫秒数。页面默认的请求间隔时间是5秒 -->
		<init-param>
			<param-name>disconnectedTime</param-name>
			<param-value>100</param-value>
		</init-param>
		<init-param>
			<param-name>maxWaitAfterWrite</param-name>
			<param-value>500</param-value>
		</init-param>
		<load-on-startup>4</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>dwr</servlet-name>
		<url-pattern>/dwr/*</url-pattern>
	</servlet-mapping>
</web-app>

(7)index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
	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>文件上传-进度条</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" type="text/css" href="styles.css">
	-->
	
	<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/ext-3.2.1.1/resources/css/ext-all.css" />
	<script type="text/javascript" src="${pageContext.request.contextPath}/ext-3.2.1.1/adapter/ext/ext-base-debug.js"></script>
	<script type="text/javascript" src="${pageContext.request.contextPath}/ext-3.2.1.1/ext-all.js"></script>
	<script type="text/javascript" src="${pageContext.request.contextPath}/ext-3.2.1.1/ext-lang-zh_CN.js"></script>
	<script type="text/javascript" src="${pageContext.request.contextPath}/dwr/engine.js"></script>
	<script type="text/javascript" src="${pageContext.request.contextPath}/dwr/util.js"></script>
	
	<script type="text/javascript">
		dwr.engine.setActiveReverseAjax(true);//开启DWR的推送功能
	</script>	
	
	<script type="text/javascript" language="javascript">
		
	<script type="text/javascript">
	Ext.onReady(function(){
		var formPanel = new Ext.FormPanel({
				renderTo: Ext.getBody(),
				title: '上传文件',
				fileUpload:true,
				items:[ {
                    	xtype: 'textfield',
                   	 	id: 'file',
                    	fieldLabel: '选择文件',
                    	inputType: 'file',
                   		buttonText: '浏览',
                    	width: 258
                },
                {
					text: "上传",
					xtype: "button",
					handler:function(){
						var file = Ext.getCmp("file");
						if(file.getValue() == ''){
							 Ext.MessageBox.alert('提示', '请选择文件!');
							return;
						}
						
						var win = new Ext.Window({
							title: "进度条",
							autoScroll: true,
							width: Ext.lib.Dom.getViewWidth() > 650 ? 650 : Ext.lib.Dom.getViewWidth() - 100,
							autoHeight: true,
							closable: true,
							layout: 'fit',
							items: [
								new Ext.ProgressBar({
									id: 'progresBar',
									anchor: '100%',
									listeners: {
										afterrender: function(b) {
											b.progressBar.setHeight(18);
										}
									}
								})
							]
						});
						
						win.show();
                		formPanel.form.submit({
                        	url: 'dwr/fileupload',
                        	method: "POST",
                        	success: function(form, action) {
                        		alert("success");
                				win.close();
                        	},
                        	failure:function(form,action){
                        		alert("failure");
                        		win.close();
                       		}
                    });
					}
                }]
			});
	});
		function refreshProgress(percentage) {
			Ext.getCmp('progresBar').updateProgress(parseFloat(percentage)/100, 
					'已完成' + parseInt(percentage) + '%', true);
		}
	</script>
	</head>
	<body>
	</body>
</html>

2、系统运行结果

(1)上传页面

(2)文件上传中

(3)文件上传完成

 

3、总结

本文使用DWR+EXTJS+Servlet+commons_fileupload基本实现了上传文件的功能,并且附带进度条,但也有一些缺陷。

3.1、没有判断文件的大小

如果文件超过限制则会上传失败(需要上传超过大小限制后才抛出异常),没有在页面上或Servlet中做判断。

要获取文件的大小有两种:

(1)、修改浏览器的安全配置,通过ActiveXObject获取。

      但这会影响影响浏览器的安全性。

<script type="text/javascript" language="javascript">
	//获取文件大小
    function getFileSize(fileName)
    { 
       if(document.all)
       { 
        var fso = new ActiveXObject('Scripting.FileSystemObject'); 
        var file = fso.GetFile(fileName);         
        var size = file.Size;
        var size_str = "";
        if(size > 1024*1024*1024){
            size_str=size/(1024*1024*1024)+"G";
        }else if(size > 1024*1024){
            size_str=size/(1024*1024)+"M";
        }else if(size > 1024){
            size_str=size/(1024)+"K";
        }else{
        	size_str=size + "B";
        }
        return size_str;
        }
    } 
    </script>

(2)、利用FLASH获取。

      这是网上的说法,以后再慢慢摸索。

3.2 不支持上传大文件

如果文件的大小超过500M,则很可能上传失败。

3.3 不支持断点续传

如果上传的过程中出现问题导致中断,再次上传时并不支持断点续传。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值