文件的上传


文件上传注意事项

  • 1.为保证服务器安全,上传文件应该放在外界无法直接访问你得目录下,比如放在WEB-INF目录下
  • 2.为防止文件覆盖现象的发生,要为文件产生一个唯一的文件名 (添加时间戳 或者 uuid 或者MD5 或者位运算)
  • 3.要限制上传文件的大小
  • 4.可以限制上传文件的类型,在收到上传文件名时,要判断后缀名是否合格。

需要用到的类详解

  • ServletFileUpload 负责处理上传的文件数据,并将表单中每个输入项封装成一个FileItem对象,在使用ServletFileUpload对象解析请求时,需要DiskFileItemFactory对象。所以,我们需要在进行解析工作前构造号DiskFileItemFactory对象,通过ServletFileUpload对象的构造方法,或setFileItemFactory()方法设置ServletFileUpload对象的fileItemFactory属性。

一,准备工作

1.导入依赖(两个jar包)

  1. <dependency>
  2. <groupId>commons-fileupload</groupId>
  3. <artifactId>commons-fileupload</artifactId>
  4. <version>1.4</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>commons-io</groupId>
  8. <artifactId>commons-io</artifactId>
  9. <version>2.6</version>
  10. </dependency>

2.前端页面核心代码

请求页面

  1. <%--通过表单上传文件
  2. get:上传文件大小有限制
  3. post:没限制
  4. --%>
  5. <%--必须在表单里增加属性
  6. enctype="multipart/form-data"
  7. --%>
  8. <%--
  9. ${pageContext.request.contextPath}
  10. 固定写法,获取服务器当前路径,不写这个只能在idea运行,服务器无法运行
  11. --%>
  12. <form action="${pageContext.request.contextPath}/upload.do" method="post" enctype="multipart/form-data">
  13. 上传用户:<input type="text" name="username"> <br>
  14. <p><input type="file" name="file1"></p>
  15. <p><input type="file" name="file1"></p>
  16. <p><input type="submit"> | <input type="reset"></p>
  17. </form>

注意

  • enctype:编码类型,multipart/form-data是指表单数据有多个部分组成,既有文件又有二进制数据组成。
  • GET:对上传文件大小有限制。
  • POST:对上传文件大小没有限制。
  • 必须在表单里增加属性
    • enctype=”multipart/form-data”
    • 在服务器端想获取数据就要通过流
  • ${pageContext.request.contextPath}

    • 固定写法,获取服务器当前路径,不写这个只能在idea运行,服务器无法运行

      常用方法介绍

  • boolean isFormField()

    • isFormField方法用于判断FileItem类对象封装的数据是一个普通文本表单(没有文件的表单)还是一个文件表单
    • 普通 返回true 否则false
  • String getFieldName()
    • 返回表单中name属性的值
  • String getString()
    • 将FileItem对象中保存的数据流内容以一个字符串返回
  • String getName()
    • 获得文件上传字段中的文件名
  • InputStream getInputStream()
    • 以流的形式返回上传文件的数据内容
  • void delete()
    • 用于清空FileItem类对象中存放的主体内容
    • 如果主体内容被保存在临时文件中,此方法将删除该临时文件3.web.xml配置映射Servlet

