使用struts2和AJAX实现文件上传并显示进度条
使用struts2和AJAX实现文件上传并显示进度条
(2011-05-25 21:48:48)
转载▼
分类:java点滴
这个是刚进入公司,技术总监叫我做的东西,开始的确没有什么头绪,以前做的项目里只做过上传,下载。而且也只是方法调用。这个方法涉及到对common.fileupload.jar里一个方法的重写,并且要实现进度条。经过两天的奋斗,再浏览了各位前辈们的佳作,终于实现了以下的代码
需要导入的jar包如下:
jsp页面:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
iframe{
border:none;
width:0;
height:0;
}
#p_out{
width:200px;
height:12px;
margin:10px 0 0 0;
padding:1px;
font-size:10px;
border:solid #6b8e23 1px; }
#p_first{
width:0%;
height:100%;
background-color:red;
margin:0;
padding:0;
}
#p_second{
width:0%;
height:100%;
background-color:blue;
margin:0;
padding:0;
}
#dis{
margin:0;
padding:0;
text-align:center;
font-size:12px;
height:12px;
width:200px;
}
//上传文件
function uploadFile(key){
document.forms[0].action =
'uploadfile.action?callback=parent.upload&key='+key;
document.forms[0].submit();
document.getElementByIdx_x_x('dis').innerHTML = "开始传送数据..."; }
//获取文件上传进度
function progress(){
document.getElementByIdx_x_x('progress_iframe').src =
'progress.action?callback1=parent.uploadFile&callback2=parent.upload';
document.getElementByIdx_x_x('dis').innerHTML = '初始化数据...';
document.getElementByIdx_x_x('p_first').style.width = "0%";
}
//更新进度
function upload(len, total){
document.getElementByIdx_x_x('p_first').style.width =
(Math.round(len/total*100))+'%';
document.getElementByIdx_x_x('dis').innerHTML = len + '/' + total + ' Byte'; if(len === total) {
document.getElementByIdx_x_x('dis').innerHTML = "文件上传完成!";
}
}
STRUTS配置文件:
"-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
"https://www.360docs.net/doc/f614937578.html,/dtds/struts-2.1.dtd">
name="myRequestParser" class="com.upload.MyRequestParseWrapper" scope="default" /> upload.java类:该类是采用servlet方法来存放文件 package com.upload; 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 https://www.360docs.net/doc/f614937578.html,mons.fileupload.FileItem; import https://www.360docs.net/doc/f614937578.html,mons.fileupload.ProgressListener; import https://www.360docs.net/doc/f614937578.html,mons.fileupload.disk.DiskFileItemFactory; import https://www.360docs.net/doc/f614937578.html,mons.fileupload.servlet.ServletFileUpload; import org.apache.log4j.Logger; public class UploadFile { private static final Logger LOG = Logger.getLogger(UploadFile.class);// LOG日志 @SuppressWarnings("unchecked") public static void upload(HttpServletRequest request, HttpServletResponse response) throws IOException { https://www.360docs.net/doc/f614937578.html,("客户端提交类型: " + request.getContentType()); //判断文件类型,为空则报异常 if (request.getContentType() == null) { throw new IOException( "the request doesn't contain a multipart/form-data stream"); } String key = request.getParameter("key"); Progress p = (Progress) request.getSession().getAttribute(key); // 设置上传文件总大小 p.setLength(request.getContentLength()); https://www.360docs.net/doc/f614937578.html,("上传文件大小为 : " + p.getLength()); // 上传临时路径 String path = request.getSession().getServletContext().getRealPath("/file"); https://www.360docs.net/doc/f614937578.html,("上传临时路径 : " + path); // 设置上传工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setRepository(new File(path)); // 阀值,超过这个值才会写到临时目录 factory.setSizeThreshold(1024 * 1024 * 10); ServletFileUpload upload = new ServletFileUpload(factory); // 最大上传限制 200M upload.setSizeMax(1024 * 1024 * 200); // 设置监听器监听上传进度 upload.setProgressListener(p); try { https://www.360docs.net/doc/f614937578.html,("解析上传文件...."); List https://www.360docs.net/doc/f614937578.html,("上传数据..."); for (FileItem item : items) { // File destFile = new File(path,item.getFieldName()); // 非表单域 if (!item.isFormField()) { https://www.360docs.net/doc/f614937578.html,("上传路径 : " + path ); FileOutputStream fos = new FileOutputStream(path + item.getName().substring( item.getName().lastIndexOf("\\"), item.getName().length())); // 文件全在内存中 if (item.isInMemory()) { fos.write(item.get()); p.setComplete(true); } 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(); https://www.360docs.net/doc/f614937578.html,("完成上传文件!"); item.delete(); https://www.360docs.net/doc/f614937578.html,("删除临时文件!"); p.setComplete(true); https://www.360docs.net/doc/f614937578.html,("更新progress对象状态为完成状态!"); } } } catch (Exception e) { LOG.error("上传文件出现异常, 错误原因 : " + e.getMessage()); // 发生错误,进度信息对象设置为完成状态 p.setComplete(true); request.getSession().removeAttribute(key); } } public static void execClientScript(HttpServletResponse resposne, String script) throws IOException { PrintWriter out = resposne.getWriter(); out.println(""); // fix ie problem out.println("------------------------------------------------------"); out.println("------------------------------------------------------"); out.println("------------------------------------------------------"); out.println("------------------------------------------------------"); out.println("------------------------------------------------------"); out.flush(); } public static class Progress implements ProgressListener { // 文件总长度 private long length = 0; // 已上传的文件长度 private long currentLength = 0; // 上传是否完成 private boolean isComplete = false; @Override public void update(long bytesRead, long contentLength, int items) { this.currentLength = bytesRead; } public long getLength() { return length; } public long getCurrentLength() { return currentLength; } public boolean isComplete() { return isComplete; } public void setLength(long length) { this.length = length; } public void setCurrentLength(long currentLength) { this.currentLength = currentLength; } public void setComplete(boolean isComplete) { this.isComplete = isComplete; } } } MyRequestParseWrapper.java重写源文件方法,不要其一次上传package com.upload; import java.io.IOException; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest; public class MyRequestParseWrapper extends JakartaMultiPartRequest { @Override public void parse(HttpServletRequest servletRequest, String saveDir) throws IOException { // 什么也不做--- } } FileService.java类:这个类是一些方法提取出来写了,在action里直接调用 package com.upload; import java.io.InputStream; import java.io.OutputStream; import java.io.FileOutputStream; import javax.activation.DataHandler; public class FileService { // 使用byte[]类型参数上传二进制文件 public boolean uploadWithByte(byte[] file, String filename) { FileOutputStream fos = null; try { fos = new FileOutputStream(filename); fos.write(file); fos.close(); } catch (Exception e) { return false; } finally { if (fos != null) { try { fos.close(); } catch (Exception e) { } } } return true; } private void writeInputStreamToFile(InputStream is, OutputStream os) throws Exception { int n = 0; byte[] buffer = new byte[8192]; while ((n = is.read(buffer)) > 0) { os.write(buffer, 0, n); } } // 使用DataHandler类型参数上传文件 public boolean uploadWithDataHandler(DataHandler file, String filename) { FileOutputStream fos = null; try { fos = new FileOutputStream(filename); // 可通过DataHandler类的getInputStream方法读取上传数据 writeInputStreamToFile(file.getInputStream(), fos); fos.close(); } catch (Exception e) { return false; } finally { if (fos != null) { try { fos.close(); } catch (Exception e) { } } } return true; } } FileAction.java 这个实现进度条的action,我认为是最重要的一个类package com.upload; import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; import com.upload.UploadFile; import com.upload.UploadFile.Progress; public class FileAction extends ActionSupport { private static final long serialVersionUID = 6649027352616232244L; private FileService fileService; public String preupload() { return SUCCESS; } public String uploadfile() { try { https://www.360docs.net/doc/f614937578.html,("文件上传操作开始"); HttpServletResponse response = ServletActionContext.getResponse(); HttpServletRequest request = ServletActionContext.getRequest(); UploadFile.upload(request, response); } catch (IOException e) { // LOG.error("上传文件发生异常,错误原因 : " + e.getMessage()); } return null; } public String progress() { System.out.println("begin"); https://www.360docs.net/doc/f614937578.html,("文件上传进度监测开始"); HttpServletResponse response = ServletActionContext.getResponse(); HttpServletRequest request = ServletActionContext.getRequest(); String callback1 = request.getParameter("callback1"); String callback2 = request.getParameter("callback2"); // 缓存progress对象的key值 String key = Integer.toString(request.hashCode()); // 新建当前上传文件的进度信息对象 Progress p = new Progress(); // 缓存progress对象 request.getSession().setAttribute(key, p); response.setContentType("text/html;charset=UTF-8"); response.setHeader("pragma", "no-cache"); response.setHeader("cache-control", "no-cache"); response.setHeader("expires", "0"); try { https://www.360docs.net/doc/f614937578.html,("文件上传进度监测开始--------"); UploadFile.execClientScript(response, callback1 + "(" + key + ")"); long temp = 0l; while (!p.isComplete()) { if (temp != p.getCurrentLength()) { temp = p.getCurrentLength(); // 向客户端显示进度 UploadFile.execClientScript(response, callback2 + "(" + p.getCurrentLength() + "," + p.getLength() + ")"); //https://www.360docs.net/doc/f614937578.html,("progress的状态:" + p.isComplete()); } else { //https://www.360docs.net/doc/f614937578.html,("progress的状态:" + p.isComplete()); //https://www.360docs.net/doc/f614937578.html,("progress上传的数据量:+ " + p.getCurrentLength()); // 上传进度没有变化时候,不向客户端写数据,写数据过于频繁会让chrome没响应 Thread.sleep(100); } } } catch (Exception e) { LOG.error("调用客户端脚本错误,原因:" + e.getMessage()); p.setComplete(true); } try { UploadFile.execClientScript(response, callback2 + "(" + p.getCurrentLength() + "," + p.getLength() + ")"); } catch (Exception e) { p.setComplete(true); } request.getSession().removeAttribute(key); https://www.360docs.net/doc/f614937578.html,("删除progress对象的session key"); return null; } public FileService getFileService() { return fileService; } public void setFileService(FileService fileService) { this.fileService = fileService; } } download.action:这类是从临时文件中下载文件给我们实际上传的目录package com.upload; import java.io.InputStream; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class DownloadAction extends ActionSupport { private static final long serialVersionUID = 3350848163772547204L; public InputStream getDownloadFile() { return ServletActionContext.getServletContext().getResourceAsStream( "/file/aa.txt"); } @Override public String execute() throws Exception { return SUCCESS; } } 在Struts 2中实现文件上传 前一阵子有些朋友在电子邮件中问关于Struts 2实现文件上传的问题,所以今天我们就来讨论一下这个问题。 实现原理 Struts 2是通过Commons FileUpload文件上传。Commons FileUpload通过将HTTP的数据保存到临时文件夹,然后Struts使用fileUpload拦截器将文件绑定到Action的实例中。从而我们就能够以本地文件方式的操作浏览器上传的文件。 具体实现 前段时间Apache发布了Struts 2.0.6 GA,所以本文的实现是以该版本的Struts 作为框架的。以下是例子所依赖类包的列表: 清单1 依赖类包的列表 首先,创建文件上传页面FileUpload.jsp,内容如下: <% @ page language = " java " contentType = " text/html; charset=utf-8 " pageEncodi ng = " utf-8 " %> <% @ taglib prefix = " s " uri = " /struts-tags " %> Java多方式实现文件上传
基于Struts2 Result Type为chain 的Action之间数据传递
chain:基本用途是构造成一条动作链。前一个Action将控制权转交给后一个Action,而前一个Action的状态在后一个Action里仍然保持着。 我现在有一个场景,FirstAction 通过chain的方式,将控制权交给SecondAction。FirstAction对应的页面代码为first.ftl,SecondAction对应的页面代码为second.ftl。 假设我们的FirstAction如下定义: public class SecondAction extends ActionSupport{ private CustomUser user = null; public String execute() throws Exception { // 利用user做事情或显示在页面上 } // getter setter } 意思很明确了,通过first.ftl的输入,到DB中或其他,生成了我们的CustomUser对象,这个CustomUser对象将要在SecondAction使用。 于是我们想到了要配置FirstAction 的name为toSecond的Result type为chain,将生成的CustomUser对象传递到SecondAction中, 我们也这样做了,但是经过调试,发现在SecondAction中没有得到FirstAction中的CustomUser对象。 SecondAction是这样实现的: public class SecondAction extends ActionSupport{ private CustomUser user = null; public String execute() throws Exception { // 利用user做事情或显示在页面上 } // getter setter } 看一下ChainingInterceptor.java的实现,发现有这样的注释: An interceptor that copies all the properties of every object in the value stack to t he currently executing object.
struts2 strus.xml中result类型及含义
struts2strus.xml中result类型及含义 一个提交到服务器的处理通常可以分为两个阶段,第一个阶段查询服务器状态(查询或者更新数据库),第二个阶段选择一个合适的结果页面其返回给用户(这里要讲的Result的内容)。 Struts2提供了对不同种类返回结果的支持,常见的有JSP,FreeMarker,Velocity等。 Struts2支持的不同类型的返回结果为: 名字说明 Chain Result用来处理Action链 Dispatcher Result用来转向页面,通常处理JSP FreeMarker Result处理FreeMarker模板 HttpHeader Result用来控制特殊的Http行为 Redirect Result重定向到一个URL Redirect Action Result重定向到一个Action Stream Result向浏览器发送InputSream对象,通常用来处 理文件下载 Velocity Result处理Velocity模板 XLS Result处理XML/XLST模板 PlainText Result显示原始文件内容,例如文件源代码 结合Tile使用 S2PLUGINS:Tiles Result 另外第三方的Result类型还包括JasperReports Plugin,专门用来处理JasperReport类型的报表输出。 在struts-default.xml文件中已经有了对于所有类型Result的定义: Struts2配置文件中使用通配符收藏 形式一:调用相同Action中的不同方法 说明:本实例使用的是echart3,jquery1.8.1 1)struts的web.xml配置代码如下: Struts2配置文件通配符的使用说明
JAVA之struts2+ajax实现echats柱状图