这是一个Servlet应用。。
首先是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"> <servlet> <servlet-name>UploadServlet</servlet-name> <servlet-class>com.jadyer.servlet.FileUploadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UploadServlet</servlet-name> <url-pattern>/UploadServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>upload.jsp</welcome-file> </welcome-file-list> </web-app>
然后是用来选择所要上传的文件的upload.jsp页面
<%@ page language="java" pageEncoding="UTF-8"%> <%-- =================================================================================== 【上传文件时表单的method和enctype属性】 普通<form>表单的method属性默认为GET,enctype属性默认为application/x-www-form-urlencoded 但在上传文件时,表单method值必须是POST,enctype需要设置为multipart/form-data 并且enctype属性是通过表单上传文件必不可少的参数,上传文件时需将其显式设置为multipart/form-data 默认的application/x-www-form-urlencoded只是用来指明表单数据在提交时,是以字符串信息进行提交的 若未指定multipart/form-data值,将导致request.getParameter("file")只能获得包含路径的文件名 =================================================================================== --%> <form action="<%=request.getContextPath()%>/UploadServlet" method="POST" enctype="multipart/form-data"> <table border="9"> <tr> <td>username</td> <td><input type="text" name="username"></td> </tr> <tr> <td>password</td> <td><input type="password" name="password"></td> </tr> <tr> <td>File11</td> <td><input type="file" name="file11"></td> </tr> <tr> <td>File22</td> <td><input type="file" name="file22"></td> </tr> <tr> <td> </td> <td><input type="submit" name="submit" value="上传"></td> </tr> </table> </form>
接着是用来显示文件上传结果的result.jsp页面
<%@ page language="java" pageEncoding="UTF-8"%> <h3>请移步D:/Program Files/tomcat6/webapps/upload/uploadFile/查看所上传的文件</h3> <table border="9"> <tr> <td>uploadResult</td> <td>${requestScope['upload.message']}</td> </tr> <tr> <td>username</td> <td>${requestScope.username}</td> </tr> <tr> <td>password</td> <td>${requestScope.password}</td> </tr> <tr> <td>File11</td> <td>${requestScope.file11}</td> </tr> <tr> <td>File22</td> <td>${requestScope.file22}</td> </tr> </table>
最后是用来处理文件上传的核心Servlet
package com.jadyer.servlet; import java.io.File; import java.io.IOException; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; /** * 实现文件上传操作的Servlet * @author 玄玉 */ public class FileUploadServlet extends HttpServlet { private static final long serialVersionUID = 7291295547319094602L; public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); //虽然getRealPath()方法已经不赞同被使用了,但是它还是很好用的 //getRealPath("/uploadFile")指的就是WebRoot下的uploadFile目录 String path = request.getRealPath("/uploadFile"); // 创建工厂。然后再通过工厂来设置两个相关的属性 // Create a factory for disk-based file items // DiskFileItemFactory factory = new DiskFileItemFactory(yourMaxMemorySize, yourTempDirectory); DiskFileItemFactory factory = new DiskFileItemFactory(); // 设置小于1MB的文件就放到内存中,大于等于1MB则写到磁盘中 // Set yourMaxMemorySize factory.setSizeThreshold(1024 * 1024); // 设置临时存储目录 // Set yourTempDirectory factory.setRepository(new File(path)); // 通过工厂生成类的实例 // Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(factory); // 设置允许用户上传文件大小, 单位:字节 // Set overall request size constraint // factory.setSizeMax(yourMaxRequestSize); try { // parse是解析的意思,parseRequest也就是解析传过来的内容 // 调用ServletFileUpload类的parseRequest()方法获取所上传的所有文件和参数的集合 // Parse the request List<FileItem> list = upload.parseRequest(request); //遍历list对象中的每个FileItem对象,FileItem对象代表表单参数和所上传的文件 //然后判断它到底是不是File类型的 for (FileItem item : list) { // Process a regular form field if (item.isFormField()) { String name = item.getFieldName();//获得字段的名字 String value = item.getString("UTF-8");//使用指定编码获得字段的值 request.setAttribute(name, value);//用于在result.jsp页面中输出 } else { // Process a file upload // If you want to process a file upload in memory, you can use code as: byte[] data = item.get(); if (null!=item.getName() && !"".equals(item.getName())) { //通过FileItem对象的getName()方法所获取的是上传文件在客户端的包含后缀的完整名称 //并且FileItem对象的getSize()、getContentType()可以获取所上传的文件的大小和类型 System.out.println("上传文件的名称:" + item.getName()); System.out.println("上传文件的大小:" + item.getSize()); System.out.println("上传文件的类型:" + item.getContentType()); System.out.println("-------------------------------------------------"); String value = item.getName(); int start = value.lastIndexOf("//"); String fileName = value.substring(start + 1); //使用FileItem对象writer()方法完成最终的上传文件的保存 item.write(new File(path, fileName)); //用于在result.jsp中显示所上传的文件名称 String name = item.getFieldName(); request.setAttribute(name, fileName); request.setAttribute("upload.message", "文件上传成功"); }else{ request.setAttribute("upload.message", "没有选择上传文件"); } } } } catch (Exception ex) { ex.printStackTrace(); request.setAttribute("upload.message", "文件上传失败"); } request.getRequestDispatcher("result.jsp").forward(request,response); } } /***************【浅析DiskFileItemFactory类】**************************************************************/ //查看org.apache.commons.fileupload.disk.DiskFileItemFactory的API文档 //观察DiskFileItemFactory的名字,翻译过来就是磁盘文件条目的工厂,因此它肯定是跟磁盘的文件有关系的 //DiskFileItemFactory中有两个setter()方法,分别为setSizeThreshold()和setRepository()方法 /***************【浅析setSizeThreshold()方法】**************************************************************/ //在API文档中setSizeThreshold()的原形是public void setSizeThreshold(int sizeThreshold) //描述:Sets the size threshold beyond which files are written directly to disk //翻译:设定上传文件的最大体积。如果超出这个size的话,文件就被直接写到磁盘里面 //也就是说指定上传文件的体积。如果上传的文件小于这个体积,就直接把文件放到内存里面。如果超出这个体积的话,就把文件放到磁盘里面 /***************【浅析setRepository()方法】*****************************************************************/ //在API文档中setRepository()的原形是public void setRepository(java.io.File repository) //描述:Sets the directory used to temporarily store files that are larger than the configured size threshold //翻译:设置用来临时的存储文件的目录,而且存储的文件是比配置的threshold要大的文件 //也就是说setRepository()是用来设置临时目录的。一旦上传的文件超出了所设定的大小时,就把这个文件临时的存储到这个目录里面 /***************【浅析ServletFileUpload类】****************************************************************/ //最重要的就是org.apache.commons.fileupload.servlet.ServletFileUpload类,它是真正用来处理上传操作的 //在以前的版本中,使用的是org.apache.commons.fileupload.DiskFileUpload类进行上传的 //DiskFileUpload描述为:Deprecated.Use ServletFileUpload together with DiskFileItemFactory instead //翻译过来就是:使用ServletFileUpload和DiskFileItemFactory来代替DiskFileUpload //以前是不用工厂的,直接New出来DiskFileUpload的实例就可以了。但是现在就不要再使用DiskFileUpload类了 //ServletFileUpload类有一个这样的构造方法ServletFileUpload(FileItemFactory fileItemFactory)。它的描述如下 //Constructs an instance of this class which uses the supplied factory to create FileItem instances //这个构造方法使用的是FileItemFactory类型的参数。查看源码可知DiskFileItemFactory类实现了FileItemFactory //因此,在构建ServletFileUpload实例的时候,就可以使用DiskFileItemFactory作为构造方法的参数来生成实例 //这样就通过工厂生成了ServletFileUpload类的一个实例了 /***************【浅析parseRequest()方法】******************************************************************/ //在ServletFileUpload类中提供了一个parseRequest()方法,它的源代码如下所示 //-------------------------------------------------------------------------------------------------- //public List /* FileItem */ parseRequest(HttpServletRequest request) throws FileUploadException{ | // return parseRequest(new ServletRequestContext(request)); | //} | //-------------------------------------------------------------------------------------------------- //parseRequest()方法是真正完成上传的处理的,它是非常复杂的一个方法。它接收的是一个HttpServletRequest参数 //我们知道,客户端传过来的东西,都是在request中的。这里的parseRequest()就会解析request,得到java.util.list //这个List就封装了客户端传过来的表单里面的所有的参数,也包括File类型。它会将这些参数封装成一个集合,便于我们使用 //其中/* FileItem */用来说明所返回的List中都是FileItem类型的。为了兼容JDK1.4,所以它没有用泛型的方式来定义 //注意,一个FileItem对应的是表单中的一个字段,而并不仅仅是表单中的File类型的字段,也不是表单中所有字段的集合 /***************【浅析FileItem接口和它的isFormField()方法】***************************************************/ //通过查看org.apache.commons.fileupload.FileItem的API发现FileItem是一个接口 //但是我们不必关心它是由什么类来具体实现的,这就是面向接口编程的一个好处 //在FileItem接口中有一个boolean isFormField()方法,它的描述如下 //Determines whether or not a FileItem instance represents a simple form field //翻译过来就是:决定FileItem实例是否代表一个简单的表单字段 //表单字段只有两种,即File类型和非File类型。如果isFormField()返回TRUE则表明是非File的,返回FALSE则表明是File类型的 //所以通过isFormField()方法就可以很明确的判断出所提交的表单,到底是不是一个文件类型。通过该方法就可以将两种类型截然的分开 /***************【FileItem.getName()方法和上传同名文件的冲突问题】**********************************************/ //只有当item为File类型时,调用getName()方法才会返回真正的文件名字,如果是普通的表单类型的话,调用getName()就会返回null //另外,由于不同的浏览器解析文件地址的时候采取的方式不同,有的浏览器会自动在文件名的前面添加路径,而有的浏览器则只取得文件名 //所以就需要我们对获得的文件名进行手工截取,最后取得的只是文件的名字,而不包含路径,这样最后得到的FileName才是真正的文件名 //注意,这里对获取的文件名的处理非常重要 //为了避免不同用户上传相同文件而导致文件覆盖,我们可以在这里将FileName时间化,即在FileName前面加上new Date().getTime() //这样保存在服务器上的就是以时间毫秒数开头的文件了,避免了文件的同名现象 //另外也可以使用随机数,但是需要我们自己来设定随机算法,并且随机数在计算时,比较耗内存 //所以当前最常用的就是使用时间来标识上传的文件 /***************【直接调用FileItem接口的write()方法便可以替代以下操作】*****************************************/ //OutputStream os = new FileOutputStream(new File(path, fileName)); //InputStream is = item.getInputStream(); //byte[] buffer = new byte[400]; //int length = 0; //while ((length = is.read(buffer)) > 0) { // os.write(buffer, 0, length); //} //os.close(); //is.close(); /********************************************************************************************************/
当文件上传成功时,会保存在本地硬盘中
即LocalDisk//tomcat6//webapps//upload//uploadFile//文件夹中