二,后端代码实现

  1. package com.dyq.servlet;
  2. import java.io.File;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.util.List;
  7. import java.util.UUID;
  8. import org.apache.commons.fileupload.FileItem;
  9. import org.apache.commons.fileupload.FileUploadException;
  10. import org.apache.commons.fileupload.ProgressListener;
  11. import org.apache.commons.fileupload.disk.DiskFileItemFactory;
  12. import org.apache.commons.fileupload.servlet.ServletFileUpload;
  13. import javax.servlet.ServletException;
  14. import javax.servlet.http.HttpServlet;
  15. import javax.servlet.http.HttpServletRequest;
  16. import javax.servlet.http.HttpServletResponse;
  17. public class FileServlet extends HttpServlet {
  18. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  19. //判断上传的文件是普通表单还是带文件的表单
  20. if(!ServletFileUpload.isMultipartContent(request)){
  21. return; //中止方法运行,说明这是一个普通表单,直接返回
  22. }//如果通过了这个if,说明我们的表单是带文件上传的
  23. //为保证服务器安全,上传文件应该放在外界无法直接访问你得目录下,比如放在WEB-INF目录下
  24. //创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访问上传文件
  25. String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
  26. File uploadFile = new File(uploadPath);
  27. if (!uploadFile.exists()){ //如果上传文件不存在
  28. uploadFile.mkdir();//创建这个目录
  29. }
  30. //缓存,临时文件
  31. //临时路径,假如文件超过了预期的大小,我们就把他放到一个临时文件中,过几天自动删除,或者提醒用户转为永久
  32. String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
  33. File file = new File(uploadPath); //设置临时文件为file
  34. if (!file.exists()){ //如果上传文件不存在
  35. file.mkdir();//创建这个目录
  36. }
  37. //处理上传的文件,一般都需要通过流来获取,我们可以使用request.getInputStream(),原生态的文件上传流获取,十分麻烦
  38. //但是我们都建议使用Apache的文件上传组件来实现,common-fileupload,他需要依赖于commons-IO组件
  39. try {
  40. // 1.创建DiskFileItemFactory对象,处理文件路径或者大小限制
  41. DiskFileItemFactory factory = getDiskFileItemFactory(file);
  42. /*
  43. * //通过这个工厂设置一个缓冲区,当上传的文件大于这个缓冲区的时候,将他放到临时文件 factory.setSizeThreshold(1024 *
  44. * 1024); //缓存区大小为1M factory.setRepository (file);//临时目录的保存目录,需要一个File
  45. */
  46. // 2、获取ServletFileUpload
  47. ServletFileUpload upload = getServletFileUpload(factory);
  48. // 3、处理上传文件
  49. // 把前端请求解析,封装成FileItem对象,需要从ServletFileUpload对象中获取
  50. String msg = uploadParseRequest(upload, request, uploadPath);
  51. // Servlet请求转发消息
  52. System.out.println(msg);
  53. if(msg == "文件上传成功!") {
  54. // Servlet请求转发消息
  55. request.setAttribute("msg",msg);
  56. request.getRequestDispatcher("info.jsp").forward(request, response);
  57. }else {
  58. msg ="请上传文件";
  59. request.setAttribute("msg",msg);
  60. request.getRequestDispatcher("info.jsp").forward(request, response);
  61. }
  62. } catch (FileUploadException e) {
  63. // TODO 自动生成的 catch 块
  64. e.printStackTrace();
  65. }
  66. }
  67. public static DiskFileItemFactory getDiskFileItemFactory(File file) {
  68. DiskFileItemFactory factory = new DiskFileItemFactory();
  69. // 通过这个工厂设置一个缓冲区,当上传的文件大于这个缓冲区的时候,将他放到临时文件中;
  70. factory.setSizeThreshold(1024 * 1024);// 缓冲区大小为1M
  71. factory.setRepository(file);// 临时目录的保存目录,需要一个file
  72. return factory;
  73. }
  74. public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
  75. ServletFileUpload upload = new ServletFileUpload(factory);
  76. // 监听长传进度
  77. upload.setProgressListener(new ProgressListener() {
  78. // pBYtesRead:已读取到的文件大小
  79. // pContextLength:文件大小
  80. public void update(long pBytesRead, long pContentLength, int pItems) {
  81. System.out.println("总大小:" + pContentLength + "已上传:" + pBytesRead);
  82. }
  83. });
  84. // 处理乱码问题
  85. upload.setHeaderEncoding("UTF-8");
  86. // 设置单个文件的最大值
  87. upload.setFileSizeMax(1024 * 1024 * 10);
  88. // 设置总共能够上传文件的大小
  89. // 1024 = 1kb * 1024 = 1M * 10 = 10м
  90. return upload;
  91. }
  92. public static String uploadParseRequest(ServletFileUpload upload, HttpServletRequest request, String uploadPath)
  93. throws FileUploadException, IOException {
  94. String msg = "";
  95. // 把前端请求解析,封装成FileItem对象
  96. List<FileItem> fileItems = upload.parseRequest(request);
  97. for (FileItem fileItem : fileItems) {
  98. if (fileItem.isFormField()) {// 判断上传的文件是普通的表单还是带文件的表单
  99. // getFieldName指的是前端表单控件的name;
  100. String name = fileItem.getFieldName();
  101. String value = fileItem.getString("UTF-8"); // 处理乱码
  102. System.out.println(name + ": " + value);
  103. } else {// 判断它是上传的文件
  104. // ============处理文件==============
  105. // 拿到文件名
  106. String uploadFileName = fileItem.getName();
  107. System.out.println("上传的文件名: " + uploadFileName);
  108. if (uploadFileName.trim().equals("") || uploadFileName == null) {
  109. continue;
  110. }
  111. // 获得上传的文件名/images/girl/paojie.png
  112. String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);
  113. // 获得文件的后缀名
  114. String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
  115. /*
  116. * 如果文件后缀名fileExtName不是我们所需要的 就直按return.不处理,告诉用户文件类型不对。
  117. */
  118. System.out.println("文件信息[件名: " + fileName + " ---文件类型" + fileExtName + "]");
  119. // 可以使用UID(唯一识别的通用码),保证文件名唯
  120. // 0UID. randomUUID(),随机生一个唯一识别的通用码;
  121. String uuidPath = UUID.randomUUID().toString();
  122. // ================处理文件完毕==============
  123. // 存到哪? uploadPath
  124. // 文件真实存在的路径realPath
  125. String realPath = uploadPath + "/" + uuidPath;
  126. // 给每个文件创建一个对应的文件夹
  127. File realPathFile = new File(realPath);
  128. if (!realPathFile.exists()) {
  129. realPathFile.mkdir();
  130. }
  131. // ==============存放地址完毕==============
  132. // 获得文件上传的流
  133. InputStream inputStream = fileItem.getInputStream();
  134. // 创建一个文件输出流
  135. // realPath =真实的文件夹;
  136. // 差了一个文件;加上翰出文件的名产"/"+uuidFileName
  137. FileOutputStream fos = new FileOutputStream(realPath + "/" + fileName);
  138. // 创建一个缓冲区
  139. byte[] buffer = new byte[1024 * 1024];
  140. // 判断是否读取完毕
  141. int len = 0;
  142. // 如果大于0说明还存在数据;
  143. while ((len = inputStream.read(buffer)) > 0) {
  144. fos.write(buffer, 0, len);
  145. }
  146. // 关闭流
  147. fos.close();
  148. inputStream.close();
  149. msg = "文件上传成功!";
  150. fileItem.delete(); // 上传成功,清除临时文件
  151. //=============文件传输完成=============
  152. }
  153. }
  154. return msg;
  155. }
  156. }

