2022.5.8 文件的上传与下载

文件的上传介绍

步骤:

  • 要有一个form标签,method=post请求(get请求有长度限制)

  • form标签的encType属性值必须为multipart/form-data值,encType=multipart/form-data表示提交的数据以多段(每一个表单项一个数据段)的形式进行拼接,然后以二进制流的形式发送给服务器

  • 在form标签中使用input type=file添加上传的文件

  • 编写服务器代码(Servlet程序)接收,处理上传的数据。

UploadServlet

 1 package com.xing.servlet;
 2  3  4 import org.apache.commons.fileupload.FileItem;
 5 import org.apache.commons.fileupload.FileItemFactory;
 6 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
 7 import org.apache.commons.fileupload.servlet.ServletFileUpload;
 8  9 import javax.servlet.ServletException;
10 import javax.servlet.ServletInputStream;
11 import javax.servlet.http.HttpServlet;
12 import javax.servlet.http.HttpServletRequest;
13 import javax.servlet.http.HttpServletResponse;
14 import java.io.File;
15 import java.io.IOException;
16 import java.util.List;
17 18 public class UploadServlet extends HttpServlet {
19 20     @Override
21     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
22         System.out.println("这种方式以流的形式发送");
23         ServletInputStream inputStream = req.getInputStream();
24         //缓冲区
25         byte[] buffer = new byte[8096];
26         //读了几个字节
27         int read = inputStream.read(buffer);
28         //在缓冲区buffer中从0字节读到read字节
29         System.out.println(new String(buffer,0,read));
30     }
31 32 }

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_4_0.xsd"
 5          version="4.0">
 6  7     <servlet>
 8         <servlet-name>UploadServlet</servlet-name>
 9         <servlet-class>com.xing.servlet.UploadServlet</servlet-class>
10     </servlet>
11     <servlet-mapping>
12         <servlet-name>UploadServlet</servlet-name>
13         <url-pattern>/uploadServlet</url-pattern>
14     </servlet-mapping>
15 16 </web-app>

upload.jsp

 1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 2 <html>
 3 <head>
 4     <title>Title</title>
 5 </head>
 6 <body>
 7     <form action="http://localhost:8080/09_EL_JSTL/uploadServlet" method="post" enctype="multipart/form-data">
 8         用户名:<input type="text" name="username" /> <br>
 9         头像:<input type="file" name="photo" > <br>
10         <input type="submit" value="上传">
11     </form>
12 </body>
13 </html>

访问:http://localhost:8080/09_EL_JSTL/upload.jsp点击上传

commons-fileupload.jar 常用 API 介绍说明

对上传接收的数据进行解析

1 <dependency>
2     <groupId>commons-fileupload</groupId>
3     <artifactId>commons-fileupload</artifactId>
4     <version>1.5</version>
5 </dependency>

我们常用的类有哪些?

ServletFileUpload类,用于解析上传的数据。

 1 boolean ServletFileUpload. isMultipartContent (HttpServletRequest request);//判断当前上传的数据格式是否是多段的格式。
 2  3 //FileItem类,表示每一个表单项。表单项还分为普通表单项、上传文件的表单项等
 4 publicList<FileItem>parseRequest(HttpServletRequestrequest);//解析上传的数据
 5     
 6 boolean FileItem.isFormField();//判断当前这个表单项,是否是普通的表单项。还是上传的文件类型,true 表示普通类型的表单项,false 表示上传的文件类型
 7     
 8 String FileItem.getFieldName();//获取表单项的name属性值
 9 String FileItem.getString();//获取当前表单项的值。
10 String FileItem.getName();//获取上传的文件名
11 void FileItem.write( file );//将上传的文件写到参数file所指向抽硬盘位置 。

fileupload 类库的使用

UploadServlet

 1 package com.xing.servlet;
 2  3 import org.apache.commons.fileupload.FileItem;
 4 import org.apache.commons.fileupload.FileItemFactory;
 5 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
 6 import org.apache.commons.fileupload.servlet.ServletFileUpload;
 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.File;
