JavaWeb 之文件的上传下载

时间:2022-05-15
本文章向大家介绍JavaWeb 之文件的上传下载,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

又到了每周更新博客的时候了,每看到自己发布的随笔阅读量上涨的时候就特别开心,我也会尽自己的努力提高自己的水平,总结出通俗易读的学习笔记,还望大家能多多支持!!!

--------------------------------------------------------------------------------------------------------------

文件的上传

- 设置表单请求方式为 post

- 设置表单类型为 file

- 设置编码方式  enctype=”multipart/form-data”

- 使用 fileUploadio 组件完成文件的上传操作

Jquery 实现添加多文件上传组件

- 功能演示

- 每次点击 createNew 添加一个新的上传组件,并为之生成最新的索引

- 点击删除按钮删删除当前组件并将其余的组件按照从小到大的顺序排列

- 实现代码

 1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 2 <html>
 3 <head>
 4     <title>FileUpload</title>
 5     <script type="text/javascript" src="jquery-1.7.2.js"></script>
 6     <script type="text/javascript">
 7         $(function () {
 8 //            定义变量 i,使其每次点击事件自增,达到动态增加目的
 9             var i = 2;
10 //            给 createNew 添加点击事件
11             $("#createNew").click(function () {
12 //                this 表示 button,第一层 parent 表示 td 第二层 parent 表示 tr,然后在其前面加入两个 tr,并为所有 tr 添加 class 属性
13                 $(this).parent().parent().before("<tr class='file'><td>File" + i + "</td><td><input type='file'name='file " + i + " '></td></tr>" +
14                     "<tr class='desc'><td>Desc" + i + "</td><td><input type='text' name='desc" + i + "'><button id='delete" + i + "'>删除</button></td></tr>");
15 //                每次添加之后是 i 加 1
16                 i++;
17 //                点击删除的事件
18                 $("#delete" + (i - 1)).click(function () {
19 //                    将 tr 保存到变量中,方便对前一个 tr(文件表单所对应的 tr) 的删除
20                     var $tr = $(this).parent().parent();
21 //                    删除前一个 tr
22                     $tr.prev().remove();
23                     $tr.remove();
24 //                    找到所有 class 为 file 的第一个 td,然后对其遍历,并将参数传入遍历的函数中
25                     $(".file").find("td:first").each(function (index) {
26                         var n = index + 1;
27 //                        将 td 的文本改变,达到对 td 的重新排序
28                         $(this).text("File" + n);
29 //                        将 input 的 name 属性改变
30                         $(this).parent().find("td:last").find("input").attr("name", "file" + n);
31                     });
32                     $(".desc").find("td:first").each(function (index) {
33                         var n = index + 1;
34                         $(this).text("Desc" + n);
35                         $(this).parent().find("td:last").find("input").attr("name", "desc" + n);
36                     });
37                 });
38                 return false;
39             });
40         });
41     </script>
42 </head>
43 <body>
44 <h3>${requestScope.message}</h3>
45 <form action="${pageContext.request.contextPath}/realUploadServlet" method="post" enctype="multipart/form-data">
46     <table cellspacing="10" cellpadding="0">
47 
48         <tr class="file">
49             <td>File1</td>
50             <td><input type="file" name="file1"></td>
51         </tr>
52         <tr class="desc">
53             <td>Desc1</td>
54             <td><input type="text" name="desc1"></td>
55         </tr>
56         <tr>
57             <td>
58                 <button type="submit">Submit</button>
59             </td>
60             <td>
61                 <button type="submit" id="createNew">CreateNew</button>
62             </td>
63         </tr>
64     </table>
65 </body>
66 </html>

数据库设计 -- files 表

 - 表结构

