看完再也不担心不会文章的上传与下载(建议收藏)

简介: ​ 既然文件上传如此头疼,那么总该有人挺身而出帮我们解决这个难题。Servlet 3.0 提供了文件上传操作功能,而且使用也非常简单。

1.JPG


一、文件的上传


将用户本地磁盘中的文件提交保存到服务器中的磁盘上。


2.JPG


1.1、存在的问题.


我们要做文件上传,一般的步骤是:


  1. 要有一个 form 标签,method=post 请求。因为get请求里面限制了大小。
  2. form 标签的 encType 属性值必须为 multipart/form-data 值。
  3. 在 form 标签中使用 input type=file 添加上传的文件。
  4. 编写服务器代码(Servlet 程序)接收,处理上传的数据。


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


3.JPG


我们通过写代码可以发现,enctype="multipart/form-data" 提交的数据,getParameter() 无法获取到。


4.JPG


1.2、Servlet3.0 文件上传


既然文件上传如此头疼,那么总该有人挺身而出帮我们解决这个难题。Servlet 3.0 提供了文件上传操作功能,而且使用也非常简单。


我们只需要给 Servlet 贴一个注解 @MultipartConfig 然后使用getPart()获取请求中指定 name 的文件到 Part 对象,就可以使用它的API来进行操作文件了。


1.3、API


HttpServletRequest 提供了两个方法用于从请求中解析上传的文件。


返回值 方法 作用
Part getPart(String name) 用于获取请求中指定 name 的文件
Collection getParts() 获取请求中全部的文件

Part中常用的方法:

返回值 方法 作用
void write(String fileName) 直接把接收到的文件保存在磁盘中
void getContentType() 获取文件的MIME类型
String getHeader(String name) 获取请求头信息
long getSize() 获取文件的大小


1.4、代码


package com.servlet;
import java.io.IOException;
import java.net.http.HttpClient;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
/**
 * @author Xiao_Lin
 * @date 2021/1/20 9:26
 */
