将表单域的enctype设置为multipart/form-data,在服务器端以二进制流的方式来获取表单信息即可实现文件的上传。
手动解析二进制流可能有些繁琐,所以有两个上传框架可以实现文件上传:Commons-FileUpload和COS。
struts2则是进一步封装,让上传下载都极大简化了。
表单的enctype属性
有以下三种:
application/x-www-form-urlencoded:正常情况下我们没有设置enctype属性,便是使用这个默认值,它将表单的value属性值处理成url编码的方式。
multipart/form-data:以二进制流的方式处理表单数据,这种编码方式会把文件域的内容也封装到请求参数中
text/plain:这种方式主要用于直接通过表单发送邮件
如果以第一种是无法上传的,且看:
<%@page language="java" contentType="text/html; charset=GBK"%>
<html>
<head>
<title>文件上传</title>
</head>
<body>
<form action="process.jsp" method="post" enctype="application/x-www-form-urlencoded">
随便名字:<input type="text" name="name"/><br/>
文件名:<input type="file" name="file"/><br/>
<input type="submit" value="上传"/>
</form>
</body>
</html>
process.jsp:
<%@page language="java" contentType="text/html; charset=GBK"%>
<html>
<head>
<title>文件上传处理</title>
</head>
<body>
<%
request.setCharacterEncoding("GBK");
out.println(request.getParameter("name"));
out.println(request.getParameter("file"));
%>
</body>
</html>
以第二种方式:
<%@page language="java" contentType="text/html; charset=GBK"%>
<html>
<head>
<title>文件上传</title>
</head>
<body>
<form action="process.jsp" method="post" enctype="multipart/form-data">
随便名字:<input type="text" name="name"/><br/>
文件名:<input type="file" name="file"/><br/>
<input type="submit" value="上传"/>
</form>
</body>
</html>
process.jsp:
<%@page language="java" contentType="text/html; charset=GBK"%>
<%@page import="java.io.*" %>
<%
InputStream is = request.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String buffer = null;
while( (buffer = br.readLine()) !=null)
{
out.println(buffer + "<br>");
}
out.flush();
%>
如此即可获得二进制流用于解析:
我上传了一个xml文件,以上是页面结果一部分。
可见,已经获得了文件内容,只要将流中的文件内容解析出来即可。
使用框架的话就简单多了,上传框架会负责解析请求中的所有域,包括表单的文件域和其他表单域。
struts2并没有提供请求解析器,而是使用了Commons-Fileupload框架,并做了进一步的封装,是的文件上传极大简化。当然,也可以使用struts.multipart.parser常量来更换文件上传的解析器。
知道了实现文件上传大概都要做些什么,现在来看看struts2给我们带来的便利。
upload.jsp:
<%@page language="java" contentType="text/html; charset=GBK"%>
<html>
<head>
<title>文件上传</title>
</head>
<body>
<form action="upload.action" method="post" enctype="multipart/form-data">
文件名字:<input type="text" name="name"/><br/>
文件:<input type="file" name="file"/><br/>
<input type="submit" value="上传"/>
</form>
</body>
</html>
action:
public class UploadAction {
private String name;
private File file;
private String fileContentType;
private String fileFileName;
private String savePath;
public String execute() throws IOException{
FileOutputStream out = new FileOutputStream(new File(getSavePath()+"\\"+getFileFileName()));
BufferedInputStream br = new BufferedInputStream(new FileInputStream(getFile()));
byte[] buf = new byte[1024];
while(br.read(buf)!= -1){
out.write(buf);
}
out.close();
br.close();
return "success";
}
public String getSavePath() {
return ServletActionContext.getRequest().getRealPath(savePath);
}
public void setSavePath(String savePath) {
this.savePath = savePath;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
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;
}
}
应当注意的是getSavePath(),它比较特殊。
另外,一个File域xxx在action类中应对应三个属性:xxxFileName,xxxContentType,xxx。savaPath是在xml文件中指定的,看如下action配置:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<package name="default" namespace="/" extends="struts-default">
<global-results>
<result name="error">/error.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="error"/>
</global-exception-mappings>
<action name="upload" class="ch6.fileupload.UploadAction">
<param name="savePath">/fileupload</param>
<result name="success">/fileupload/result.jsp</result>
<result name="error">/conversion/error.jsp</result>
</action>
</package>
</struts>
在文件目录中应该有upload目录,用于存放上传的文件。
另外,struts2已经定义了拦截器用于控制上传文件的类型过滤和大小限制:
<action name="upload" class="ch6.fileupload.UploadAction">
<interceptor-ref name="fileUpload">
<param name="maximumSize">20000</param>
<param name="allowedTypes">image/bmp</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"/>
<param name="savePath">/fileupload</param>
<result name="success">/fileupload/result.jsp</result>
<result name="error">/conversion/error.jsp</result>
</action>
如此即可。
实现多个文件的上传
在upload.jsp中:定义多个file域,并让他们name相同。
在action中:定义File[] upload,String[] uploadFileName,String[] contentType,在execute()对每个file处理即可。也可以使用List来保存File和String
其他的都一样了。