DAO、doMain 类设计

 1 package com.javaweb.file.servlet.database.dao;
 2 
 3 import com.mchange.v2.c3p0.ComboPooledDataSource;
 4 
 5 import javax.sql.DataSource;
 6 import java.sql.Connection;
 7 import java.sql.SQLException;
 8 
 9 /**
10  * Created by shkstart on 2017/12/02.
11  */
12 public class JDBCTools {
13 
14     private static DataSource dataSource;
15 
16     static {
17         dataSource = new ComboPooledDataSource("uploadFile");
18     }
19 
20     public static Connection getConnection() {
21         Connection connection = null;
22 
23         try {
24             connection = dataSource.getConnection();
25         } catch (SQLException e) {
26             e.printStackTrace();
27         }
28 
29         return connection;
30     }
31 
32     public static void releaseConnection(Connection connection) {
33         try {
34             connection.close();
35         } catch (SQLException e) {
36             e.printStackTrace();
37         }
38     }
39 }
 1 package com.javaweb.file.servlet.database.dao;
 2 
 3 import org.apache.commons.dbutils.QueryRunner;
 4 import org.apache.commons.dbutils.handlers.BeanListHandler;
 5 
 6 import java.lang.reflect.ParameterizedType;
 7 import java.lang.reflect.Type;
 8 import java.sql.Connection;
 9 import java.sql.SQLException;