@WebServlet("/fileUpload")
@MultipartConfig
public class FileUploadServlet extends HttpServlet {
  @Override
  protected void service(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    // 普通的参数还是使用原来的接收方式
    String username = req.getParameter("username");
    // 文件数据的获取
    Part part = req.getPart("headImg");
    //保存到磁盘,参数名称为盘符+文件名+后缀名(自己命名)
    part.write("d:/headimg.jpg");
复制代码
<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<html>
<body>
<h2>Hello World!</h2>
<form action="/fileUpload" method="post" enctype="multipart/form-data">
    用户名:<input type="text" name="username">
    上传文件:<input type="file" name="headImg">
    <input type="submit" value="注册">
</form>
</body>
</html>
复制代码


二、文件上传拓展


2.1、获取上传文件名


我们可以使用可使用 Part对象的API来获取。


返回值 方法 作用
String getHeader("content-disposition") Tocmat 8.0 之前使用通过请求头获取文件名,需截取字符串
String getSubmittedFileName() Tomcat8.0 之后提供的直接获取文件名方式


package com.servlet;
import java.io.IOException;
import java.net.http.HttpClient;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
/**
 * @author Xiao_Lin
 * @date 2021/1/20 9:26
 */
@WebServlet("/fileUpload")
@MultipartConfig
public class FileUploadServlet extends HttpServlet {
  @Override
  protected void service(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    // 普通的参数还是使用原来的接收方式
    String username = req.getParameter("username");
    // 文件数据的获取
    Part part = req.getPart("headImg");
    // 保存到磁盘,参数名称为盘符+文件名+后缀名(自动获取文件名)
    part.write("d:/"+part.getSubmittedFileName());
  }
}
复制代码


2.2、使用UUID生成文件名


若上传得文件名相同会导致覆盖服务器之前已上传的的文件,我们的解决方法就是自己给文件起一个唯一的名称,确保不被覆盖,这里我们使用的是 UUID


package com.servlet;
import java.io.IOException;
import java.net.http.HttpClient;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
/**
 * @author Xiao_Lin
 * @date 2021/1/20 9:26
 */
@WebServlet("/fileUpload")
@MultipartConfig
public class FileUploadServlet extends HttpServlet {
  @Override
  protected void service(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    // 文件数据的获取
      Part part = req.getPart("headImg");
    //获取上传的文件名
    String realName = part.getSubmittedFileName();
    //拿到文件的拓展名
    String ext = realName.substring(realName.lastIndexOf("."));
    //生成唯一的UUID,保证不会重复
    String fileNewName = UUID.randomUUID().toString()+ext;
    part.write("d://"+fileNewName);
  }
}
复制代码


注意:在tomcat7 的环境下就没有part.getSubmittedFileName()这一方法,无法直接获取文件名,如果使用的是Tomcat7插件或者是Tomcat8以下的版本,需要换方法。不然会报错。


5.JPG


String cd = part.getHeader("Content-Disposition");
//截取不同类型的文件需要自行判断
 String filename = cd.substring(cd.lastIndexOf("=")+2, cd.length()-1);
复制代码


2.3、文件保存位置问题


文件在磁盘某个位置,不在项目下,无法使用 HTTP 协议访问,所以要把用户上传的文件存放到项目中


才可通过 HTTP 协议来访问,且保存的位置路径不可以写绝对路径,那么我们该如何进行访问呢?


我们可以通过ServletContext 对象的 getRealPath("项目中保存上传文件的文件夹的相对路径") 来获取其的绝对路径。


我们在webapps目录下新建一个upload用来存放文件。


package com.servlet;
import java.io.IOException;
import java.net.http.HttpClient;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
/**
 * @author Xiao_Lin
 * @date 2021/1/20 9:26
 */
@WebServlet("/fileUpload")
@MultipartConfig
public class FileUploadServlet extends HttpServlet {
  @Override
  protected void service(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    // 文件数据的获取
      Part part = req.getPart("headImg");
    String cd = part.getHeader("Content-Disposition");
    //获取上传的文件名
    String realName = cd.substring(cd.lastIndexOf("=")+2, cd.length()-1);
    //拿到文件的拓展名
    String ext = realName.substring(realName.lastIndexOf("."));
    //生成唯一的UUID,保证不会重复
    String fileNewName = UUID.randomUUID().toString()+ext;
    // 获取项目下的 upload 目录的绝对路径,拼接成文件的保存路径(maven项目需要用tomcat7才可以)
    String realPath = req.getServletContext().getRealPath("/upload") +"/"+ fileNewName;
    part.write(realPath);
  }
}
复制代码


2.4、文件类型的约束


限制用户恶意上传文件,比如要让用户上传头像,而用户却上传一个非图片文件,比如 JSP 文件。


package com.servlet;
import java.io.IOException;
import java.net.http.HttpClient;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
/**
 * @author Xiao_Lin
 * @date 2021/1/20 9:26
 */
@WebServlet("/fileUpload")
@MultipartConfig
public class FileUploadServlet extends HttpServlet {
  @Override
  protected void service(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    // 文件数据的获取
    Part part = req.getPart("headImg");
    System.out.println(part.getContentType());
    // 如果上传的文件不是图片(文件扩展名不是以image开头的就不是图片)
    if (!part.getContentType().startsWith("image/")) {
      req.setAttribute("msg","请上传图片");
      req.getRequestDispatcher("/index.jsp").forward(req, resp);
      return;
    }
  }
}
复制代码


2.5、文件的大小约束


文件上传限制大小可提高服务器硬盘的使用率,防止用户恶意上传文件造成服务器磁盘资源紧张。我们可以通过设置 @MutipartConfig 的属性做限制,他有两个属性:


  1. maxFileSize:单个上传文件大小限制,单位:bytes。
  2. ·maxRequestSize·:显示请求中数据的大小,单位:bytes。


@MultipartConfig(maxFileSize = 80000, maxRequestSize = 140000)
复制代码


三、文件的下载

3.1、代码


package com.servlet;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * @author Xiao_Lin
 * @date 2021/1/21 10:58
 */
@WebServlet(urlPatterns = "/download")
public class DownloadServlet extends HttpServlet {
  @Override
  protected void service(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    // 获取用户需要下载的文件名称
    String fileName = req.getParameter("fileName");
    // 获取文件所在的根路径
    String realPath = req.getServletContext().getRealPath("/WEB-INF/upload/");
    // 使用工具类Files的copy方法获取一个文件输出流,响应给浏览器
    Files.copy(Paths.get(realPath,fileName),resp.getOutputStream());
  }
}
复制代码


3.2、下载文件的名称问题


默认情况下,Tomcat 服务器未告知浏览器文件的名称,所以需要手动设置响应头来告知浏览器文件名称。


// 给浏览器一个推荐名称
resp.setHeader("Content-Disposition", "attachment;filename=文件名称");
复制代码


如果文件中有中文的话还涉及到需要处理中文乱码的问题,这里分为两个流派:

  • IE 使用 URL 编码方式:URLEncoder.encode(fileName, "UTF-8")
  • 非 IE使用 ISO-8859-1 编码:new String (fileName.getBytes("UTF-8"), "ISO-8859-1")


package com.servlet;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * @author Xiao_Lin
 * @date 2021/1/21 10:58
 */
@WebServlet(urlPatterns = "/download")
public class DownloadServlet extends HttpServlet {
  @Override
  protected void service(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    // 获取用户需要下载的文件名称
    String fileName = req.getParameter("fileName");
    // 获取浏览器的类型
    String header = req.getHeader("User-Agent");
    // 如果包含MSIE说明是微软的浏览器(非IE),否则就不是IE
    String name = header.contains("MSIE") ? URLEncoder.encode(fileName, StandardCharsets.UTF_8) :
        new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
    // 设置文件的下载名
    resp.setHeader("Content-Disposition","attachment;filename=" + name);
    // 获取文件所在的根路径
    String realPath = req.getServletContext().getRealPath("/WEB-INF/upload/");
    // 使用工具类Files的copy方法获取一个文件输出流,响应给浏览器
    Files.copy(Paths.get(realPath,fileName),resp.getOutputStream());
  }
}
相关文章
|
存储
【C盘瘦身】如何清理Wechat Files,经常使用电脑微信用户必知的常识!
【C盘瘦身】如何清理Wechat Files,经常使用电脑微信用户必知的常识!
2306 0
【C盘瘦身】如何清理Wechat Files,经常使用电脑微信用户必知的常识!
|
10月前
|
JavaScript Java 区块链
经常忘记网址?将Vue项目一键打包为桌面客户端 十分钟让你解决烦恼(一)
经常忘记网址?将Vue项目一键打包为桌面客户端 十分钟让你解决烦恼
150 0
|
7月前
|
存储 缓存 数据安全/隐私保护
偶然间发现C盘爆红,几个办法超详细教你轻松解决,电脑小白也不用为此而烦恼!
今天无意间打开“我的电脑”发现作为驱动盘的**C盘爆红**!!!导致自己的血压飙升,在网上查了很多的处理办法之后,苦苦花费数小时之后自己顺利解决,以下方法教你轻松解决“C盘爆红”。**以下方法本人亲测,放心使用****清理和扩容C盘的方法还有很多,我觉得值得注意的是在平时安装软件的时候,要注意对安装路径的选择更改,而不是一股脑的点击“下一步”,这样你的C盘会减小很大的压力! 大家还有什么清理和扩容C盘的好办法呢?欢迎在评论区分享出来 ~ :)**
666 0
偶然间发现C盘爆红,几个办法超详细教你轻松解决,电脑小白也不用为此而烦恼!
|
4月前
|
移动开发 JavaScript C#
分享53戏源代码总有一个是你想要的(亲测每一个均可用)
分享53戏源代码总有一个是你想要的(亲测每一个均可用)
24 0
|
8月前
|
存储 程序员 对象存储
picgo+typora 超级好用的图床工具,再也不用担心图片失效啦
picgo+typora 超级好用的图床工具,再也不用担心图片失效啦
111 0
|
9月前
图片太大传输和保存不方便?一招解决你的烦恼!
在日常工作中,“拍照”是我们必不可不少的一件事情。写简报、总结都离不开图片。
89 0
|
10月前
|
JavaScript 应用服务中间件 网络安全
经常忘记网址?将Vue项目一键打包为桌面客户端 十分钟让你解决烦恼(二)
经常忘记网址?将Vue项目一键打包为桌面客户端 十分钟让你解决烦恼
144 0
|
11月前
|
JavaScript Java 应用服务中间件
经常忘记网址?将Vue项目一键打包为桌面客户端 十分钟让你解决烦恼
本文讲解了如何将一个Vue项目打包为桌面客户端,实现像Excel一样双击运行,适用于管理较多项目且经常忘记网址的场景。本文还讲解了 Vue 项目从下载依赖、打包和Nginx部署的全过程,可以给开发者参考学习。
11630 3
|
JavaScript 容器
《大胖 • 小课》- 玩玩多文件配多进度上传
这是《大胖小课》栏目的专题一《说说文件上传那些事儿》的第4节-《玩玩多文件配多进度上传》 专题已经更新章节: 《大胖 • 小课》- 我是这样理解文件上传原理的 《大胖 • 小课》- 写一个文件上传接口 《大胖 • 小课》- 不用 js 实现文件无刷新上传 既然要说多文件配多进度上传,那就要看看单个进度是如何实现的。
91 1
《大胖 • 小课》- 玩玩多文件配多进度上传
|
缓存 开发者
微擎网页快照BUG解决方案
2022年7月更新微擎后BUG解决方案
微擎网页快照BUG解决方案