Servlet文件的上传与下载详解

 更新时间:2022年06月18日 10:46:26   作者:苏瞳呐  
很多朋友不清楚在Servlet中怎么上传下载文件,谈到这个问题,首先需要我们掌握开发servlet的步骤,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

文件的上传和下载

1. 文件上传细节

要有一个 form 标签,method-post请求 (因为get有长度限制)

form标签的属性 encType 值必须为 multipart/form-data

表示提交的数据以多端(每一个表单项一个数据段)的形式进行拼接,然后以二进制流的形式发送给服务器

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

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

文件上传http请求信息:

请求头:Content-Type: multipart/form-data; boundary=------WebKitFormBoundaryCd3g75eOt35olUs7

解析:

  • Content-Type 表示提交的数据类型
  • multipart/form-data 表示以流的形式分段提交服务器
  • boundary 表示每段数据的分隔符,值:----WebKitFormBoundarylXiF4fEzpo9c8L4p 是浏览器每次随机生成的,它就是每段数据的分界符。在每段里面 第一行是对表单项的描述,然后有个空行,下面是提交的值。

请求体:

------WebKitFormBoundaryCd3g75eOt35olUs7
Content-Disposition: form-data; name="username"

zhu
------WebKitFormBoundaryCd3g75eOt35olUs7
Content-Disposition: form-data; name="photo"; filename="head.jpg"
Content-Type: image/jpeg

文件的信息(很长这里省略了)
------WebKitFormBoundaryCd3g75eOt35olUs7--

因为客户端是以按流的方式提交是,所以我们要按流的方式获取,不能这样: req.getParameter("username");

正确用法:

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("上传成功");
    ServletInputStream inputStream = req.getInputStream(); // 先得到 字节输入流
    byte[] buffer = new byte[1024]; // 缓冲区
    int readCount = 0;
    while ((readCount = inputStream.read(buffer)) != -1) { // 打印出来的就是上面全部的请求体
        System.out.println(new String(buffer, 0, readCount));
    }
}

2. 文件上传

这种文件上传(常用)有很多第三方提供好的API我们使用进行了,可以帮我们对收到的数据进行解析。

