一、文件上传
1、文件上传介绍
-
要有一个 form 标签,method=post 请求
-
form 标签的 encType 属性值必须为 multipart/form-data 值
-
在 form 标签中使用 input type=file 添加上传的文件
-
编写服务器代码(Servlet 程序)接收,处理上传的数据。
注意:encType=multipart/form-data
表示提交的数据,以多段(每一个表单项一个数据段)的形式进行拼接,然后以二进制流的形式发送给服务器。
upload.jsp文件:
注意:get的url长度有限制,post无限制,一般上传使用post
1 2 3 4 5 6
| <%--get的url长度有限制,post无限制--%> <form action="uploadServlet" method="post" enctype="multipart/form-data"> 用户名:<input type="text" name="username"><br> 头像:<input type="file" name="photo"><br> <input type="submit" value="提交"><br> </form>
|
配置XML文件:
1 2 3 4 5 6 7 8
| <servlet> <servlet-name>UploadServlet</servlet-name> <servlet-class>com.atguigu.servlet.UploadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UploadServlet</servlet-name> <url-pattern>/upload</url-pattern> </servlet-mapping>
|
uploadServlet文件:
注意:以流的形式发送,无法通过请求参数接收!form表单的enctype属性决定的!
使用如下方式接收上传的文件,在控制台自然是乱码的,毕竟是二进制数据!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ System.out.println("收到文件了!");
ServletInputStream is = req.getInputStream();
byte[] buffer = new byte[102400000]; int len = is.read(buffer); System.out.println(new String(buffer, 0, len)); }
|
文件上传发送的HTTP协议内容:
注意:谷歌浏览器中上传的文件的数据显示的是空行,毕竟数据太多,还不是文本数据,但不影响服务器接收数据!
2、使用第三方包解决
需要使用第三方包 commons-fileupload.jar来解决!
2.1、导包
- commons-fileupload.jar
- commons-io.jar
2.2、该开源库的常用方法
ServletFileUpload 类,用于解析上传的数据:
- public static final boolean isMultipartContent(HttpServletRequest request):判断当前上传的数据格式是否是多段的格式。
- public List<FileItem> parseRequest(HttpServletRequest request):解析上传的数据,返回包含每一个表单项的List集合
FileItem类,表示每一个表单项:
- public boolean isFormField():如果当前表单项是普通表单项,返回true,文件类型返回false
- public String getFieldName():获取当前表单项的name属性值
- public String getString():获取当前表单项的value属性值,参数为”UTF-8”可解决乱码问题
- public String getName():获取上传的文件名
- public void write(File file):将上传的文件写到参数File所指向的硬盘位置
2.3、解析上传数据的代码
注意:此开源jar包并不兼容Tomcat10,Tomcat10实在太新了。请安装Tomcat8使用!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public class UploadServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
if(ServletFileUpload.isMultipartContent(req)){ FileItemFactory fileItemFactory = new DiskFileItemFactory(); ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
try { List<FileItem> list = servletFileUpload.parseRequest(req);
for (FileItem fileItem : list) { if(fileItem.isFormField()){ System.out.println("表单项的name属性为:" + fileItem.getFieldName()); System.out.println("表单项的value属性为:" + fileItem.getString("UTF-8")); }else{ System.out.println("表单项的name属性为:" + fileItem.getFieldName()); System.out.println("上传的文件名为:" + fileItem.getName());
fileItem.write(new File("C:\\Users\\15890\\Desktop\\" + fileItem.getName())); } }
} catch (Exception e) { e.printStackTrace(); }
} } }
|
二、文件下载
1、文件下载过程
- 获取要下载的文件名
- 创建ServletContext对象
- 回传客户端前,通过ServletContext对象设置响应头告诉客户端返回的数据类型及用途
- 通过ServletContext对象流读取该文件
- 通过Response获取输出流
- 通过commons-io包下的 IOUtils工具类的copy方法读到输出流
2、代码实现
注意点:
- 告诉客户端设置数据类型:
resp.setContentType(mimeType)
- 告诉客户端为下载用途:
resp.setHeader("Content-Disposition", "attachment; fileName=" + fileName)
- Content-Disposition:表示收到数据如何处理
- attachment:表示附件,用于下载
- fileName:表示下载文件的保存名字
下载文件名为中文的乱码问题:
使用URL编码即可: String fileName = URLEncoder.encode(downloadFileName, "UTF-8")
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public class DownLoadServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String downloadFileName = "ghs.mp4"; ServletContext servletContext = getServletContext();
String mimeType = servletContext.getMimeType("/file/" + downloadFileName); resp.setContentType(mimeType); System.out.println("文件类型为:" + mimeType); String fileName = URLEncoder.encode(downloadFileName, "UTF-8"); resp.setHeader("Content-Disposition", "attachment; fileName=" + fileName);
InputStream resourceAsStream = servletContext.getResourceAsStream("/file/" + downloadFileName); ServletOutputStream outputStream = resp.getOutputStream(); IOUtils.copy(resourceAsStream, outputStream);
} }
|
3、火狐浏览器乱码问题(了解)
以前的火狐浏览器下载的文件名含有中文会乱码,使用URL编码后仍然乱码,必须使用BASE64编码!
But:如今新时代的火狐浏览器使用和谷歌或IE浏览器一样的URL编码即可正确显示中文文件名!
So:下方处理火狐浏览器下载中文乱码的内容,仅作为学习记录,了解即可!
3.1、Base64使用
注意:jdk8之后不再支持BASE64Decoder和BASE64Encoder两个类!
取而代之的是java.util.Base64
类!
JDK8之前的旧版、废弃版:(了解)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder;
public class Base64Test { public static void main(String[] args) throws Exception { String content = "这是需要Base64编码的内容"; System.out.println("初始内容:" + content); BASE64Encoder base64Encoder = new BASE64Encoder(); String encodedString = base64Encoder.encode(content.getBytes("UTF-8")); System.out.println("编码后的结果:" + encodedString ); BASE64Decoder base64Decoder = new BASE64Decoder(); byte[] bytes = base64Decoder.decodeBuffer(encodedString); String str = new String(bytes, "UTF-8"); System.out.println("解码后的结果:" + str); } }
|
JDK8之后的新版、高效率版:
与sun.misc套件和Apache Commons Codec所提供的Base64编解码器来比较的话,Java 8提供的Base64拥有更好的效能。
实际测试编码与解码速度的话,Java 8提供的Base64,要比sun.misc套件提供的还要快至少11倍,比Apache Commons Codec提供的还要快至少3倍。
因此在Java上若要使用Base64,这个Java 8底下的java.util套件所提供的Base64类别绝对是首选!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Base64Test {
public static void main(String[] args) throws UnsupportedEncodingException { String str = "这是我的祖国!";
Base64.Encoder encoder = Base64.getEncoder(); String s = encoder.encodeToString(str.getBytes(StandardCharsets.UTF_8)); System.out.println(s);
Base64.Decoder decoder = Base64.getDecoder(); String s1 = new String(decoder.decode(s), "UTF-8"); System.out.println(s1);
} }
|
3.2、火狐乱码解决(了解)
- 谷歌浏览器请求头:
Content-Disposition: attachment; filename=中文名
- 火狐浏览器请求头:
Content-Disposition: attachment; filename==?charset?B?xxxxx?=
filename后的参数介绍:
=?
表示编码内容的开始
charset
表示字符集(UTF-8、GBK等)
B
表示BASE64编码
xxxx
表示BASE64编码后的内容
?=
表示编码内容的结束
通过User-Agent判断浏览器类型,分别处理:(了解)
1 2 3 4 5 6 7 8 9 10 11 12
|
if(req.getHeader("User-Agent").contains("Firefox")){ String str = "attachment; fileName=" + "=?utf-8?B?" + Base64.getEncoder().encodeToString(downloadFileName.getBytes("utf-8")) + "?="; resp.setHeader("Content-Disposition", str); }else{ String fileName = URLEncoder.encode(downloadFileName, "UTF-8"); resp.setHeader("Content-Disposition", "attachment; fileName=" + fileName); }
|