13 import java.io.IOException;
14 import java.util.List;
15 16 public class UploadServlet extends HttpServlet {
17 18     @Override
19     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
20         req.setCharacterEncoding("UTF-8");//获取中文文件名时乱码
21         
22         //1 先判断上传的数据是否多段数据(只有是多段的数据,才是文件上传的) true是多值
23         if (ServletFileUpload.isMultipartContent(req)) {
24             //创建FileItemFactory工厂实现类
25             FileItemFactory fileItemFactory = new DiskFileItemFactory();
26             // 创建用于解析上传数据的工具类ServletFileUpload类
27             ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
28             try {
29                 // 解析上传的数据,得到每一个表单项FileItem
30                 List<FileItem> list = servletFileUpload.parseRequest(req);
31                 // 循环判断,每一个表单项,是普通类型,还是上传的文件
32                 for (FileItem fileItem : list) {
33 34                     if (fileItem.isFormField()) {
35                         // 普通表单项
36                         System.out.println("表单项的name属性值:" + fileItem.getFieldName());//表单项的name属性值:username
37                         // 参数UTF-8.解决乱码问题
38                         System.out.println("表单项的value属性值:" + fileItem.getString("UTF-8"));//表单项的value属性值:aaa
39 40                     } else {
41                         // 上传的文件
42                         System.out.println("表单项的name属性值:" + fileItem.getFieldName());//表单项的name属性值:photo
43                         System.out.println("上传的文件名:" + fileItem.getName());//上传的文件名:常见请求和响应头-说明.pdf
44                         //上传文件的写入地址
45                         fileItem.write(new File("C:\\Users\\16159\\Desktop\\work\\" + fileItem.getName()));
46                     }
47                 }
48             } catch (Exception e) {
49                 e.printStackTrace();
50             }
51         }
52 53     }
54 55 }

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_4_0.xsd"
 5          version="4.0">
 6  7     <servlet>
 8         <servlet-name>UploadServlet</servlet-name>
 9         <servlet-class>com.xing.servlet.UploadServlet</servlet-class>
10     </servlet>
11     <servlet-mapping>
12         <servlet-name>UploadServlet</servlet-name>
13         <url-pattern>/uploadServlet</url-pattern>
14     </servlet-mapping>
15 16 </web-app>

upload.jsp

 1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 2 <html>
 3 <head>
 4     <title>Title</title>
 5 </head>
 6 <body>
 7     <form action="http://localhost:8080/09_EL_JSTL/uploadServlet" method="post" enctype="multipart/form-data">
 8         用户名:<input type="text" name="username" /> <br>
 9         头像:<input type="file" name="photo" > <br>
10         <input type="submit" value="上传">
11     </form>
12 </body>
13 </html>

访问:http://localhost:8080/09_EL_JSTL/upload.jsp点击上传

文件下载

Download

响应头的设置要放到流传输的前面

 1 package com.xing.servlet;
 2  3 import org.apache.commons.io.IOUtils;
 4 import sun.misc.BASE64Encoder;
 5  6 import javax.servlet.ServletContext;
 7 import javax.servlet.ServletException;
 8 import javax.servlet.http.HttpServlet;
 9 import javax.servlet.http.HttpServletRequest;
10 import javax.servlet.http.HttpServletResponse;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.io.OutputStream;
14 import java.net.URLEncoder;
15 16 public class Download extends HttpServlet {
17 18 19     @Override
20     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
21         // 获取要下载的文件名
22         String downloadFileName = "2.jpg";
23         // 读取要下载的文件内容 (通过ServletContext对象可以读取)
24         ServletContext servletContext = getServletContext();
25 26         // 获取要下载的文件类型
27         String mimeType = servletContext.getMimeType("/file/" + downloadFileName);
28         System.out.println("下载的文件类型:" + mimeType);
29 30         // 在回传前,通过响应头告诉客户端返回的数据类型
31         resp.setContentType(mimeType);
32 33         // 还要告诉客户端收到的数据是用于下载使用(还是使用响应头)
34         // Content-Disposition响应头,表示收到的数据怎么处理
35         // attachment表示附件,表示下载使用
36         // filename= 表示指定下载的文件名
37         resp.setHeader("Content-Disposition", "attachment; filename=" + downloadFileName);
38 39         /**
40          * /斜杠被服务器解析表示地址为http://ip:prot/工程名/  映射 到代码的Web目录
41          * getResourceAsStream获取资源像流一样返回
42          * 输入流:文件变成流
43          * 输出流:流变成文件
44          */
45         InputStream resourceAsStream = servletContext.getResourceAsStream("/file/" + downloadFileName);
46         // 获取响应的输出流
47         OutputStream outputStream = resp.getOutputStream();
48 49         // 把下载的文件内容回传给客户端
50         // 读取输入流中全部的数据,复制给输出流,输出给客户端
51         IOUtils.copy(resourceAsStream, outputStream);
52 53     }
54 }

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_4_0.xsd"
 5          version="4.0">
 6     
 7   <servlet>
 8     <servlet-name>Download</servlet-name>
 9     <servlet-class>com.xing.servlet.Download1</servlet-class>
10   </servlet>
11   <servlet-mapping>
12     <servlet-name>Download</servlet-name>
13     <url-pattern>/Download</url-pattern>
14   </servlet-mapping>
15 </web-app>

访问:http://localhost:8080/09_EL_JSTL/Download

将文件名设置成中文

