背景:
文件上传有许多方式可以做到,并不困难,本文仅仅记录struts2框架的文件上传的使用。
前台html:
<!--//重点1:enctype="multipart/form-data" 最好单独做一个表单提交文件。-->
<form id="form1" enctype="multipart/form-data" action="upload!fileUpload.action" method="post">
<!--//重点2:post提交,submit表单。-->
<table cellspacing="0" cellpadding="0" width="100%" id="tab">
<tbody>
<tr>
<th width="30%">
导入文件:
</th>
<td width="50%">
<input style="width:175px;" type="file" name="upFile" id="file" value=""/>
</td>
<td width="20%">
<!--//重点3:name属性要与后台Action的File属性一致。struts2在上传文件时就绑定了File的一些属性,此处在getFile里上传了文件-->
<input type="button" onclick="getFile();" value="解析" style="margin-left:10px;margin-right:3px;width:40px;overflow:visible;">
</td>
</tr>
</tbody>
</table>
</form>
补充:表单的encType属性:
application/x-www-form-urlencoded: 窗体数据被编码为名称/值对。这是标准的编码格式。
multipart/form-data: 窗体数据被编码为一条消息,页上的每个控件对应消息中的一个部分。
text/plain: 窗体数据以纯文本形式进行编码,其中不含任何控件或格式字符。
常用有两 种:
application/x-www-form-urlencoded和multipart/form-data,默认为application /x-www-form-urlencoded。 当action为get时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1& amp;name2=value2…),然后把这个字串append到url后面,用?分割,加载这个新的url。 当action为post时候,浏览器把form数据封装到http body中,然后发送到server。
如果没有type=file的控件,用默认的application/x-www-form-urlencoded就可以了。 但是如果有type=file的话,就要用到multipart/form-data了。浏览器会把整个表单以控件为单位分割,并为每个部分加上 Content-Disposition(form-data或者file),Content-Type(默认为text/plain),name(控件 name)等信息,并加上分割符(boundary)。
$('#form1').ajaxSubmit({
//有关 ajaxSubmit 请参考 http://www.cnblogs.com/xiaosama/p/4747848.html 以及百度
success:function(date){
//提交整个表单,文件会以二进制作为multidate形式上传。
if(date=="success"){
geneTableSelect();
}
}});
这样,就通过表单的action找到struts2相应的处理类,这里 upload!fileUpload.action 对应自己项目的处理类。
文件到达struts2,需要配置(以下配置可二选一):
struts.properies
struts.properies:存放上传文件的临时地址。上传最终是从这个地址里的.tmp文件开始的。
struts.multipart.saveDir=/tmp
...
struts-action.xml
这里配置一些拦截属性,比如文件类型的限制,临时文件保存路径,文件大小的限制等等
<constant name="struts.multipart.saveDir" value="/tmp"></constant>
<constant name="struts.multipart.maxSize" value="1024102400"></constant>
<action name="upload" class="com.tom.hss.bss.action.UploadAction">
</action>
action内部的具体代码:处理文件
//必须的参数,参数名与表单file空间的name属性相同,如果一个表单名对应多个上传文件,
//则必须为数组或List
private File upFile;
//必须的参数,格式:表单file控件的name属性+ContentType,表示上传文件类型
private String upFileContentType;
//必须的参数,格式:表单file控件的name属性+FileName,表示上传的文件名
private String upFileFileName;
get/set......
//核心是copyFile方法,其他的是我自己的业务逻辑,不必在意。
public String fileUpload() throws IOException {
String type = ServletActionContext.getRequest().getParameter("type");
String temp_path=ServletActionContext.getServletContext().getRealPath("/upload");
String bss_path=ServletActionContext.getServletContext().getRealPath("/tmp");
String realpath = type.equals("")?temp_path:bss_path;
if (upFile != null) {
File savefile = new File(new File(realpath), upFileFileName);
System.out.println(realpath+File.separator+savefile.getName());
FileUtils.copyFile(upFile, savefile);
this.setSession(type.equals("")?"upload":type+"tmp",realpath+File.separator+savefile.getName());
System.out.println(savefile.getName());
ActionContext.getContext().put("message", "文件上传成功");
System.out.println("-"+type+"-");
PrintWriter writer = null;
writer=getResponse().getWriter();
writer.write("success");
}
return null;
}
copyFile是commons-io包下的方法:内部 实现如下:
private static void doCopyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException {
if(destFile.exists() && destFile.isDirectory()) {
throw new IOException("Destination \'" + destFile + "\' exists but is a directory");
} else {
FileInputStream input = new FileInputStream(srcFile);
try {
FileOutputStream output = new FileOutputStream(destFile);
try {
IOUtils.copy(input, output);
} finally {
IOUtils.closeQuietly(output);
}
} finally {
IOUtils.closeQuietly(input);
}
if(srcFile.length() != destFile.length()) {
throw new IOException("Failed to copy full contents from \'" + srcFile + "\' to \'" + destFile + "\'");
} else {
if(preserveFileDate) {
destFile.setLastModified(srcFile.lastModified());
}
}
}
}
copy内部:
public static long copyLarge(InputStream input, OutputStream output) throws IOException {
byte[] buffer = new byte[4096];
long count = 0L;
int n1;
for(boolean n = false; -1 != (n1 = input.read(buffer)); count += (long)n1) {
output.write(buffer, 0, n1);
}
return count;
}
由此可见,这里的copyfile本质上获得上传文件的输入,最后写到目标文件里。
struts2去年爆出了s2-032漏洞,安全性备受质疑,而且struts2也显得太重了,所以现在使用越来越少,之后会介绍springMVC下的文件上传!