例如:commons-fileupload-1.2.1.jar (依赖于 commons-io-1.4.jar

  • 导入两个jar包
  • 解析

关键的类:

  • ServletFileUpload 类:用于解析上传的数据
  • FileItem 类:每一个表单项
//ServletFileUpload中的方法
// 判断当前上传的数据是否是多端的格式,不是解析不了
public boolean ServletFileUpload.isMultipartContent(HttpServletRequest req) 
// 解析上传的数据,FileItem表示每一个表单项
public List<FileItem> parseRequest(HttpServletRequest req)
//FileItem中方法
// 判断当前这个表单项是普通的表单项还是文件上传的类型,true表示普通的
public boolean isFormField()    
// 获取表单项name属性值
public String getFieldName()
// 获取当前表单项的值
public String getString() // 可传入字符集,防止乱码,一开始req.setCharacterEncoding("UTF-8");也行
// 获取上传的文件名
public String getName()
// 将上传的文件写道 参数file所指向的磁盘位置
public void write(File file)

Servlet上传文件示例:

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    req.setCharacterEncoding("UTF-8"); // 防止乱码
    resp.setContentType("text/html; charset=utf-8");
    String savePath = getServletContext().getRealPath("/WEB-INF/uploadFile"); //保存的路径
    // 首先判断上传的数据是否是多段的数据
    if (ServletFileUpload.isMultipartContent(req)) {
        FileItemFactory fileItemFactory = new DiskFileItemFactory(); // 创建FileItemFactory工厂的实现类,
        // 创建用于解析上传数据的工具类
        ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory); 
        try {
            List<FileItem> list = servletFileUpload.parseRequest(req); // 解析,得到每一个表单项
            for (FileItem fileItem : list) {
                if (fileItem.isFormField()) { // 普通表单项
                    System.out.print("表单项的name属性值:" + fileItem.getFieldName());
                    System.out.println("  表单项的value:" + fileItem.getString("UTF-8"));
                } else { // 文件类型
                    System.out.print("文件的name属性值:" + fileItem.getFieldName());
                    System.out.println("  上传的文件名:" + fileItem.getName());
                    // 一般会保存到用户访问不能直接访问的目录下 File.separator是系统默认路径分隔符,win下是 / 
                    // (下面这是保存到了部署的真是目录下,保存到了服务器中)
                    // 可以用UUID保证文件名的唯一性,防止文件覆盖。
                    // 防止单个目录文件过多影响读写速度,还可以使用目录生成算法分散储存
                    fileItem.write(new File(savePath + File.separator + fileItem.getName()));
                    //fileItem.delete(); //关闭资源
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3. 文件下载

客户端 ->(发送请求告诉服务器我要下载什么文件) -> 服务器

服务器干的内容:

  • 获取要下载的文件名
  • 读取要下载的文件内容
  • 通过响应头告诉客户端返回的数据类型是什么 (和要下载的类型一致)
  • 告诉的客户端收到的数据是用于下载使用(还是用响应头设置)
  • 把下载的的文件内容回传给客户端下载

这个也能用 commons-io-1.4.jar 的IOUtils 类:

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    req.setCharacterEncoding("UTF-8"); // 防止乱码
    resp.setCharacterEncoding("UTF-8");
    //1.获取要下载的文件名路径名,并通过ServletContext读取读取文件
    String downloadFileName = "head.jpg"; // 我们这里写死了
    ServletContext servletContext = getServletContext();
    String savePath = servletContext.getRealPath("/WEB-INF/upload"); //以前上传文件保存的目录
    String downloadPath = savePath + File.separator + downloadFileName;
    //2.告诉客户端返回的类型
    String downloadType = servletContext.getMimeType(downloadPath); //获取要下载文件的类型 (这个是image/jpeg)
    resp.setContentType(downloadType); // (和要下载的类型一样)
    //3.告诉客户端收到的数据是用于下载的,不是直接显示在页面的
    // Content-Disposition表示收到的数据怎么处理,attachment表示附件下载使用,filename表示下载文件的名字
    // filename名可以不和本地的名字一样,当有中文时会乱码,因为http协议设置的的时候不支持中文,需要进行url编码
    /resp.setHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
    resp.setHeader("Content-Disposition", 
                   "attachment;filename=" + URLEncoder.encode(downloadFileName, "UTF-8"));
    InputStream resourceAsStream = servletContext.getResourceAsStream(downloadPath); 
    // getResourceAsStream() 传入文件路径,读取文件!!!!!!!!!!!!!
    // 4.commons-io-1.4.jar中有IOUtils我们可以直接用,不用自己read() write()了
    ServletOutputStream outputStream = resp.getOutputStream(); // 获取响应的输出流
    IOUtils.copy(resourceAsStream, outputStream); 
    // 读取输入流的信息复制给输出流,输出给客户端,传入一个输入流和输出流 (字节字符流都行)
}

到此这篇关于Servlet文件的上传与下载详解的文章就介绍到这了,更多相关Servlet上传下载文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Log4j如何屏蔽某个类的日志打印

    Log4j如何屏蔽某个类的日志打印

    这篇文章主要介绍了Log4j如何屏蔽某个类的日志打印,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • JAVA实现深拷贝的几种方式代码

    JAVA实现深拷贝的几种方式代码

    这篇文章主要给大家介绍了关于JAVA实现深拷贝的几种方式,在Java中深拷贝和浅拷贝是用来复制对象的两种不同方式,深拷贝会对所有数据类型进行拷贝,包括对象所包含的内部对象,需要的朋友可以参考下
    2023-09-09
  • 详解hibernate双向多对多关联映射XML与注解版

    详解hibernate双向多对多关联映射XML与注解版

    本篇文章主要介绍了详解hibernate双向多对多关联映射XML与注解版,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-05-05
  • 解决spring中redistemplate不能用通配符keys查出相应Key的问题

    解决spring中redistemplate不能用通配符keys查出相应Key的问题

    这篇文章主要介绍了解决spring中redistemplate不能用通配符keys查出相应Key的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • Java实现多个数组间的排列组合

    Java实现多个数组间的排列组合

    这篇文章主要为大家详细介绍了Java实现多个数组间的排列组合,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • 详解如何将JAR包发布到Maven中央仓库

    详解如何将JAR包发布到Maven中央仓库

    这篇文章主要介绍了详解如何将JAR包发布到Maven中央仓库,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • 自从在 IDEA 中用了热部署神器 JRebel 之后,开发效率提升了 10(真棒)

    自从在 IDEA 中用了热部署神器 JRebel 之后,开发效率提升了 10(真棒)

    在javaweb开发过程中,使用热部署神器 JRebel可以使class类还是更新spring配置文件都能立马见到效率,本文给大家介绍JRebel的两种安装方法,小编建议使用第二种方法,具体安装步骤跟随小编一起看看吧
    2021-06-06
  • Java replaceAll()方法报错Illegal group reference的解决办法

    Java replaceAll()方法报错Illegal group reference的解决办法

    这篇文章主要给大家介绍了关于Java replaceAll()方法报错Illegal group reference的解决办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • java:程序包org.springframework.boot不存在的完美解决方法

    java:程序包org.springframework.boot不存在的完美解决方法

    最近项目中运行的时候提示了"java: 程序包org.springframework.boot不存在",下面这篇文章主要给大家介绍了关于java:程序包org.springframework.boot不存在的完美解决方法,需要的朋友可以参考下
    2023-05-05
  • JVM GC 垃圾收集梳理总结

    JVM GC 垃圾收集梳理总结

    这篇文章主要介绍了JVM GC 垃圾收集梳理总结,GC是一种自动的存储管理机制。当一些被占用的内存不再需要时,就应该予以释放,这种存储资源管理,称为垃圾回收
    2022-07-07

最新评论