一、单文件上传:
1:struts.xml文件配置如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <constant name="struts.enable.DynamicMethodInvocation" value="false" /> <constant name="struts.devMode" value="false" /> <constant name="struts.multipart.maxSize" value="2073741824" /> <package name="logsin" extends="struts-default"> <action name="upload" class="com.dingxun.upload.FileUploadAction" method="upload"> <interceptor-ref name="fileUpload"> <param name="allowedTypes"> image/bmp,image/png,image/gif,image/jpeg,image/jpg ,image/x-png, image/pjpeg </param> <param name="maximumSize">1048576</param> </interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> <param name="SavePath">/upload</param> <result name="success">/resultUpload.jsp</result> </action> </package> <!-- <include file="example.xml"/> --> </struts>
备注1:在action中添加<param name="SavePath">/upload</param>主要用来设定保存上传文件的路径,相对路径和绝对路径都可
备注2:上面那个拦截器可要可不要,因为限制上传文件大小和类型在拦截器里配置不能起作用,要用常量配置如下面的限制文件大小的
<constant name="struts.multipart.maxSize" value="2073741824" />上面的常量覆盖了default.properties里的设置
2:FileUploadAction代码如下:
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.commons.io.FileUtils; import org.apache.struts2.ServletActionContext; public class FileUploadAction { private final static int BUFFER_SIZE = 16 * 1024; private File upload; private String uploadFileName; private String uploadContentType; private String title; private String SavePath; private String ss; public String getSavePath() { return SavePath; } public void setSavePath(String savePath) { SavePath = savePath; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public File getUpload() { return upload; } public void setUpload(File 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; } /* * copy这个方法主要是用来实现文件上传的,实现的原理就是分别打开输入输出流,进行文件拷贝的 */ private void copy(File src, File dist) { InputStream in = null; BufferedOutputStream out = null; try { in = new BufferedInputStream(new FileInputStream(src), BUFFER_SIZE); out = new BufferedOutputStream(new FileOutputStream(dist),BUFFER_SIZE); byte[] buffer = new byte[BUFFER_SIZE]; int len = 0; try { while ((len=in.read(buffer)) > 0) { out.write(buffer, 0, len); } } catch (IOException e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); }finally{ if(null!=in){ try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if(null!=out){ try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } public String upload() { String distPath = ServletActionContext.getServletContext().getRealPath(getSavePath())+"//"+getUploadFileName(); System.out.println(distPath); File disFile = new File(distPath); System.out.println("文件类型: "+getUploadContentType()); // try { // FileUtils.copyFile(upload, disFile); // } catch (IOException e) { // e.printStackTrace(); // } copy(upload,disFile); return "success"; } }
备注:
1:ServletActionContext context = ServletActionContext.getServletContext();
2: ServletActionContext.getServletContext().getRealPath(getSavePath()) 得到上传文件目的文件夹的实际路径
3: ServletActionContext.getServletContext().getRealPath(getSavePath())+"//"+getUploadFileName() 一个文件的实际路径,这个主要是用来建立输出流
如 File disFile = new File(distPath)
OutputStream out = new BufferedOutputStream(new FileOutputStream(dist),BUFFER_SIZE);
4: 上传文件可以自己用io流拷贝文件,还可以用FileUtils.copyFile(file1,file2);
5:File的名字要和上传页面File域name属性的值一致如:upload 则FileUploadAction中的File的名字也应为upload (private File upload),除此之外还要添加以下两个属性:
private String uploadFileName 对应于上传文件的名字
private String uploadContentType 对应于上传文件的类型
以上两个属性的名字的命名必需以File的属性名开头,然后再加上FileName或ContentType如 uploadFileName 和 uploadContentType
3:jsp页面如下:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>struts2单文件上传页面</title> </head> <body> <form action="upload.action" method="post" enctype="multipart/form-data"> 标题:<input type="text" name="title"/><br> 请选选择:<input type="File" name="upload"/><br> <input type="submit" value="提交"/> </form> </body> </html>
二、多文件上传
1:多文件上传的struts.xml配置文件和单文件上传配置文件一样,这里就不再介绍了。
2:MultUploadAction如下:
import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class MultUploadAction extends ActionSupport { private File[] upload; private String[] uploadFileName; private String[] uploadContentType; private String savePath; public String getSavePath() { return savePath; } public void setSavePath(String savePath) { this.savePath = savePath; } public File[] getUpload() { return upload; } public void setUpload(File[] 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 execute(){ String realPath = ServletActionContext.getServletContext().getRealPath(savePath); for(int i=0;i<upload.length;i++){ File distFile = new File(realPath+"//"+uploadFileName[i]); try { FileUtils.copyFile(upload[i],distFile); } catch (IOException e) { e.printStackTrace(); } } return SUCCESS; } }
备注1: 多文件上传的实质的单文件上传一样,只不过多文件上传时文件,文件名,文件类型会保存到数组里面如:
private File[] upload;
private String[] uploadFileName;
private String[] uploadContentType;
有一点很重要,那就是upload[i] 和 uploadFileName[i] 和 uploadContentType[i] 相对应,理解这一点就好办了,利用循环针到单文件操作了
备注2: 这里用了第二种方法上传文件FileUtils.copyFile(file1,file2),自己写io流copy也可以
3:jsp页面如下:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Insert title here</title> </head> <body> <form action="multiupload.action" method="post" enctype="multipart/form-data"> 文件1<input type="File" name="upload"/><br> 文件2<input type="File" name="upload"/><br> 文件3<input type="File" name="upload"/><br> 文件4<input type="File" name="upload"/><br> <input type="submit" value="提交"/> </form> </body> </html>
总结:
1.文件上传的原理:
表单元素的enctype属性指定的是表单数据的编码方式,该属性有3个值:
1) application/x-www-form-urlencoded:这是默认编码方式,它只处理表单域里的value属性值,采用这种编码方式的表单会将表单域的值处理成URL编码方式。
2) multipart/form-data:这种编码方式的表单会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数里。
3) text/plain:这种方式主要适用于直接通过表单发送邮件的方式。
文件上传是web应用经常用到的一个知识。原理是,通过为表单元素设置enctype="multipart/form-data"属性,让表单提交的数据以二进制编码的方式提交。
在接收此请求的Servlet中用二进制流来获取内容,就可以取得上传文件的内容,从而实现文件的上传。
在Java领域中,有两个常用的文件上传项目:一个是Apache组织Jakarta的Common-FileUpload组件(http://commons.apache.org/fileupload/);
另一个是Oreilly组织的COS框架(http://www.servlets.com/cos/)。利用这两个框架都能很方便的实现文件的上传。
2. Struts2的文件上传:
Struts2并未提供自己的请求解析器,也就是就Struts2不会自己去处理multipart/form-data的请求,它需要调用其他请求解析器,将HTTP请求中的表单域解析出来。
但Struts2在原有的上传解析器基础上做了进一步封装,更进一步简化了文件上传。
Struts2默认使用的是Jakarta的Common-FileUpload框架来上传文件,因此,要在web应用中增加两个Jar文件:commons-fileupload-1.2.jar
和commons-io- 1.3.1.jar。它在原上传框架上做了进一步封装,简化了文件上传的代码实现,取消了不同上传框架上的编程差异。
如果要改成其它的文件上传框架,可以修改struts.multipart.parser常量的值为cos/pell,默认值是jakata。并在classpath中增加相应上传组件的类库。
3. 如果上传文件失败,系统返回到input对应的页面,要在input对应的页面输出文件过滤失败信息,可以在input对应的页面中增加 <s:fielderror/>来显示错误信息。
显然,这样的提示不太友好,应用使用国际化信息。在国际化资源文件中添加如下三句:
#更改上传文件类型不允许的提示信息
struts.messages.error.content.type.not.allowed=文件上传失败:你要上传的文件类型不允许
#更改上传文件太大的提示信息
struts.messages.error.file.too.large=文件上传失败:你要上传的文件太大
#文件上传其它错误信息
struts.messages.error.uploading=文件上传失败:发生内部错误
4.但是有一点要注意Struts2默认文件上传最大为2M即便你设置了<param name="maximumSize">5242880</param>
当上传的文件大于2M时候也会出错的这时要设置另外一个常量<constant name="struts.multipart.maxSize" value="1000000000"/>
要让他的value设置的比你限 定上传最大值要大一点。
5.有一点还要注意struts2提供了一个ServletActionContext.getServletContext().getResourceAsStream(filePath);方法根据路径返回输入流;但是
这个方法和servletContext有关,当你把下载的文件放在项目的根目录中才可以否则会出错的,最保险的办法就是根据文件路径找到这个文件然后在转化成输入流返回。