笔者学习了Struts2文件上传和下载,
一、首先学习一下文件上传的原理:
表单元素的enctype属性:
enctype属指定的是表单数据的编码方式,该属性有如下三个值。
1、application/x-www-form-urlencoded:这是默认编码模式,它只处理表单域的value属性值。采用这种编码方式的表单会将表单域的值处理成URL编码方式。
2、multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据。这种编码方式会把文件与域指定文件的内容也封装到请求参数里。
3、text/plain:当表单得Action属性为mailto:URL的形式时使用这种编码方式比较方便,这种方式主要适用于直接通过表单发送邮件的情况。
为了实现文件上传必须设置enctype属性设置为“”multipart/form-data",并把接受页面的代码改为直接使用二进制流处理的代码。
如果程序手动获取该请求中包含的二进制流,并将二进制流中包含的内容解析出来,程序就可以实现手动上传——完全无须任何框架的支持。
注意:一旦设置了表单的enctype="multipart/form-data" 属性,就将无法通过HttpServletRequest对象的getParamter放法取得请求参数。
二、手动上传
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ page import="java.io.*,java.util.*" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<%
InputStream is=request.getInputStream();
BufferedReader br =new BufferedReader(new InputStreamReader(is));
String buffer =null;
while((buffer=br.readLine())!=null)
{
if(buffer.endsWith("--")&&buffer.startsWith("---------------------------"))
{
if(br.readLine().indexOf("filename")>1)
{
br.readLine();
br.readLine();
File file =new File(request.getRealPath("/")+UUID.randomUUID()+".txt");
PrintStream ps =new PrintStream(new FileOutputStream(file));
String content =null;
while((content = br.readLine())!=null)
{
if(content.startsWith("----------------------"))
{
break;
}
ps.println(content);
}
ps.flush();
ps.close();
}
}
}
%>
</body>
</html>
通过分析HttpServletRequest的二进制流,解析出二进制流中所包含的全部表单域,分析出每个表单域的类型,并允许开发者取得文件域的内容字节,文件名和文件内容等信息,也可以取得其他表单域的值。
Struts2的文件上传
<form action="uploadPro" method="post" enctype="multipart/form-data">
文件标题:<input type="text" name="title"/><br>
选择文件:<input type="file" name="upload"/><br>
<input type="submit" value="上传">
</form>
package com.zmy.action;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.UUID;
import com.opensymphony.xwork2.ActionSupport;
/**
* @author Administrator
*
*/
public class UploadAction extends ActionSupport {
private String title;
private String upload;
private String uploadContentType;
private String uploadFileName;
private String savePath;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUpload() {
return upload;
}
public void setUpload(String upload) {
this.upload = upload;
}
public String getUploadContentType() {
return uploadContentType;
}
public void setUploadContentType(String uploadContentType) {
this.uploadContentType = uploadContentType;
}
public String getUploadFileName() {
return uploadFileName;
}
public void setUploadFileName(String uploadFileName) {
this.uploadFileName = uploadFileName;
}
public String getSavePath() {
return savePath;
}
public void setSavePath(String savePath) {
this.savePath = savePath;
}
@Override
public String execute() throws Exception {
// TODO Auto-generated method stub
String newName=UUID.randomUUID()+uploadFileName.substring(uploadFileName.lastIndexOf("."));
//以服务器的文件保存地址和随机文件名上传文件输入流
FileOutputStream fos=new FileOutputStream(getSavePath()+"\\"+newName);
/*创建一个向具有指定名称的文件中写入数据的输出文件流。创建一个新 FileDescriptor 对象来表示此文件连接。
首先,如果有安全管理器,则用 name 作为参数调用 checkWrite 方法。
如果该文件存在,但它是一个目录,而不是一个常规文件;或者该文件不存在,但无法创建它;抑或因为其他某些原因而无法打开它,则抛出 FileNotFoundException。
name - 与系统有关的文件名*/
FileInputStream fis=new FileInputStream(getUpload());
byte[] buffer =new byte[1024];
int len=0;
while((len=fis.read(buffer))>0)
{
fos.write(buffer,0,len);
}
setUploadFileName(newName);
return SUCCESS;
}
}
Struts2直接将文件域中包含的上传文件名和文件类型的信息直接封装到uploadFileName和uploadContentType属性中。
即如果表单中包含一个name属性为xxx的文件域,则对应得Action需要使用三个属性来封装文件域的信息:
类型为File的xxx属性封装了该文件域对应得文件内容。
类型为String的xxxFileName属性封装了该文件域对应的文件的文件名。
类型为String的xxxContentType属性封装了该文件域对应的文件的文件类型。
savePath属性,该属性的值通过配置文件来设置,从而允许动态设置该属性的值--这是典型的依赖注入。
配置文件上传的Action
与之前的区别是,该Action还配置了一个<param.../>元素,该元素用于为该Action的属性动态分配属性值。