10 import java.util.List;
11 
12 /**
13  * Created by shkstart on 2017/12/02.
14  */
15 public class DAO<T> {
16 
17     private static QueryRunner queryRunner;
18     private Class<T> type;
19 
20 
21     public DAO() {
22         queryRunner = new QueryRunner();
23 
24         Type superclass = getClass().getGenericSuperclass();
25         if (superclass instanceof  ParameterizedType) {
26             ParameterizedType parameterizedType = (ParameterizedType) superclass;
27 
28             Type[] args = parameterizedType.getActualTypeArguments();
29             if (args != null && args.length > 0) {
30                 if (args[0] instanceof Class) {
31                     type = (Class<T>) args[0];
32                 }
33             }
34         }
35     }
36 
37     public void update(String sql, Object...args) {
38         Connection connection = JDBCTools.getConnection();
39         System.out.println(queryRunner);
40         try {
41             queryRunner.update(connection, sql, args);
42         } catch (SQLException e) {
43             e.printStackTrace();
44         } finally {
45             JDBCTools.releaseConnection(connection);
46         }
47     }
48 
49     public List<T> getAll(String sql) {
50         Connection connection = JDBCTools.getConnection();
51         List<T> fileList = null;
52         try {
53             fileList = queryRunner.query(connection, sql, new BeanListHandler<T>(type));
54         } catch (SQLException e) {
55             e.printStackTrace();
56         }
57         return fileList;
58     }

- c3p0 配置文件

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <c3p0-config>
 3     <named-config name="uploadFile">
 4         <property name="user">root</property>
 5         <property name="password">zy961029</property>
 6         <property name="driverClass">com.mysql.jdbc.Driver</property>
 7         <property name="jdbcUrl">jdbc:mysql:///sh_db</property>
 8 
 9         <property name="maxStatements">1</property>
10         <property name="maxStatementsPerConnection">5</property>
11     </named-config>
12 </c3p0-config>

- 依据数据表新建 Files 类

 1 package com.javaweb.file.servlet.file.bean;
 2 
 3 /**
 4  * Created by shkstart on 2017/12/02.
 5  */
 6 public class Files {
 7     private Integer id;
 8     private String fileName;
 9     private String filePath;
10     private String fileDesc;
11 
12     public Files() {
13 
14     }
15 
16     @Override
17     public String toString() {
18         return "Files{" +
19                 ", fileName='" + fileName + ''' +
20                 ", filePath='" + filePath + ''' +
21                 ", fileDesc='" + fileDesc + ''' +
22                 '}';
23     }
24 
25     public Files(String fileName, String filePath, String fileDesc) {
26         this.fileName = fileName;
27         this.filePath = filePath;
28         this.fileDesc = fileDesc;
29     }
30 
31     public Integer getId() {
32         return id;
33     }
34 
35     public void setId(Integer id) {
36         this.id = id;
37     }
38 
39     public String getFileName() {
40         return fileName;
41     }
42 
43     public void setFileName(String fileName) {
44         this.fileName = fileName;
45     }
46 
47     public String getFilePath() {
48         return filePath;
49     }
50 
51     public void setFilePath(String filePath) {
52         this.filePath = filePath;
53     }
54 
55     public String getFileDesc() {
56         return fileDesc;
57     }
58 
59     public void setFileDesc(String fileDesc) {
60         this.fileDesc = fileDesc;
61     }
62 }

- 依据文件上传功能的要求新建 files 表对应的接口(实现文件上传需要插入数据表即 update,实现文件下载需要获取数据表数据即 getAll())

 1 package com.javaweb.file.servlet.database.dao;
 2 
 3 import com.javaweb.file.servlet.file.bean.Files;
 4 
 5 import java.util.List;
 6 
 7 /**
 8  * Created by shkstart on 2017/12/02.
 9  */
10 public interface FilesDao {
11     void update(Files files);
12     List<Files> getAll();
13 }

- 使用 DAO 类实现 FilesDao 接口

 1 package com.javaweb.file.servlet.daoImpl;
 2 
 3 import com.javaweb.file.servlet.database.dao.DAO;
 4 import com.javaweb.file.servlet.database.dao.FilesDao;
 5 import com.javaweb.file.servlet.file.bean.Files;
 6 
 7 import java.util.List;
 8 
 9 /**
10  * Created by shkstart on 2017/12/02.
11  */
12 public class FilesDaoImpl extends DAO<Files> implements FilesDao {
13     @Override
14     public void update(Files files) {
15         String sql = "INSERT INTO files (file_name, file_path, file_desc) VALUES(?, ?, ?)";
16         update(sql, files.getFileName(), files.getFilePath(), files.getFileDesc());
17     }
18 
19     @Override
20     public List<Files> getAll() {
21         String sql = "SELECT file_name fileName, file_path filePath, file_desc fileDesc FROM files";
22         List<Files> filesList = getAll(sql);
23         return filesList;
24     }
25 }

配置上传文件的需求,并在 ContextListener 监听器中初始化(文件大小、文件类型等限制)

- 新建一个单例的属性控制器,在监听器中调用该类的方法添加属性,以及在 Servlet 中调用该类方法获取属性

 1 package com.javaweb.file.servlet.property.data;
 2 
 3 import java.util.HashMap;
 4 import java.util.Map;
 5 
 6 /**
 7  * 该类为单例设计模式
 8  */
 9 public class PropertiesControl {
10 //    存储所配置的属性
11     private Map<String, String> properties = new HashMap<String, String>();
12 //    将该类编写为单例的
13     private PropertiesControl() {}
14 
15     private static PropertiesControl instance = new PropertiesControl();
16 
17     public static PropertiesControl getInstance() {
18         return instance;
19     }
20 //    添加属性到 map 的方法
21     public void addPorperty(String propertyName, String propertyValue) {
22         properties.put(propertyName, propertyValue);
23     }
24 //    获取属性的方法
25     public String getProperty(String propertyName) {
26         return properties.get(propertyName);
27     }
28 }

- 监听器类(初始化所有属性)

 1 package com.javaweb.file.servlet.properties.listener; /**
 2  * Created by shkstart on 2017/11/30.
 3  */
 4 
 5 import com.javaweb.file.servlet.property.data.PropertiesControl;
 6 
 7 import javax.servlet.ServletContextEvent;
 8 import javax.servlet.ServletContextListener;
 9 import java.io.IOException;
10 import java.io.InputStream;
11 import java.util.Map;
12 import java.util.Properties;
13 
14 public class PropertiesListener implements ServletContextListener{
15 
16 //    利用 ContextListener 读取属性并初始化
17 //    我没想到用监听器,想到的是 web 应用的初始化参数,和 servlet 的 init 方法
18     @Override
19     public void contextInitialized(ServletContextEvent servletContextEvent) {
20 //        读取配置文件
21         InputStream inputStream = getClass().getClassLoader().getResourceAsStream("/upload.properties");
22         Properties properties = new Properties();
23         try {
24 //            加载输入流(文件)
25             properties.load(inputStream);
26 //            遍历属性集合
27             for (Map.Entry<Object, Object> entry : properties.entrySet()) {
28 //                获取属性名和属性值
29                 String propertyName = (String) entry.getKey();
30                 String propertyValue = (String) entry.getValue();
31 //                添加属性到 PropertyControl 类
32                 PropertiesControl.getInstance().addPorperty(propertyName, propertyValue);
33             }
34         } catch (IOException e) {
35             e.printStackTrace();
36         }
37     }
38 
39     @Override
40     public void contextDestroyed(ServletContextEvent servletContextEvent) {
41 
42     }
43 }

- 配置文件

1 #文件总大小为 200M
2 sizeMax=209715200
3 #单个文件大小为 10M
4 sizeSingle=10485760
5 #允许的文件后缀
6 nameOfEnd=.md,.png,.jpg,.zip

文件上传实现代码(核心Servlet

- 使用 fileUpload 组件上传文件其具体细节可查看其自带的官方文档,这里直接贴出代码(含有详细注释)

  1 package com.javaweb.file.servlet.test.servlet;
  2 
  3 import com.javaweb.file.servlet.daoImpl.FilesDaoImpl;
  4 import com.javaweb.file.servlet.database.dao.FilesDao;
  5 import com.javaweb.file.servlet.file.bean.Files;
  6 import com.javaweb.file.servlet.helloServlet.DeleteFile;
  7 import com.javaweb.file.servlet.project.exname.exception.ExNameException;
  8 import com.javaweb.file.servlet.property.data.PropertiesControl;
  9 import org.apache.commons.fileupload.FileItem;
 10 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
 11 import org.apache.commons.fileupload.servlet.ServletFileUpload;
 12 
 13 import javax.servlet.ServletException;
 14 import javax.servlet.http.HttpServlet;
 15 import javax.servlet.http.HttpServletRequest;
 16 import javax.servlet.http.HttpServletResponse;
 17 import java.io.*;
 18 import java.util.*;
 19 
 20 /**
 21  * Created by shkstart on 2017/11/30.
 22  */
 23 public class UploadServlet extends HttpServlet {
 24 //    设置要把文件保存到的虚拟路径,可获得其真实路径
 25     private static final String REAL_PATH = "/WEB-INF";
 26     private HttpServletRequest request;
 27 //    设置的临时文件夹
 28     private static final String TEMP_DIR = "D:/io";
 29 
 30     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 31         this.request = request;
 32 
 33 //        获取 ServletFileUpload
 34         ServletFileUpload upload = getServletFileUpload();
 35 //        
 36         String path = request.getContextPath() + "/uploadFileTest/success.jsp";
 37         try {
 38 //            此 Map 的键为需要上传文件的路径加文件名,值为可获取对应的输入流
 39             Map<String, FileItem> uploadFile = new HashMap<String, FileItem>();
 40 //            获取所有提交的表单域和文件域
 41             List<FileItem> items = upload.parseRequest(request);
 42 //            构建 FileUploadBean,和需要上传文件的 Map 集合
 43             List<Files> beans = buildFileUploadBeans(items, uploadFile);
 44 //            校验扩展名
 45             validateExName(beans);
 46 //            上传文件操作
 47             upload(uploadFile);
 48 //            保存到数据库
 49             save(beans);
 50 //            清空临时文件夹
 51             DeleteFile.deleteFiles(TEMP_DIR);
 52         } catch (Exception e) {
 53             e.printStackTrace();
 54 //            若发生异常转发回原页面,并提示错误消息(在这可以抓取后缀名不合法的异常,并返回页面报错)
 55             path = "/upload.jsp";
 56             request.setAttribute("message", e.getMessage());
 57             request.getRequestDispatcher(path).forward(request, response);
 58         }
 59 //        若没有异常则重定向到文件上传成功目录
 60         response.sendRedirect(path);
 61     }
 62 //    执行数据库保存操作
 63     private void save(List<Files> beans) {
 64         for (Files file : beans) {
 65             FilesDao fileDao = new FilesDaoImpl();
 66 //            执行插入操作
 67             fileDao.update(file);
 68         }
 69     }
 70 //    遍历所传入的 Map 集合获得文件路径和可获得输入流的 item 对象
 71     private void upload(Map<String, FileItem> uploadFile) {
 72         for (Map.Entry<String, FileItem> entry : uploadFile.entrySet()) {
 73             String filePath = entry.getKey();
 74             FileItem item  = entry.getValue();
 75             uploadFile(filePath, item);
 76         }
 77     }
 78 //    进行文件上传操作(IO 操作)
 79     private void uploadFile(String filePath, FileItem item) {
 80         try {
 81             int len;
 82             byte[] buffer = new byte[1024];
 83             InputStream inputStream = item.getInputStream();
 84             BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
 85             OutputStream outputStream = new FileOutputStream(filePath);
 86             BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
 87 
 88             while ((len = bufferedInputStream.read(buffer)) != -1) {
 89                 bufferedOutputStream.write(buffer, 0, len);
 90             }
 91             bufferedOutputStream.close();
 92             bufferedInputStream.close();
 93         } catch (IOException e) {
 94             e.printStackTrace();
 95         }
 96     }
 97 //    校验文件后缀名
 98     private void validateExName(List<Files> beans) {
 99 //        允许的后缀名
100         String nameOfEnd = PropertiesControl.getInstance().getProperty("nameOfEnd");
101 //        将配置的文件名分开,并存为一个 list
102         List<String> legalExName = Arrays.asList(nameOfEnd.split(","));
103 //        遍历将要上传的文件的后缀名
104         for (Files bean : beans) {
105 //            获得当前文件的后缀名
106             String exName = getExName(bean.getFileName());
107 //            如果后缀名不合法那么就抛出自定义异常,并转发到页面打印错误消息
108             if (!legalExName.contains(exName)) {
109 //                若不是允许的后缀名则抛出自建异常,并提示错误消息
110                 throw new ExNameException("不允许上传后缀名为" + exName + "的文件");
111             }
112         }
113     }
114 //    根据传入的文件名获得文件的后缀名
115     private String getExName(String fileName) {
116 //        获得 . 对应的下标
117         int numOfPoint = fileName.lastIndexOf(".");
118 //        返回文件后缀名
119         return fileName.substring(numOfPoint, fileName.length());
120     }
121 
122     //    构建 FileUploadBean 集合
123     private List<Files> buildFileUploadBeans(List<FileItem> items, Map<String, FileItem> uploadFile) {
124 //        需要返回的 FileUploadBean 集合
125         List<Files> beans = new ArrayList<Files>();
126 //        初始化 filePath
127         String filePath = null;
128 //        将表单域和文件域分开存储,便于比较并对 FileUpload 赋值
129         List<FileItem> itemDesc = new ArrayList<FileItem>();
130         List<FileItem> itemFile = new ArrayList<FileItem>();
131 
132 //        分别为表单集合和文件集合赋值
133         for (FileItem item : items) {
134             if (item.isFormField()) {
135 //                为表单集合赋值
136                 itemDesc.add(item);
137             }
138 //            判断 item 对象是否为文件域
139             if (!item.isFormField()) {
140 //                为文件集合赋值
141                 itemFile.add(item);
142             }
143         }
144         for (FileItem item1 : itemDesc) {
145 //            获得表单前面显示文本,如 desc1
146             String fieldName1 = item1.getFieldName();
147 //            获得表单前面显示文本得最后一位数字,如 1
148             String descNum = fieldName1.substring(fieldName1.length() - 1, fieldName1.length());
149 //            新建数据表对应的 Files 对象,在后面经过比较后为其初始化
150             Files bean = null;
151 //            遍历两个集合找出相匹配的文本域
152             for (FileItem item2 : itemFile) {
153 //                获得表单前面显示文本,如 file1
154                 String fieldName2 = item2.getFieldName();
155 //                获得表单前面显示文本的最后一位,如 1
156                 String fileNum = fieldName2.substring(fieldName2.length() - 1, fieldName2.length());
157 //                如果获得的数字一样,那么就表示他们两个是一组上传组件
158                 if (descNum.equals(fileNum)) {
159 //                    利用文件 item 对象构建完整的存放路径,获取后缀名
160                     String exName = getExName(item2.getName());
161 //                    利用随机数加系统时间构建文件名,以及真实路径
162                     filePath = gteFilePath(exName);
163 //                    初始化 bean
164                     String desc = null;
165                     try {
166 //                        使用过滤器不能彻底解决乱码问题,在过滤器的基础上获取参数值的过程中传入编码参数
167                         desc = item1.getString("UTF-8");
168                     } catch (UnsupportedEncodingException e) {
169                         e.printStackTrace();
170                     }
171 //                    经过比较初始化 bean 对象
172                     bean = new Files(item2.getName(), filePath, desc);
173                 }
174 //                初始化 Map 对象
175                 uploadFile.put(filePath, item2);
176             }
177 //            将所有的 files 对象加入 list 集合中
178             beans.add(bean);
179         }
180         return beans;
181     }
182 
183 //    构建 filePath
184     private String gteFilePath(String exName) {
185 //        生成随机数
186         Random random = new Random();
187 //        获得所提供虚拟路径的真实路径,并构建上传文件所需的地址 + 文件名(更改原文件名为随机的,即为随机数加上系统时间)
188         String filePath = getServletContext().getRealPath(REAL_PATH) + "\" + System.currentTimeMillis() + random.nextInt(100000) + exName;
189         return filePath;
190     }
191 
192     private ServletFileUpload getServletFileUpload() {
193 //        文件总大小的限制(获取监听器初始化的属性配置)
194         String sizeMax = PropertiesControl.getInstance().getProperty("sizeMax");
195 //        单个文件大小限制
196         String sizeSingle = PropertiesControl.getInstance().getProperty("sizeSingle");
197 //        获取 FileItem 集合对象
198         DiskFileItemFactory factory = new DiskFileItemFactory();
199 //        设置临时文件夹(当文件大小超过设置的大小就先将文件存储在临时文件下,以提高效率)
200         factory.setRepository(new File(TEMP_DIR));
201 //        设置使用临时文件夹的阀值 5M
202         factory.setSizeThreshold(1024 * 1024 * 5);
203 //        获得 ServletFileUpload 对象
204         ServletFileUpload upload = new ServletFileUpload(factory);
205 //        设置总文件大小限制
206         upload.setSizeMax(Long.parseLong(sizeMax));
207 //        设置单个文件大小限制
208         upload.setFileSizeMax(Long.parseLong(sizeSingle));
209         return upload;
210     }
211 
212     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
213         doPost(request, response);
214     }
215 }

- 清空临时文件夹的操作类

 1 package com.javaweb.file.servlet.helloServlet;
 2 
 3 import java.io.File;
 4 
 5 /**
 6  * Created by shkstart on 2017/12/01.
 7  */
 8 public class DeleteFile {
 9 
10     public static void deleteFiles(String filePath) {
11 //        根据所传路径新建 File 对象
12         File file = new File(filePath);
13 //        获得所有的文件集合
14         File[] files = file.listFiles();
15 //        遍历文件和目录集合
16         for (File file1 : files) {
17 //            如果碰到文件直接删除
18             if (file1.isFile()) {
19                 file1.delete();
20             }
21 //            如果碰到目录,先删除所有文件
22             if (file1.isDirectory()) {
23 //                递归调用,删除目录中所有的文件
24                 deleteFiles(filePath + "/" + file1.getName());
25 //                调用方法删除空目录
26                 deleteDir(filePath + "/" + file1.getName());
27             }
28         }
29     }
30 
31     private static void deleteDir(String filePath) {
32 //        因为目录为空,所以新建 File 对象为空目录,直接删除
33         File file = new File(filePath);
34         file.delete();
35     }
36 }

- 过滤器操作

 1 package com.javaweb.file.servlet.encode.filter;
 2 
 3 import javax.servlet.*;
 4 import javax.servlet.http.HttpServletRequest;
 5 import java.io.IOException;
 6 
 7 /**
 8  * Created by shkstart on 2017/12/01.
 9  */
10 public class EncodeFilter implements Filter {
11     public void destroy() {
12     }
13 
14     public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
15         req.setCharacterEncoding("UTF-8");
16         chain.doFilter(req, resp);
17     }
18 
19     public void init(FilterConfig config) throws ServletException {
20 
21     }
22 }

- 上传成功页面

1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
2 <html>
3 <head>
4     <title>SuccessPage</title>
5 </head>
6 <body>
7   <h3>上传成功!<a href="${pageContext.request.contextPath}/index.jsp">返回</a></h3>
8 </body>
9 </html>

文件下载

- 点击文件下载超链接到 Servlet 中查询数据库获取所有已上传的文件,封装到 request 中转发回显示页面,提供下载操作

- DownloadServlet

 1 package com.javaweb.file.servlet.test.servlet;
 2 
 3 import com.javaweb.file.servlet.daoImpl.FilesDaoImpl;
 4 import com.javaweb.file.servlet.database.dao.FilesDao;
 5 import com.javaweb.file.servlet.file.bean.Files;
 6 import com.sun.corba.se.spi.orbutil.fsm.Input;
 7 
 8 import javax.servlet.ServletException;
 9 import javax.servlet.http.HttpServlet;
10 import javax.servlet.http.HttpServletRequest;
11 import javax.servlet.http.HttpServletResponse;
12 import java.io.*;
13 import java.lang.reflect.InvocationTargetException;
14 import java.lang.reflect.Method;
15 import java.net.URLEncoder;
16 import java.util.List;
17 
18 /**
19  * Created by shkstart on 2017/12/02.
20  */
21 public class DownloadServlet extends HttpServlet {
22     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
23         String servletPath = request.getServletPath();
24         String methodName = servletPath.substring(1, servletPath.length() - 3);
25         try {
26             Method method = getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
27             method.invoke(this, request, response);
28         } catch (NoSuchMethodException e) {
29             e.printStackTrace();
30         } catch (IllegalAccessException e) {
31             e.printStackTrace();
32         } catch (InvocationTargetException e) {
33             e.printStackTrace();
34         }
35     }
36 
37     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
38         doPost(request, response);
39     }
40 
41     protected void show(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
42         FilesDao filesDao = new FilesDaoImpl();
43 //        查询数据库,将所有数据封装到 list 中
44         List<Files> filesList = filesDao.getAll();
45 //        将list 封装在 request 域中传回页面
46         request.setAttribute("filesList", filesList);
47         request.getRequestDispatcher("/download.jsp").forward(request, response);
48     }
49 
50 //    纯 IO 操作
51     protected void download(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
52 //        根据请求参数获取文件名
53         String fileName = request.getParameter("fileName");
54 //        根据请求参数获取文件路径
55         String filePath = request.getParameter("filePath");
56 //        获取文件响应类型,通知浏览器这是一个需要下载的文件,以及应该将该处理交由用户处理
57         response.setContentType("multipart/form-data");
58         response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
59 //        获取输出流
60         OutputStream outputStream = response.getOutputStream();
61 //        获取输入流
62         InputStream inputStream = new FileInputStream(filePath);
63 
64 //        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
65 //        BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
66 
67         int len;
68         byte[] buffer = new byte[1024];
69 
70         while ((len = inputStream.read()) != -1) {
71             outputStream.write(buffer, 0, len);
72         }
73 
74 //        bufferedOutputStream.close();
75 //        bufferedInputStream.close();
76         inputStream.close();
77     }
78 }

- 在首页点击下载后,请求到 Servlet 中执行 show 方法,并将请求转发到显示页面(download.jsp),如下

 1 <%--
 2   Created by IntelliJ IDEA.
 3   User: yin‘zhao
 4   Date: 2017/12/02
 5   Time: 13:28
 6   To change this template use File | Settings | File Templates.
 7 --%>
 8 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 9 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
10 <html>
11 <head>
12     <title>DownloadPage</title>
13 </head>
14 <body>
15 <h3>
16     <c:forEach items="${requestScope.filesList}" var="file">
17         FileName: ${file.fileName}<br><br>
18         FileDesc: ${file.fileDesc}<br><br>
19         <a href="download.do?fileName=${file.fileName}&filePath=${file.filePath}">Download</a><br><br>
20         <hr><br>
21     </c:forEach>
22 </h3>
23 </body>
24 </html>

- 该案例的 web.xml 文件

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
 5          version="3.1">
 6     <filter>
 7         <filter-name>EncodeFilter</filter-name>
 8         <filter-class>com.javaweb.file.servlet.encode.filter.EncodeFilter</filter-class>
 9     </filter>
10     <filter-mapping>
11         <filter-name>EncodeFilter</filter-name>
12         <url-pattern>/*</url-pattern>
13     </filter-mapping>
14     <listener>
15         <listener-class>com.javaweb.file.servlet.properties.listener.PropertiesListener</listener-class>
16     </listener>
17     <servlet>
18         <servlet-name>FileUploadServlet</servlet-name>
19         <servlet-class>com.javaweb.file.servlet.helloServlet.FileUploadServlet</servlet-class>
20     </servlet>
21     <servlet>
22         <servlet-name>UploadServlet</servlet-name>
23         <servlet-class>com.javaweb.file.servlet.test.servlet.UploadServlet</servlet-class>
24     </servlet>
25     <servlet>
26         <servlet-name>DownloadServlet</servlet-name>
27         <servlet-class>com.javaweb.file.servlet.test.servlet.DownloadServlet</servlet-class>
28     </servlet>
29     <servlet-mapping>
30         <servlet-name>DownloadServlet</servlet-name>
31         <url-pattern>*.do</url-pattern>
32     </servlet-mapping>
33     <servlet-mapping>
34         <servlet-name>UploadServlet</servlet-name>
35         <url-pattern>/realUploadServlet</url-pattern>
36     </servlet-mapping>
37     <servlet-mapping>
38         <servlet-name>FileUploadServlet</servlet-name>
39         <url-pattern>/uploadServlet</url-pattern>
40     </servlet-mapping>
41 </web-app>

- 点击页面的下载后,执行下载操作(Servlet 中的 download 方法)

  写这个小案例时遇到了以下几个问题,折腾了好一会儿,虽然找到了解决方法但是对有些问题并不是很清楚,其解决方法我觉得还有更好,还望大神指教,先谢谢了!

    - 使用了 c3p0.0.92.jar 需要 额外的依赖包,使用 0.91.jar 不需要额外的依赖包

    - 在下载文件的时候我们利用到了反射,由于没有在 files 类中创建无参构造器,而报错 

    - 在上一步报错后,自己在 deBug 找错完之后,直接运行时出现1099 端口被占用问题(在 cmd 命令行中杀死 1099 进程)

    - 有时候启动 IDEA 的时候会报错(Cannot start internal HTTP server. Git integration, JavaScript debugger and LiveEdit may operate with errors. Please check your firewall settings and restart IntelliJ IDEA),我每次都是关掉防火墙不知道有没有彻底点的解决方案!!!

  建议在开发的过程中使用绝对路径,可以避免找不到页面的问题,应该先了解 / 所代表的含义

    - 在请求转发的时候、web.xml 文件映射 Servlet 访问路径的时候,/ 代表当前 WEB 应用的根目录

    - 在超链接中、form 表单的 action 中、请求重定向的时候,/ 代表当前站点的根目录

    - 若 / 交由 Servlet 容器来处理则代表当前 WEB 应用的根目录,若 / 交由浏览器处理则代表当前站点的根目录

  至此文件的上传和下载小案例就结束了,欢迎大家提出多的、好的意见,一块进步!