为了能上传文件,我们必须将表单的method设置为post,将enctype设置为multipart/form-data,只有在这种情况下,浏览器才会把用户选择的文件的二进制数据发送给服务器。
Struts2并未提供自己的请求解析器,也就是说,Struts2不会自己去处理multipart/form-data的请求数据,它需要调用其他上传框架来解析二进制请求数据。但Struts2在原有的上传解析器基础上做了进一步封装,从而进一步简化了文件上传。
在Struts2的default.properties文件中,有如下配置:
# struts.multipart.parser=cos
# struts.multipart.parser=pell
struts.multipart.parser=jakarta
Struts2的封装隔离了底层文件上传组件的区别,开发者只要配置文件上传所使用的解析器,就可以轻松地在不同的文件上传框架之间切换。如果不配置的话,默认使用jakarta解析器。
fileupload.jsp :
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
<s:form action="upload" enctype="multipart/form-data" method="post">
<s:file name="file" label="上传文件"></s:file>
<s:submit value="上传"></s:submit>
</s:form>
</body>
</html>
struts.xml :
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
<package name="demo" extends="struts-default">
<action name="upload" class="action.UploadAction">
<param name="savePosition">/uploadDir</param>
<result name="success">/success.jsp</result>
</action>
</package>
</struts>
UploadAction.java :
public class UploadAction extends ActionSupport {
private File file;
private String fileContentType;
private String fileFileName;
private String savePosition;
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public String getFileContentType() {
return fileContentType;
}
public void setFileContentType(String fileContentType) {
this.fileContentType = fileContentType;
}
public String getFileFileName() {
return fileFileName;
}
public void setFileFileName(String fileFileName) {
this.fileFileName = fileFileName;
}
public String getSavePosition() {
return savePosition;
}
public void setSavePosition(String savePosition) {
this.savePosition = savePosition;
}
@Override
public String execute() throws Exception {
String realPath=
ServletActionContext.getServletContext().getRealPath(getSavePosition());
FileOutputStream fos=new FileOutputStream(
realPath+File.separator+getFileFileName());
FileInputStream fis=new FileInputStream(getFile());
byte[] buffer=new byte[1024];
int len=0;
while((len=fis.read(buffer))!=-1){
fos.write(buffer,0,len);
}
return "success";
}
}
success.jsp :
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
<s:property value="fileFileName"/>上传成功...
</body>
</html>
解释:我们看到表单的文件域的name属性为file(当然也可以取其他名),对应的Action使用了一个File类型来封装它,同时提供了xxxFileContentType和xxxFileName来封装文件的类型和名称,必须要这样做,因为Struts2就是这么设计的。可以认为:如果表单中包含一个name属性为xxx的文件域,则对应Action需要使用3个属性来封装该文件域的信息。
① 类型为File的xxx属性封装了该文件域对应的文件内容。
② 类型为String的xxxContentType属性封装了该文件域对应的文件类型。
③ 类型为String的xxxFileName属性封装了该文件域对应的文件名称。
除此之外,Action中还提供了一个savePosition属性,该属性的值通过配置文件struts.xml来进行配置,从而实现上传目录的动态可配置。
Struts2的Action中的属性,功能非常丰富:
① 可以用于封装HTTP请求参数
② 可以封装Action的处理结果
③ 还可通过在Struts2的配置文件struts.xml中进行配置,接收框架的注入,允许在配置文件中为该属性动态指定值。
本例中,我们上传时把文件保存到服务器时,该文件的文件名依然没有发生改变,这在实际项目中需要改进,因为多个用户并发上传时可能发生文件名相同的情形,因此建议使用java.util.UUID工具类来生成唯一的文件名。