`
PerfectPlan
  • 浏览: 121161 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论
阅读更多

 

 关于struts2-上传与下载

 

一、struts2的上传下载是如何实现的?

:其实struts2框架中的下载是基于commons.fileupload.jar 和 commons.io.jar来实现的它只是将某些复

   杂的逻辑代码封装起来,并且简化从而利于开发者的开发。

二、struts2上传下载的核心是怎么样的?

  1.struts2上传下载的核心是由commons.fileupload中的ServletFileUpload和DiskFileItemFactory类

  来实现(在commons.fileupload.jar中以前的版本,主要使用的是FileUpload类。新的版本提倡使用   FileUpload的子类ServletFileUpload)

  2.DiskFileItemFacotry需要设置两个参数

   :Repository:创建一个文件上传的缓存目录

   SizeThreshold:设置在缓存中的文件大小

 

  3.ServletFileUpload实现它的一个有参构造方法

   :参数为FileItemFactory(它是一个接口) DiskFileItemFactory实现了这个接口

   :通过ServletFileUpload类的parseRequest()方法获取一个List<FileItem>集合,通过对集合的遍历解

    析获取表单中的信息

  4.下面提供一个以Servlet和jsp 使用commons.fileupload 和commons.io 实现的上传功能

   Servlet:(UploadServlet)

package org.viancent.servlet;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
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.FileUpload;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class UploadServlet extends HttpServlet {
	@Override
	@SuppressWarnings("unchecked")
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		/*
		 * 注意,当jsp中表单的enctype设置的为:multipart/form-data的时候 我们无法直接使用
		 * request.getParameter("") 获取表单的数据信息
		 */
		// 使用DiskFileItemFacotry类进行表单的处理,以及文件的上传
		DiskFileItemFactory disk = new DiskFileItemFactory();
		// 获取WebRoot目录下的upload文件夹的路径
		String path = req.getRealPath("/upload");
		disk.setRepository(new File(path));// 设置上传文件的缓存目录
		disk.setSizeThreshold(1024 * 1024); // 设置文件的大小,如果超过这个大小,文件则会直接向硬盘存入

		// 借助ServletFileUpload 进行表单的解析,与文件的流的处理
		ServletFileUpload upload = new ServletFileUpload(disk);
		try {
			List<FileItem> list = upload.parseRequest(req);
			// List<FileItem>中保存着有关表单元素的所有信息 需要对它进行遍历
			for (FileItem item : list) {
				// item.isFormField() 判断该元素是不是表单的一个字段 如果是 则可以直接取得它的名称和内容
				if (item.isFormField()) {
					String name = item.getFieldName();
					/*
					 * 获取该字段的名称 如:<input type="text" name="password"/>
					 * 该方法便是获取name属性的值 :password
					 */
					String value = item.getString("gbk");
					/* 获取该字段的value属性的值 */
					req.setAttribute(name, value);
				} else// else则证明它是一个file文件流
				{
					String name = item.getFieldName();
					String value = item.getName();
					/*
					 * 对于表单中的file元素,我们不能通过getString获取它的内容,因为它是一个流
					 * 只能够通过getName方法获取当前文件的名称
					 */
					int start = value.lastIndexOf("\\");
					// 对value进行处理,由于某些浏览器 可能只显示 文件名+后缀
					// 有的则将文件的全部路径都显示出来 ,所以我们要在这里对它进行一次通用处理
					String filename = value.substring(start + 1);
					// 记住一定要将start+1 因为start的位置对应的是'\\'
					req.setAttribute(name, filename);
					// 创建输入流 与 输出流
					InputStream input = item.getInputStream();
					byte[] buffer = new byte[1024];
					int length = 0;
					OutputStream os = new FileOutputStream(new File(path,
							filename));
					// 开始读取并写入信息
					while ((length = input.read(buffer)) > 0) {
						os.write(buffer, 0, length);
					}
					// 一次关闭流
					os.close();
					input.close();
					// 上传完毕
					System.out.println("Upload Over!");
				}
			}
		} catch (FileUploadException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// 请求转发
		req.getRequestDispatcher("/upload/result.jsp").forward(req, resp);
	}
}

  Jsp:(upload.jsp)

<form action="/struts2/upload" method="post"
	enctype="multipart/form-data">
	//一定要设置form表单的 //method属性和enctype实行 UserName:<input type="text"
		name="username" id="username" /><br /> Password:<input type="password"
		name="password" id="password" /><br /> File: <input type="file"
		name="file" id="file" /><br /> <input type="submit" value="submit" />
</form>
 

  三、如何使用struts2封装后的上传与下载

: 1.上传

a):对于struts2中的上传主要是由struts-default.xml中名为:fileUpload的拦截器实现的通过拦截客户
端的请求,获取数据信息实现上传功能。
b):实现的主要步骤
1.我们需要创建一个对应上传的Action,在Action中我们需要定义三个字段用于存储表单中文件的信息
如下:
如果页面(<input type="file" name="upload">表单中的file元素名为:upload,那么我们需要在
Action中定义如下字段
private File upload; //对应文件流  根据表单的中的file元素的name属性值命名
private String uploadFileName;  //对应文件的名称 表单name属性值+FileName
private String uploadContentType; //对应文件的类型 表单name属性值+ContentType
/*命名规范是固定,并且要实现它们的getter 和 setter方法 可以参看fileUpload拦截器对应的
        Interceptor类中代码
主要用于拦截器为定义的属性进行赋值,以及后面的调用
*/
2.我们需要在struts.xml 文件中配置一个对应上传的<Action>
如下:
在定义的Action标签中需要添加名为 fileUpload的拦截器,并为它的属性进行赋值。
<interceptor ref="fileUpload">
//可以设置 上传文件的类型,最大大小,
/*
在FileUploadInterceptor 源代码中 有如下片段实例
 * <ul>
 * <p/>
 * <li>maximumSize (optional) - the maximum size (in bytes) that the interceptor will allow a file reference to be set
 * on the action. Note, this is <b>not</b> related to the various properties found in struts.properties.
 * Default to approximately 2MB.</li>
 * <p/>
 * <li>allowedTypes (optional) - a comma separated list of content types (ie: text/html) that the interceptor will allow
 * a file reference to be set on the action. If none is specified allow all types to be uploaded.</li>
 * <p/>
 * <li>allowedExtensions (optional) - a comma separated list of file extensions (ie: .html) that the interceptor will allow
 * a file reference to be set on the action. If none is specified allow all extensions to be uploaded.</li>
 * </ul>
			 
 maximumSize:设置单个上传文件的最大字节,struts2中默认的总上传文件的大小为2097152字节(2M) 我们可以通过
 <Constant name="struts.multipart.maxSize" value="">value指定大小 ,单位为字节
 allowedTypes:设置上传文件的类型 上传的文件类型可以参考tomcat中web.xml配置中的文件类型信息
 属性值 如:application/vnd.ms-powerpoint 代表文件的类型为ppt
 allowedExtensions:设置文件的扩展名,同上一个属性的效果是一样的,不过它的属性值更加
 直观易懂 如: .ppt 
 */	
 <param name="allowedExtensions">.ppt,.txt</param>//使用<param>标签进行赋值
 <param name="maximumSize">409600</param>//上传单个文件的最大字节
 </interceptor ref>
 3.一个使用struts2的上传实例:
Action:
package org.viancent.action;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

public class UploadAction extends ActionSupport {

	private String username;
	private String password;
	/*
	 * 如果每次只上传一个文件 就可以使用上面介绍的代码
	 * 
	 * 这里义的泛型集合,是为了上传多个文件,也可以用数组 如:
	 *  privaet File [] file;
	 * private String [] fileFileName;
	 * private String [] fileContentType;
	 */
	private List<File> file;
	private List<String> fileFileName;
	private List<String> fileContentType;

	/*
	 * 为什么要定义fileFileName 和filecontextType 这里是用于FileUpload的拦截器的赋值
	 */
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public List<File> getFile() {
		return file;
	}

	public void setFile(List<File> file) {
		this.file = file;
	}

	public List<String> getFileFileName() {
		return fileFileName;
	}

	public void setFileFileName(List<String> fileFileName) {
		this.fileFileName = fileFileName;
	}

	public List<String> getFileContentType() {
		return fileContentType;
	}

	public void setFileContentType(List<String> fileContentType) {
		this.fileContentType = fileContentType;
	}

	@Override
	public String execute() throws Exception {
		// 指定上传的位置
		String path = ServletActionContext.getRequest().getRealPath("/upload");
		for (int i = 0; i < file.size(); i++) {
			// 获取输入流
			InputStream is = new FileInputStream(file.get(i));
			byte[] buffer = new byte[1024];
			int length = 0;
			// 创建输出流对象
			OutputStream os = new FileOutputStream(new File(path, this
					.getFileFileName().get(i)));
			// 开始上传
			while ((length = is.read(buffer)) > 0) {
				os.write(buffer, 0, length);
			}
			// 一次关闭流
			os.close();
			is.close();
		}
		// 返回结果
		return SUCCESS;
	}
}
  View : upload2.jsp
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'upload2.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">

<script type="text/javascript">
							function addMore() //触发此方法后添加一个,file元素
							{
							var td= document.getElementById("more");

							var br=document.createElement("br");

							var input = document.createElement("input");

							var button = document.createElement("input");

							input.type="file";
							input.name="file";

							button.type="button";
							button.value="Remove";
							button.onclick=function ()//为Remove按钮注册一个点击事件
							{
								td.removeChild(br);
								td.removeChild(input);
								td.removeChild(button);
								}
							td.appendChild(br);
							td.appendChild(input);
							td.appendChild(button);
								}
						</script>
</head>
<body style="text-align: center">

	<div style="text-align: left">
		<s:fielderror cssStyle="color:red"></s:fielderror>
		<s:actionerror />
	</div>
	<s:form action="upload" method="post" enctype="multipart/form-data"
		theme="simple">
		<table border="1" width="80%">
			<tr>
				<td>UserName:</td>
				<td><s:textfield name="username"></s:textfield></td>
			</tr>
			<tr>
				<td>PassWord:</td>
				<td><s:password name="password"></s:password></td>
			</tr>
			<tr>
				<td>File1:</td>
				<td id="more"><s:file name="file"></s:file> <input
					type="button" value="Add More" onclick="addMore()"></td>
			</tr>
			<tr>
				<td><s:submit value="Submit"></s:submit></td>
				<td></td>
			</tr>

		</table>
	</s:form>
</body>
</html>

  struts.xml的配置信息

				<struts>

					<constant name="struts.multipart.saveDir" value="e:\"></constant>//设置缓存文件的存放位置(当上传完成后,会被自动删除)
					<constant name="struts.i18n.encoding" value="gbk"></constant> //设置编码格式
					<constant name="struts.custom.i18n.resources" value="message"></constant>//当上传失败的时候,可以在指定的message.properties中定义显示的错误信息

					<package name="struts2" extends="struts-default">

						<action name="upload" class="org.viancent.action.UploadAction">
							<result name="success">/upload/result.jsp</result>
							<result name="input">/upload/upload2.jsp</result>

							<interceptor-ref name="fileUpload">
								<param name="allowedExtensions">.ppt,.txt</param>
								<param name="maximumSize">409600</param>
							</interceptor-ref>
							<interceptor-ref name="defaultStack"></interceptor-ref>
						</action>
					</package>
				</struts>

 

//当上传的文件太大,或者文件类型不符合规定的时候我们可以自定义一个资源文件
//根据struts-message.properties中的默认属性名 在自己定义的资源文件中给这些属性重新赋值
struts.messages.error.file.too.large=File too large: {0} "{1}" "{2}" {3}
//当文件太大的时候抛出的错误信息
struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" "{2}" {3}
//文件类型不符合规定的时候抛出的错误信息
struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3}
//当文件的扩展名不符合规定的时候抛出的错误信息
//注意这些错误都是FieldError级别的 如果希望在页面上显示,那么就要使用 <s:fielderror>标签
 

4.介绍一下关于defalut.properties 中的struts.multipart.maxSize 和 fileUpload中的

maximumSize的区别!

 

1.struts.multipart.maxSize掌控整个项目所上传文件的最大的Size。超过了这个size,后台报

错,程序处理不了如此大的文件。ActionError里面会有如下的提示:

the request was rejected because its size (16272982) exceeds the configured

maximum (9000000)

 

2.fileUpload拦截器的maximumSize属性必须小于struts.multipart.maxSize的值。

struts.multipart.maxSize默认2M,当maximumSize大于2M时,必须设置

struts.multipart.maxSize的值大于maximumSize。

 

3.当上传的文件大于struts.multipart.maxSize时,系统报错

当上传的文件在struts.multipart.maxSize和maximumSize之间时,系统提示:

File too large: file "MSF的

 

 

2.下载

a):关于下载主要是有struts-default.xml中的<result-type name="stream"

class="org.apache.struts2.dispatcher.StreamResult"/>来完成的

所以我们只需要设置struts.xml中对应下载的<action>中的<result type="">的type属性 将它设置成:

stream。

1.为stream对应的org.apache.struts2.dispatcher.StreamResult.class类的属性进行赋值主要有

如下属性:

 

//StreamResult类中的字段源码
/*
			protected String contentType = "text/plain";//设置下载文件的类型
			protected String contentLength;				//设置文件的大小
			protected String contentDisposition = "inline";	//设置下载的时候显示的文件名
			protected String contentCharSet ;				//设置编码格式
			protected String inputName = "inputStream";		
			//设置对应下载的Action类中获取java.io.InputStream的类的名称 在Action中该类的名称最好为:
			// public InputStream getInputStream(){}
			protected int bufferSize = 1024;	//设置下载缓冲大小		
*/

       2.具体实例如下:

struts.xml:

						
						<action name="download" class="org.viancent.action.DownloadAction">
							<result name="success" type="stream">
								
								<param name="contentType">application/vnd.ms-powerpoint</param>//这里的赋值方式 与 fileUploadInterceptor的allowedTypes方式相同
								<param name="contentDisposition">filename="${fileNames}"</param>
								/*
									${fileNames} 这个el表达是是为了获取Action中 getFileNames()方法的返回值
									该方法是为了解决文件乱码实现的
								*/
								<param name="inputName">inputStream</param>
								/*
									inputStream 是为了获取对应Action 中的getInputStream()方法的返回值
									该返回值的类型为 java.io.InputStream
								*/
								<param name="bufferSize">4096</param>
								
							</result>
						</action>

 Action:

package org.viancent.action;

import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class DownloadAction extends ActionSupport {

	private String pathName; // 该字段是为了获取页面传过来的文件名称的信息

	public String getPathName() {
		return pathName;
	}

	public void setPathName(String pathName) {
		this.pathName = pathName;
	}

	public String getFileNames() throws Exception {
		// 返回文件的名称 给<param
		// name="contentDisposition">filename="${fileNames}"</param>
		return this.getPathName();
	}

	public InputStream getDownload() throws Exception {
		// 这里是一个重点 获取一个输入流
		return ServletActionContext.getServletContext().getResourceAsStream(
				"/upload/"/* 获取WebRoot/upload/的某一个文件 */
						+ new String(this.getPathName().getBytes("iso-8859-1"),
								"gb18030"));
		// new String(this.getPathName().getBytes("iso-8859-1"),"gb18030")
		// 将文件名进行转码 转换成简体中文
		// 当没有找到该文件对象的时候 会抛出
		/*
		 * Can not find a java.io.InputStream with the name [download] in the
		 * invocation stack. Check the <param name="inputName"> tag specified
		 * for this action.
		 */
	}

	@Override
	public String execute() throws Exception {
		return SUCCESS;
	}
}

  Jsp (upload2.jsp)

<a href="/struts2/download.action?pathName=第四讲.ppt">下载一</a>
<a href="/struts2/download.action?pathName=12.txt">下载二</a>
/*
pathName=第四讲.ppt
对Action中的pathName属性进行赋值,用于指定下载哪一个文件
*/
5
3
分享到:
评论
3 楼 PerfectPlan 2012-06-17  
fancy2010love 写道
// 获取WebRoot目录下的upload文件夹的路径 
29.  String path = req.getRealPath("/upload"); 
req.getRealPath这个方法已经过时了,应该不建议再使用吧

嗯嗯,是不建议是用了。以前写的,谢谢建议哦
2 楼 fancy2010love 2012-06-17  
String path = request.getSession().getServletContext().getRealPath("/upload")
这个方法应该可以吧
1 楼 fancy2010love 2012-06-17  
// 获取WebRoot目录下的upload文件夹的路径 
29.  String path = req.getRealPath("/upload"); 
req.getRealPath这个方法已经过时了,应该不建议再使用吧

相关推荐

Global site tag (gtag.js) - Google Analytics