前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java学习笔记-全栈-web开发-12-文件上传和下载

Java学习笔记-全栈-web开发-12-文件上传和下载

作者头像
devi
发布2021-08-18 15:29:37
3400
发布2021-08-18 15:29:37
举报
文章被收录于专栏:搬砖记录

1. 文件上传

1.1 准备

前提

  • 提供form表单,method必须是POST
  • form表单的enctype必须是multipart/form-data
    • 若使用默认的,则只能获取到文件名
  • 提供input type="file"类的上传输入域

enctype属性

enctype作用:告知服务器请求正文的MIME类型。(请求消息头:与Content-Type作用是一致的)

可选值:

  • application/x-www-form-urlencoded(默认): 正文:username=admin&password=123 服务器获取数据:String username = request.getParameter(“username”);
  • multipart/form-data: 正文:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

服务器获取数据:不能通过request.getParameter(String)方法获取指定的表单字段字符内容,因为文件上传表单已经不在是字符内容,而是字节内容,需要通过IO流获取

1.2 案例 (了解)

html

在这里插入图片描述
在这里插入图片描述

Servlet

在这里插入图片描述
在这里插入图片描述

这种办法获取到的数据会带分割串,处理比较麻烦,因此一般使用第三方包

1.3 fileupload (重点)

1.3.1 简介

fileupload是由apache的commons组件提供的上传组件。 它最主要的工作就是帮我们解析request.getInputStream()。

使用fileupload只需要2个jar包

  • commons-fileupload.jar,核心包;
  • commons-io.jar,依赖包。

fileupload的核心类有:

  • DiskFileItemFactory
  • ServletFileUpload
  • FileItem

1.3.2 解析原理

在这里插入图片描述
在这里插入图片描述

1.3.3 FileItem对象

FileItem对象对应一个表单项(表单字段)。可以是文件字段或普通字段

  • boolean isFormField():判断当前表单字段是否为普通文本字段,如果返回false,说明是文件字段;
  • String getFieldName():获取字段名称,例如:,返回的是username;
  • String getString():获取字段的内容,如果是文件字段,那么获取的是文件内容,当然上传的文件必须是文本文件;
  • String getName():获取文件字段的文件名称;(a.txt)
  • String getContentType():获取上传的文件的MIME类型,例如:text/plain。
  • int getSize():获取上传文件的大小;
  • InputStream getInputStream():获取上传文件对应的输入流;
  • void write(File):把上传的文件保存到指定文件中。
  • delete():删除临时文件

1.3.4 使用fileupload

