1.先给上传页面添加文件选择框标签。
[xhtml] view plaincopyprint? <%@ page language="java" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <%-- ================================================================= 【控制台报告的关于POST的信息】 当点击submit按钮时,在控制台中会弹出一下提示信息 Struts has detected a file upload UI tag (s:file) being used without a form set to method 'POST'. This is probably an error! 这是告诉我们当上传文件时,没有在<s:form/>中设定表单提交的method值为post 事实上Struts2的<s:form/>表单已经默认的将method值设为post了 如果我们讨厌这条信息的话,可以在<s:form/>中显式的指明method="POST"即可 ================================================================= 【上传文件时的报错信息的国际化】 展开struts2-core-2.0.11.jar中的org.apache.struts2包 打开包中的struts-messages.properties文件,在该文件中发现了以下两个键 struts.messages.error.file.too.large struts.messages.error.content.type.not.allowed 然后再查看它们的键值,接着再与文件上传时所提示的错误消息对比一下 这就为我们提供了给用户显示更为人性化错误信息的机会 也就是说程序在运行中所自动产生的各种提示信息,都不是它自己随便产生出来的 都是由Struts2在struts-messages.properties里面设置好的 还有一个struts.messages.error.uploading属性也是和文件上传有关的 比如在上传文件的过程中,突然网络中断,或者很多其它以外的情况 所以struts.messages.error.uploading用来统一处理其它上传错误提示信息的 ================================================================= --%> <script type="text/javascript"> function addMore(){ var td = document.getElementById("more"); var br = document.createElement("br"); var input = document.createElement("input"); var button = document.createElement("input"); input.type = "file"; input.name = "upfile"; button.type = "button"; button.value = "Remove"; button.onclick = function(){ td.removeChild(br); td.removeChild(input); td.removeChild(button); } td.appendChild(br); td.appendChild(input); td.appendChild(button); } </script> <%-- 上传出错时产生的错误信息也是被放到FieldError中的 所以就可以在页面中使用<s:fielderror/>输出错误消息 --%> <s:fielderror/> <s:form action="upload" theme="simple" enctype="multipart/form-data"> <table border="9"> <tr> <td>用户</td> <td><s:textfield name="username"/></td> </tr> <tr> <td>密码</td> <td><s:password name="password"/></td> </tr> <tr> <td>文件</td> <td id="more"><s:file name="upfile"/><input type="button" value="Add More.." onclick="addMore()"></td> </tr> <tr> <td> </td> <td><s:submit value="上传"/></td> </tr> </table> </s:form>
2.编写upLodeAction控制文件上传。
[java] view plaincopyprint? package com.jadyer.action; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; @SuppressWarnings("serial") public class UploadAction extends ActionSupport { private String username; private String password; private List<File> upfile; private List<String> upfileFileName; private List<String> upfileContentType; /* 五个属性相应的setter和getter方法略 */ @Override public String execute() throws Exception { for (int i = 0; i < upfile.size(); ++i) { //获得第i个文件的输入流 //这里一定要用字节流,不要用字符流。因为上传过来的东西不知道是字节还是字符 InputStream is = new FileInputStream(upfile.get(i)); //指定路径 String root = ServletActionContext.getRequest().getRealPath("/upload"); File destFile = new File(root, this.getUpfileFileName().get(i)); //获得文件输出流 OutputStream os = new FileOutputStream(destFile); //使用字节数组作为中间变量,完成输入到输出的转换 byte[] buffer = new byte[400]; int length = 0; while ((length = is.read(buffer)) > 0) { os.write(buffer, 0, length); } is.close(); os.close(); } return SUCCESS; } /******************【关于org.apache.commons.io.FileUtils.copyFile()方法】*****************************/ //我们这里从前台标签接收到的文件域数量不定,所以定义为private List<File> upfile //如果我们从前台表单接收到的文件域只有一个,可以定义为private File upfile //此时就可以利用org.apache.commons.io.FileUtils.copyFile()方法,代码如下 //public class UploadAction extends ActionSupport { // private String username; // private String password; // private File upfile; // private String upfileFileName; // private String upfileContentType; // /* 五个属性相应的setter和getter方法略 */ // @Override // public String execute() throws Exception { // String realpath = ServletActionContext.getServletContext().getRealPath("/upload"); // File file = new File(realpath); // if(!file.exists()){ // file.mkdirs(); // } // FileUtils.copyFile(upfile, new File(file, upfileFileName)); // return SUCCESS; // } //} /***************【文件上传的本质上就是IO操作】************************************************************/ //通过构造一个输入流,从upfile里面把文件的信息读到输入流里面去 //接着再把它写到一个输出流里面,这样就完成了文件的上传 /***************【Struts2的文件上传的实质】**************************************************************/ //Struts2虽然提供了文件上传的机制,但它并未实现文件上传底层的东西 //事实上Struts2是采用第三方的文件上传组件来帮助它完成上传的功能的 //它本身只是在更高层次上把它们封装了一下,以便于用户的开发和使用 //从这一点上来讲,Struts2跟Spring是非常类似的 //Spring的很多东西也是集成了第三方的东西,而它自己却并没有写多少 /***************【使用集合或数组实现多文件上传】***********************************************************/ //在Struts1中使用org.apache.struts.upload.FormFile类型来接收前台表单中的文件域 //在Struts2中使用java.io.File类型接收文件域,它的名字要与表单中的文件域的name值一致 //也可采用数组的方式声明upfile等等。实际从Struts2角度来看,它认为数组跟集合是没有区别的 //当它采用IOC的方式依赖注入的时候,它是同样对待数组和集合的,都是遍历其中的每一个元素 //不过还是建议大家采用集合加泛型的方式,这样可以使得程序更加简单,更加轻松明了 //而且,这里的三个集合中的元素的顺序都是一一对应的 //也就是说upfile集合的第一个文件对应upfileFileName集合的第一个名字,对应upfileContentType集合的第一个类型 //然后就可以很轻松的使用一个for循环读出全部的内容,然后写到系统的路径里面 //因此,我们就可以非常非常轻松的完成多文件上传的功能 /***************【定义文件上传所必备的三个属性】***********************************************************/ //文件在上传过来之后,必然会有它的相应的文件名和文件类型,然后在这里将它们接收过来 //Struts2中已为我们定义好了,它们前面的名字应与<s:file name=""/>的name值一致,后面分别跟FileName和ContentType //所以,upfileFileName属性就是用来表示上传过来的文件的名字,upfileContentType属性就表示上传的文件的类型 //这些东西都是Struts2框架自动为我们注入进来的,非常类似于Spring里面的依赖注入 /***************【FileName和ContentType的固定写法】*****************************************************/ //打开struts2-core-2.0.11.jar中的struts-default.xml文件,然后观察 //发现Struts2默认使用的拦截器defaultStack中包含了fileUpload拦截器 //然后我们到org.apache.struts2.interceptor.FileUploadInterceptor类中查看 //在FileUploadInterceptor类中定义了一些属性,通过这些属性就可以限制上传文件的大小或类型等等 //然后在FileUploadInterceptor类源码的第253和254和255行可以发现两行代码。如下所示 //parameters.put(inputName, files);-----------------------------第253行 //parameters.put(inputName + "ContentType", contentType);-------第254行 //parameters.put(inputName + "FileName", fileName);-------------第255行 //这里inputName就是上传过来的文件的名字,然后在它的后面加上固定的ContentType和FileName //关于文件上传,实际上我们只要知道在Action中应该定义三个必备的属性就可以了 //第一个属性就是upfile,它对应的是上传文件的文件体 //第二个属性就是upfileFileName,用来构造文件的名字 //第三个属性就是upfileContentType,用来构造文件的类型 /****************************************************************************************************/ }
3.配置Struts2的配置文件struts.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd"> <struts> <constant name="struts.multipart.saveDir" value="D:/"/> <package name="struts2.1" extends="struts-default"> <action name="upload" class="com.jadyer.action.UploadAction"> <result name="success">/result.jsp</result> <result name="input">/upload.jsp</result> <interceptor-ref name="fileUpload"> <param name="maximumSize">512000</param> <param name="allowedTypes">application/vnd.ms-powerpoint</param> </interceptor-ref> <interceptor-ref name="defaultStack"/> </action> </package> </struts>
4.配置 web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>upload.jsp</welcome-file> </welcome-file-list> </web-app>