关于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.上传
<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的上传实例:
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)
本文详细介绍了Struts2框架中的文件上传与下载功能。包括Struts2如何利用commons.fileupload.jar和commons.io.jar实现上传下载,核心组件的使用方法,以及如何配置Struts2的上传下载拦截器和结果类型。
1137

被折叠的 条评论
为什么被折叠?



