在web开发应用中,文件上传是很多情形下必备的一项功能。本文详细介绍如何通过struts2实现一个简单的文件上传功能。
首先了解几个术语:
MIME类型:设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。是描述消息内容类型的因特网标准。 MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据。Tomcat的安装目录/conf/web.xml 中就定义了大量MIME类型。
拦截器:是Struts 2的一个强有力的工具,有许多功能(feature)都是构建于它之上,如国际化、转换器,校验等。它是AOP思想的编程方式。提供一种机制使开发者能把相对独立的代码抽象出来,配置到Action前后执行。
准备相应的jar包:commons-fileupload-1.2.1.jar;commons-io-1.4.jar;commons-logging-1.0.4.jar;freemarker-2.3.8.jar;ognl-2.6.11.jar;struts2-core-2.0.14.jar;xwork-2.0.7.jar。
接下来编写一个Action名字叫做UploadAction,继承自ActionSupport虽然struts2的Action抛弃了request,response等Servlet API,但我们仍然可以通过ServletActionContext来得到相关Servlet对象,比如request,response,application,session等。
- package org.common.action;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import org.apache.struts2.ServletActionContext;
- import com.opensymphony.xwork2.Action;
- import com.opensymphony.xwork2.ActionContext;
- import com.opensymphony.xwork2.ActionSupport;
- @SuppressWarnings("all")
- public class UploadAction extends ActionSupport {
- private File attach;
- private String attachContentType;
- private String attachFileName;
- public String upload() throws Exception {
- File saved = new File(ServletActionContext.getServletContext().getRealPath("uploads"), attachFileName);
- FileInputStream fis = null;
- FileOutputStream fos = null;
- try {
- saved.getParentFile().mkdirs();
- fis = new FileInputStream(attach);
- fos = new FileOutputStream(saved);
- byte[] bytes = new byte[1024];
- int len = 0;
- while ((len=fis.read(bytes))!=-1) {
- fos.write(bytes, 0, len);
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (fis!=null) {
- fis.close();
- }
- if (fos!=null) {
- fos.close();
- }
- }
- return Action.SUCCESS;
- }
- public File getAttach() {
- return attach;
- }
- public void setAttach(File attach) {
- this.attach = attach;
- }
- public String getAttachContentType() {
- return attachContentType;
- }
- public void setAttachContentType(String attachContentType) {
- this.attachContentType = attachContentType;
- }
- public String getAttachFileName() {
- return attachFileName;
- }
- public void setAttachFileName(String attachFileName) {
- this.attachFileName = attachFileName;
- }
- }
package org.common.action;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
@SuppressWarnings("all")
public class UploadAction extends ActionSupport {
private File attach;
private String attachContentType;
private String attachFileName;
public String upload() throws Exception {
File saved = new File(ServletActionContext.getServletContext().getRealPath("uploads"), attachFileName);
FileInputStream fis = null;
FileOutputStream fos = null;
try {
saved.getParentFile().mkdirs();
fis = new FileInputStream(attach);
fos = new FileOutputStream(saved);
byte[] bytes = new byte[1024];
int len = 0;
while ((len=fis.read(bytes))!=-1) {
fos.write(bytes, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fis!=null) {
fis.close();
}
if (fos!=null) {
fos.close();
}
}
return Action.SUCCESS;
}
public File getAttach() {
return attach;
}
public void setAttach(File attach) {
this.attach = attach;
}
public String getAttachContentType() {
return attachContentType;
}
public void setAttachContentType(String attachContentType) {
this.attachContentType = attachContentType;
}
public String getAttachFileName() {
return attachFileName;
}
public void setAttachFileName(String attachFileName) {
this.attachFileName = attachFileName;
}
}
配置struts.xml文件,注意package继承struts-default的相关配置,在使用拦截器的时候,在Action里面最后一定要引用struts2自带的拦截器缺省堆栈defaultStack,不然会出错。
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE struts PUBLIC
- "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
- "http://struts.apache.org/dtds/struts-2.0.dtd">
- <struts>
- <constant name="struts.multipart.maxSize" value="50000000" />
- <constant name="struts.multipart.saveDir" value="/mytemp" />
- <package name="main" extends="struts-default">
- <!-- 所有的全局Result -->
- <global-results>
- <result name="login">/WEB-INF/jsp/login.jsp</result>
- </global-results>
- <action name="struts" class="org.common.action.UploadAction">
- <interceptor-ref name="fileUpload">
- <param name="allowedTypes">image/bmp, image/x-png, image/gif, image/jpeg</param>
- <param name="maximumSize">204800</param>
- </interceptor-ref>
- <interceptor-ref name="defaultStack"></interceptor-ref>
- <result name="input">/index.jsp</result>
- <result name="success">/WEB-INF/jsp/welcome.jsp</result>
- </action>
- </package>
- </struts>
上传文件的jsp页面(注意file的name属性一定要与Action里面的File类型属性名一致):
- <body>
- <s:form enctype="multipart/form-data" action="struts!upload.action" method="post">
- <s:file name="attach" label="图片附件"></s:file>
- <s:submit value="上传"></s:submit>
- <s:reset value="重置"></s:reset>
- </s:form>
- </body>
<body>
<s:form enctype="multipart/form-data" action="struts!upload.action" method="post">
<s:file name="attach" label="图片附件"></s:file>
<s:submit value="上传"></s:submit>
<s:reset value="重置"></s:reset>
</s:form>
</body>
上传成功的jsp页面:
- <%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
- <%@ taglib uri="/struts-tags" prefix="s" %>
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <html>
- <head>
- <title>登录成功</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <!--
- <link rel="stylesheet" type="text/css" href="styles.css">
- -->
- </head>
- <body>
- <h1>恭喜你,<s:property value="username" />上传成功!</h1><br>
- </body>
- </html>
总结一下:导入文件上传相关的两个组件commons-fileupload.jar和commons-io.jar,两者缺一不可;前台form表单设置enctype="multipart/form-data",file标签的name属性要与相关Action里的File属性名一致;后台定义上传Action,该Action可以定义文件的原始名称xxx与file的那么属性一致,struts会将原文件名设置到该属性上,此外还可以设置xxxContentType和xxxFileName属性,只要设置了这些都要提供相关的getter和setter方法供struts使用;根据需要使用fileUpload拦截器,从而可以限制上传文件大小和文件类型,注意上传文件大小需要在struts.multipart.maxSize属性要大于拦截器的maximumSize属性,否则maximum参数不起作用;显示使用了拦截器后,一定要将<interceptor-ref name="defaultStack"></interceptor-ref>引入;当想实现多个文件上传时,只需在Action中指定File[]或者List<File>类型的变量,并使用多个同名的<s:file />标签即可,如:
private File[] attach;
private String[] attachContentType;
private String[] attachFileName;