Struts2本身没有提供解析上传文件内容的功能,它通过第三方上传组件来实现文件上传的功能。So,我们通过使用Struts2实现文件上传的功能,首先要将commons-fileupload-1.2.1.jar和commons-io-1.4.jar复制到项目的WEB-INF/lib目录下。
Struts2的上传组件只有一个拦截器: org.apache.struts2.interceptor.FileUploadInterc eptor(这个拦截器不用配置,是自动装载的),它负责调用底层的文件上传组件解析文件内容,并为Action准备与上传文件相关的属性值。
下面是上传单个文件JSP页面代码片段,上传页面的表单中有file和text两种类型的元素。
singleupload.jsp:
<!--在进行文件上传时,表单提交方式一定要是post的方式,因为文件上传时二进制文件可能会很大,还有就是enctype属性,这个属性一定要写成multipart/form-data,不然就会以二进制文本上传到服务器端-->
<th>日期</th>
<td>
<input type="text" id="startdate" name="startdate" />
</td>
<th>文件上传 </th>
<td colspan="3">
<input type="file" id="upload" name="upload" size="45" >
</td>
以下是对应的请求action,一般文件上传后会先生成一个.tmp临时文件:
方法1:
通过临时文件获取数据。
这里要强调的是:处理文件上传请求的Action必须提供特殊样式命名的属性。例如,假设表单中文件选择框的名字为upload,那么Action就应该提供以下三个属性upload,uploadFileName,uploadContentType来分别表示上传文件的File对象、上传文件名以及上传文件内容类型
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import jxl.Sheet;
import jxl.Workbook;
import lombok.Data;
public @Data class UploadAction extends BaseAction {
// @Data映射getter,setter 方法
private File upload; //file表单
private String startdate;
private String uploadFileName;//提交过来的file的名字
private String uploadContentType;//提交过来的file的MIME类型
public void uploadReport() {
try {
String str="";
InputStream is = new FileInputStream(upload);
Workbook rwb = Workbook.getWorkbook(is);
int sheetCount = rwb.getNumberOfSheets();
Sheet rs = rwb.getSheet(0);
int rows = rs.getRows(); // 行
int cols = rs.getColumns(); // 列
for (int i = 0; i < rows ; i++) {
str=rs.getCell(0,i).getContents().trim();
}
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
这里的upload并不是真正指代jsp传过来的文件,而是一个临时文件。当文件上传过来时,struts2首先会寻找struts.multipart.saveDir所指定的存放位置(我们也可以新建一个struts.properties属性文件来指定临时文件的位置),如果没有指定,那么文件会存放在tomcat的work\Catalina\localhost\目录下
这种方法能获取到upload临时文件,也能够获取到表单元素内的值。如果要获取真正的文件,我们可以制定文件上传后的存放位置,然后通过输出流将其写到流里面就行了,如以下代码段
//此代码段暂时没写
方法2:
也可以通过以下的这个方法来获取上传文件
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import jxl.Sheet;
import jxl.Workbook;
import lombok.Data;
public @Data class UploadAction extends BaseAction {
public void uploadReport() {
String str="";
int rows = 0;
List<FileItem> templist = null;
// 上传文件这开始
try {
String contentType = this.getRequest().getContentType(); // 获取客户端给服务器发送数据的格式
File filedir = new File(System.getProperty("user.dir") + "/1fileTop");
HttpServletRequest request = this.getRequest();
DiskFileItemFactory difactory = new DiskFileItemFactory(); // 对象的工厂,可以设定缓冲区大小和存放临时文件目录。
difactory.setSizeThreshold(1024 * 1024 * 3); // 设定的缓冲区 3M,如果不指定,那么缓冲区的大小默认是10KB
difactory.setRepository(filedir); // 设置上传文件的临时目录
ServletFileUpload sfu = new ServletFileUpload(difactory);
sfu.setHeaderEncoding("UTF-8");// 解决上传文件名的中文乱码
templist = (List<FileItem>) sfu.parseRequest(request); // 解析request请求
System.out.println("templist:" + templist.size());
Map param = new HashMap();
if (templist != null && templist.size() > 0) {
// 遍历判断是表单输入域 还是 文本上传域
for (FileItem item : templist) {
if (item.isFormField()) {
param.put(item.getFieldName(), item.getString("UTF-8"));// 如果你页面编码是utf-8的
System.out.println("普通输入项");
} else {
System.out.println("上传文件输入项");
Workbook rwb = Workbook.getWorkbook(item.getInputStream()); //获取文件的输入流
int sheetCount = rwb.getNumberOfSheets();
Sheet rs = rwb.getSheet(0);
rows = rs.getRows(); // 行
int cols = rs.getColumns(); // 列
for (int i = 0; i < rows; i++) {
str=rs.getCell(0, i).getContents().trim(); // getCell(列,行)
}
}
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 获取文件结束
}
通过这种方法进行文件上传可能会遇到的异常:
1.无法通过属性的getter,setter方法来获取表单中对应的属性值,可以通过以上方法中item.getString(“UTF-8”)单个获取,但是比较麻烦,特别是对于表单是一个封装的对象来说
2.解析request请求时,debug得到request里有值,但是sfu.parseRequest(request)解析request为空。原因大概是struts2的源代码FileUploadInterceptor在跳转到action对应的方法之前已经对request进行了解析,而request只能被解析一次。
这个问题需要根据struts2-core-2.3.15.2.jar的包名来解决。
a.如果struts2是status2.3.4 , 在配置文件struts.xml里加上
<bean type= "org.apache.struts2.dispatcher.multipart.MultiPartRequest" name= "myRequestParser" class= "com.icf.common.base.actions.RequestParseWrapper" scope= "default" optional= "true " />
<constant name= "struts.multipart.handler" value= "myRequestParser" />
public class RequestParseWrapper extends JakartaMultiPartRequest {
public void parse(HttpServletRequest servletRequest, String saveDir)throws IOException{
}
}
b.如果struts2是struts2.3.15.1以后的版本,在struts2.3.15.1后的配置里,struts2的struts-default.xml 里把 struts.multipart.handler 改成了struts.multipart.parser,在struts配置文件中加上
<bean type= "org.apache.struts2.dispatcher.multipart.MultiPartRequest" name= "myRequestParser" class= "com.icf.common.base.actions.RequestParseWrapper" scope= "default" optional= "true " />
<constant name= "struts.multipart.parser" value= "myRequestParser" />
创建一个自己的类RequestParseWrapper
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest;
public class RequestParseWrapper extends JakartaMultiPartRequest {
@Override
public void parse(HttpServletRequest arg0, String arg1) throws IOException {
}
}