代码语言:javascript
复制
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet{
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException,IOException {

        //1.判断是否为文件上传表单
        if(ServletFileUpload.isMultipartContent(req)){
            //2.创建个文件工厂
            FileItemFactory factory = new DiskFileItemFactory();
            //3.创建文件上传对象
            ServletFileUpload fileUpload = new ServletFileUpload(factory);

            //4.解析请求
            try{
                List<FileItem> items = fileUpload.parseRequest(req);
                for(FileItem item : items){
                    if(item.isFormField()){//普通表单字段
                        processFormField(item);
                    }else{//文件字段
                        processFile(item);
                    }
                }
            }catch (FileUploadException fue){
                fue.printStackTrace();
            }

        }

    }

    private void processFile(FileItem item) {
        String fieldName = item.getFieldName();
        String fieldValue = item.getString();
        //1.获取文件扩展名
        String suffix = item.getName().split("\\.")[1];
        String saveFileName = UUID.randomUUID().toString() + "." + suffix;
        System.out.println(saveFileName +  ":" + item.getContentType());

        //2.创建文件保存的文件夹
        String folderPath = this.getServletContext().getRealPath("/WEB-INF/upload");//获取项目真实路径
        System.out.println("保存的路径:" + folderPath);
        File file = new File(folderPath);
        if(!file.exists()){
            file.mkdirs();
        }

        //3.保存文件
        //文件完整保存路径
        String filePath = folderPath + "/" + saveFileName;
        try {
            item.write(new File(filePath));
item.delete();//删除临时文件
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void processFormField(FileItem item) {
        String fieldName = item.getFieldName();
        String fieldValue = item.getString();
        System.out.println(fieldName + ":" + fieldValue);
    }
}

1.4 保存路径配置

1.4.1 添加日期目录

在这里插入图片描述
在这里插入图片描述

1.4.2 将日期转换为16进制符

在这里插入图片描述
在这里插入图片描述

上述方法源自视频教学,但是似乎有误。 可能是每个Date对象都有不同的hashCode造成的,改为:将Date赋值给String对象,使用String创建hashcode

1.5 注意事项

1.5.1 中文乱码

表单普通字段乱码用item.getString(“UTF-8”);

文件名乱码可用

在这里插入图片描述
在这里插入图片描述

1.5.2 文件上传大小限制

单个文件大小:

  • ServletFileUpload.setFileSizeMax(字节)
在这里插入图片描述
在这里插入图片描述

总文件大小:(多文件上传)

  • ServletFileUpload.setSizeMax(字节)

1.5.3 临时文件问题

DiskFileItemFactory:

  • 作用:产生FileItem对象
  • 内部有一个缓存,缓存大小默认是10Kb。如果上传的文件超过10Kb,用磁盘作为缓存。

存放缓存文件的目录在哪里? 默认是系统的临时目录。

如果自己用IO流实现的文件上传,要在流关闭后,清理临时文件。 在最后加上FileItem.delete(),删除临时文件

1.6 多文件上传

动态添加

代码语言:javascript
复制
<form action="/UploadServlet"  method="post" enctype="multipart/form-data">
    用户名:<input type="text" name="username" placeholder="请输入用户名"><br>
    密码:<input type="password" name="password" placeholder="请输入密码"><br>
    <div id="div1">
        <div>
            <input type="file" name="photo" /><input type="button" value="添加" onclick="addFile()"/><br />
        </div>
    </div>
    <input type="submit" value="提交">
</form>
代码语言:javascript
复制
<script type="text/javascript">
    function addFile(){
        //得到div容器
        var div1 = document.getElementById("div1");
        div1.innerHTML +=  "<div><input type='file' name='photo' /><input type='button' value='删除' οnclick='delFile(this)'/><br /></div>";
    }

    function delFile(input){
        //使用input对象的爷爷删除他的爸爸
        input.parentNode.parentNode.removeChild(input.parentNode);
    }
</script>

2. 文件下载

2.1 响应头设置

文件下载需要设置两个响应头

  • Content-Disposition attachment;filename=xx.png 以附件形式下载
  • Content-Type application/octet-stream 二进制流

2.2 案例

代码语言:javascript
复制
@WebServlet("/DownloadServlet")
public class DownloadServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        //1.文件下载的位置
		//此处可通过获取客户端参数然后在数据库中查找是否存在文件
        String filePath = "C:/test.jpg";

        //2.文件名
        String fileName = "img.jpg";
        fileName = URLEncoder.encode(fileName,"UTF-8");//中文名文件需要进行URL编码
        //3.设置响应头
        resp.setHeader("Content-Disposition","attachment;filename=" + fileName);
        resp.setContentType("application/octet-stream");

        //4.响应文件
        File file = new File(filePath);
        InputStream is = new FileInputStream(file);
        byte[] bytes = new byte[1024 * 8];
        int len;
        OutputStream os = resp.getOutputStream();
        while((len = is.read(bytes)) != -1){
            os.write(bytes,0,len);
        }

        //5.关闭流
        is.close();
        os.close();
    }
}

3. 总结

实质上,就是IO流的使用 由于文件在网络上通过字节流传输,因此通过字节IO流实现即可

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/12/21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 文件上传
    • 1.1 准备
      • 1.2 案例 (了解)
        • 1.3 fileupload (重点)
          • 1.3.1 简介
          • 1.3.2 解析原理
          • 1.3.3 FileItem对象
          • 1.3.4 使用fileupload
        • 1.4 保存路径配置
          • 1.4.1 添加日期目录
          • 1.4.2 将日期转换为16进制符
        • 1.5 注意事项
          • 1.5.1 中文乱码
          • 1.5.2 文件上传大小限制
          • 1.5.3 临时文件问题
        • 1.6 多文件上传
        • 2. 文件下载
          • 2.1 响应头设置
            • 2.2 案例
            • 3. 总结
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档