web.xml配置servlet路径

  1. <servlet>
  2. <servlet-name>FileServlet</servlet-name>
  3. <servlet-class>com.dyq.servlet.FileServlet</servlet-class>
  4. </servlet>
  5. <servlet-mapping>
  6. <servlet-name>FileServlet</servlet-name>
  7. <url-pattern>/upload.do</url-pattern>
  8. </servlet-mapping>

505解决

实例化servlet类[web.LoginServlet]异常

异常

Exception
javax.servlet.ServletException: 实例化Servlet类[web.RegisterServlet]异常

原因

Root Cause
java.lang.NoClassDefFoundError: org/apache/commons/dbutils/ResultSetHandler
Root Cause
java.lang.ClassNotFoundException:org.apache.commons.dbutils.ResultSetHandler
文件上传与下载 - 图1
错误显示dbutils下的…,但是我的jar包明明导入了,还是不行
文件上传与下载 - 图2
找了好些人问了一下这个问题,检查了代码没什么问题,最后找到是jar包没到好的原因。
这个工程下虽然导入了libs,也成功add as libray了,但Tomcat服务器不认账,还要再在导这里入导包。
文件上传与下载 - 图3
文件上传与下载 - 图4
右击book然后单击Put into /WEB_INF/lib,再重启Tomcat服务器即可。
into /WEB_INF/lib,再重启Tomcat服务器即可。