Download

 1 package com.xing.servlet;
 2  3 import org.apache.commons.io.IOUtils;
 4 import sun.misc.BASE64Encoder;
 5  6 import javax.servlet.ServletContext;
 7 import javax.servlet.ServletException;
 8 import javax.servlet.http.HttpServlet;
 9 import javax.servlet.http.HttpServletRequest;
10 import javax.servlet.http.HttpServletResponse;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.io.OutputStream;
14 import java.net.URLEncoder;
15 16 public class Download extends HttpServlet {
17 18 19     @Override
20     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
21         // 获取要下载的文件名
22         String downloadFileName = "2.jpg";
23         // 读取要下载的文件内容 (通过ServletContext对象可以读取)
24         ServletContext servletContext = getServletContext();
25 26         // 获取要下载的文件类型
27         String mimeType = servletContext.getMimeType("/file/" + downloadFileName);
28         System.out.println("下载的文件类型:" + mimeType);
29 30         // 在回传前,通过响应头告诉客户端返回的数据类型
31         resp.setContentType(mimeType);
32 33         // 还要告诉客户端收到的数据是用于下载使用(还是使用响应头)
34         if (req.getHeader("User-Agent").contains("Firefox")) {
35             // 如果是火狐浏览器使用Base64编码
36             resp.setHeader("Content-Disposition", "attachment; filename==?UTF-8?B?" + new BASE64Encoder().encode("中国.jpg".getBytes("UTF-8")) + "?=");
37         } else {
38             // 如果不是火狐,是IE或谷歌,使用URL编码操作  url编码是把汉字转换成为%xx%xx的格式  xx是十六进制数
39             resp.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("中国.jpg", "UTF-8"));
40         }
41         /**
42          * /斜杠被服务器解析表示地址为http://ip:prot/工程名/  映射 到代码的Web目录
43          * getResourceAsStream获取资源像流一样返回
44          * 输入流:文件变成流
45          * 输出流:流变成文件
46          */
47         InputStream resourceAsStream = servletContext.getResourceAsStream("/file/" + downloadFileName);
48         // 获取响应的输出流
49         OutputStream outputStream = resp.getOutputStream();
50 51         // 把下载的文件内容回传给客户端
52         // 读取输入流中全部的数据,复制给输出流,输出给客户端
53         IOUtils.copy(resourceAsStream, outputStream);
54 55     }
56 }

附件中文名乱码问题

方案一: URLEncoder 解决 IE 和谷歌浏览器的附件中文名问题。

如果客户端浏览器是IE浏览器或者是谷歌浏览器。我们需要使用URLEncoder类先对中文名进行UTF- 8 的编码

操作。因为IE浏览器和谷歌浏览器收到含有编码后的字符串后会以UTF- 8 字符集进行解码显示。

方案二: BASE 64 编解码 解决 火狐浏览器的附件中文名问题 (现阶段火狐浏览器已经支持方案一了)

如果客户端浏览器是火狐浏览器。 那么我们需要对中文名进行BASE 64 的编码操作。这时候需要把请求头Content-Disposition: attachment; filename=中文名

编码成为:Content-Disposition: attachment; filename==?charset?B?xxxxx?=

=?charset?B?xxxxx?= 现在我们对这段内容进行一下说明。

  • =? 表示编码内容的开始

  • charset 表示字符集

  • B 表示BASE 64 编码

  • xxxx 表示文件名BASE 64 编码后的内容

  • ?= 表示编码内容的结束

BASE 64 编解码

 1 package com.xing.servlet;
 2  3 import sun.misc.BASE64Decoder;
 4 import sun.misc.BASE64Encoder;
 5  6 public class Base64Test {
 7     public static void main(String[] args) throws Exception {
 8         String content = "这是需要Base64编码的内容";
 9         // 创建一个Base64编码器
10         BASE64Encoder base64Encoder = new BASE64Encoder();
11         // 执行Base64编码操作
12         String encodedString = base64Encoder.encode(content.getBytes("UTF-8"));
13 14         System.out.println( encodedString );
15         // 创建Base64解码器
16         BASE64Decoder base64Decoder = new BASE64Decoder();
17         // 解码操作
18         byte[] bytes = base64Decoder.decodeBuffer(encodedString);
19 20         String str = new String(bytes, "UTF-8");
21 22         System.out.println(str);
23     }
24 }

因为火狐使用的是 BASE 64 的编解码方式还原响应中的汉字。所以需要使用 BASE 64 Encoder 类进行编码操作。

那么我们如何解决上面两种不同编解码方式呢。我们只需要通过判断请求头中User-Agent这个请求头携带过来的

浏览器信息即可判断出是什么浏览器。

 
posted @ 2022-05-23 09:02  暴躁C语言  阅读(3)  评论(0编辑  收藏  举报