【JavaWeb】文件的上传和下载

目录

一、实现文件上传注意:

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

commons 常用API:

源码实现文件上传:

1.注意事项:

2.前端组件:

3.实现步骤:

导入Maven坐标:

 运行结果:

三、文件下载解析:

1.文件下载源码实现:

2.Base64 编码和解码操作:


一、实现文件上传注意:

  • 提交时,前端使用form标签,method=post请求
  • form标签的encType属性值必须为:multipart/form-data值
  • form标签中使用 input type=file 添加文件上传
  • 编写服务器代码接收(Servlet程序),处理上传的数据

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


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

        commons-fileupload.jar 需要依赖commons-io.jar 这个包,所以两个包都需要在项目中引入!

commons 常用API:

  • ServletFileUpload类,用于解析上传的数据
    • boolean ServletFileUpload.isMultipartContent(HttpServletRequest request):判断当前上传的数据格式是否是多段的格式。
    • public List<Fileltem> parseRequest(HttpservletRequest request):解析上传的数据
  • Fileitem类:表示每一个表单项
    • boolean FileItem·isFormField():判断当前这个表单项,是否是普通的表单项。还是上传的文件类型        true表示普通类型的表单项        false表示上传的文件类型
    • String FileItem·getFieldName():获取表单项的name属性值
    • String FileItem.getString():获取当前表单项的值。
    • String FileItem.getName():获取上传的文件名
    • void FileItem.write(file):将上传的文件写到参数file所指向的硬盘位置

源码实现文件上传:

1.注意事项:

  • 为保证服务器安全,上传文件应当保存在外界无法直接访问的路径(如 WEB-INF 目录下)
  • 为防止文件覆盖,要为上传的文件生成一个唯一的文件名(如-时间戳,-uuid,-md5,-位运算算法)
  • 要限制上传文件的大小的最大值。
  • 可以限制上传文件的类型,在获取上传文件名时,判断后缀名是否合法。

2.前端组件:

        浏览器处理上传文件,是将文件以的形式提交到服务器端。

  • commons-fileuploadApache 的文件上传组件,取代原生的文件上传流。
  • commons-iocommons-fileupload 组件依赖于该组件。

from表单:

  • 提交方式method=“post”(post传送的数据量大,可视为不受限制)
  • 编码类型enctype="multipart/form-data"(表单包含文件上传控件时必须使用)
    • enctype 属性
      • application/x-www=form-urlencoded:默认方式,只处理表单域中的 value 属性值,将表单域中的值处理成 URL 编码方式;
      • multipart/form-data:以二进制流的方式处理表单数据,除了表单域中的 value 属性值,还会处理表单域的文件内容,将其封装到请求参数中,不会对字符编码;
      • text/plain:将空格转换为+号,其它字符不做编码处理,适用于通过表单发送邮件。

input输入框:

  • 类型type=“file”

  • 属性:要求具有 name 属性

3.实现步骤:

  1. 判断表单:是否包含文件上传控件。
  2. 创建上传文件和临时文件的保存路径
  3. 创建 DiskFileItemFactory 对象。
    • 设置临时文件夹
    • *设置缓冲区大小
  4. 创建 ServletFileUpload 对象
    • 设置 FileItemFactory
    • *监听文件上传进度、处理乱码问题、设置单个文件和总共上传文件的最大值
  5. 解析请求并处理文件传输
    • 解析前端请求,将每个表单项解析并封装成 FileItem 对象
    • 判断表单项是否为上传文件
    • 处理普通文本:
      • 获取字段名
      • 获取数据流内容
    • 处理文件:
      • 获取上传文件名
      • 生成随机 UUID 作为文件存储路径,并为其生成文件夹
      • 通过 IO 流传输文件

导入Maven坐标:

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>
public class FileServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 判断表单是否包含文件上传控件
        if (!ServletFileUpload.isMultipartContent(req)) { // 不包含文件上传控件,即普通表单
            return;
        }

        // 创建上传文件的保存路径:外界无法直接访问
        String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
        File uploadFile = new File(uploadPath);
        makeDirIfNotExist(uploadFile);

        // 创建临时文件的保存路径
        String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
        File tmpFile = new File(tmpPath);
        makeDirIfNotExist(tmpFile);

        // 1、创建DiskFileItemFactory对象
        DiskFileItemFactory factory = getDiskFileItemFactory(tmpFile);
        // 2、创建ServletFileUpload对象
        ServletFileUpload servletFileUpload = getServletFileUpload(factory);
        // 3、解析请求并处理文件传输
        String msg = "";
        try {
            msg = uploadParseRequest(req, servletFileUpload, uploadPath);
        } catch (FileUploadException e) {
            e.printStackTrace();
        }

        req.setAttribute("msg", msg);
        req.getRequestDispatcher("/success.jsp").forward(req, resp);
    }


    private String uploadParseRequest(HttpServletRequest httpServletRequest, ServletFileUpload servletFileUpload, String uploadPath)
            throws FileUploadException, IOException {
        String msg = "";

        // 解析前端请求,将每个表单项解析并封装成FileItem对象
        List<FileItem> fileItems = servletFileUpload.parseRequest(httpServletRequest);
        for (FileItem fileItem : fileItems) {
            // 判断表单项是否为上传文件
            if (fileItem.isFormField()) { // 普通文本
                String filedName = fileItem.getFieldName(); // 获取字段名:表单项name属性的值
                String value = fileItem.getString("UTF-8"); // FileItem对象中保存的数据流内容:即表单项为普通文本的输入值
                System.out.println(filedName + ":" + value);
            } else { // 上传文件
                // ------------------------1、处理文件------------------------


                String uploadFileName = fileItem.getName();// 上传文件名
                System.out.println("上传的文件名:" + uploadFileName);

                if (uploadFileName == null || uploadFileName.trim().equals("")) { // 文件名为空值或空
                    continue; // 进入下一轮循环,判断下一个FileItem对象
                }

                String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1); // 文件后缀名
                System.out.println("文件信息【文件名:" + uploadFileName + ",文件类型:" + fileExtName + "】");

                // 使用UUID保证文件名唯一
                String uuidPath = UUID.randomUUID().toString();

                // ------------------------2、处理路径------------------------

                // 存储路径:uploadPath
                String realPath = uploadPath + '/' + uuidPath; // 真实存在的路径
                // 给每个文件创建一个文件夹
                File realPathFile = new File(realPath);
                makeDirIfNotExist(realPathFile);

                // ------------------------3、文件传输------------------------

                // 获得输入流
                InputStream is = fileItem.getInputStream();
                // 获得输出流
                FileOutputStream fos = new FileOutputStream(realPathFile + "/" + uploadFileName);
                // 创建缓冲区
                byte[] buffer = new byte[1024];

                int len;
                while ((len = is.read(buffer)) > 0) {
                    fos.write(buffer, 0, len);
                }
                msg = "文件上传成功!";

                fileItem.delete(); // 上传成功,清除临时文件

                fos.close();
                is.close();
            }
        }

        return msg;
    }


    private ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
        // ServletFileUpload servletFileUpload = new ServletFileUpload(factory); // 构造方法设置FileItemFactory

        ServletFileUpload servletFileUpload = new ServletFileUpload();
        servletFileUpload.setFileItemFactory(factory); // 设置FileItemFactory

        // ------------------------辅助功能------------------------
        // 监听文件上传进度
        servletFileUpload.setProgressListener(new ProgressListener() {
            /**
             *
             * @param pBytesRead      已读取的文件大小
             * @param pContentLength  文件大小
             * @param pItems
             */
            @Override
            public void update(long pBytesRead, long pContentLength, int pItems) {
                String percentage = (int) (((double) pBytesRead / pContentLength) * 100) + "%";
                System.out.println("总大小:" + pContentLength + ",已上传:" + pBytesRead + "\t" + percentage);
            }
        });
        // 处理乱码问题
        servletFileUpload.setHeaderEncoding("UTF-8");
        // 设置单个上传文件的最大值
        servletFileUpload.setFileSizeMax(1024 * 1024 * 10); // 10M
        // 设置总共上传文件的最大值
        servletFileUpload.setSizeMax(1024 * 1024 * 10); // 10M

        return servletFileUpload;
    }

    /**
     * 获得磁盘文件项目工程,设置缓冲文件夹及缓冲区大小
     *
     * @param tmpFile 缓冲文件夹
     * @return
     */
    private DiskFileItemFactory getDiskFileItemFactory(File tmpFile) {
        // return new DiskFileItemFactory(1024 * 1024, tmpFile);

        DiskFileItemFactory factory = new DiskFileItemFactory();

        // ------------------------辅助功能------------------------
        factory.setSizeThreshold(1024 * 1024); // 1M(缓冲区大小):上传文件大于缓冲区大小时,fileupload组件将使用临时文件缓存上传文件
        factory.setRepository(tmpFile); // 临时文件夹
        return factory;
    }

    /**
     * 如果文件目录不存在,为其创建目录
     *
     * @param file
     */
    private void makeDirIfNotExist(File file) {
        if (!file.exists()) {
            file.mkdir();
        }
    }
}

 运行结果:

        上传的文件会保存在 Target 目录下对应项目的保存路径下。

         非临时文件:

  • 保存在 upload 文件夹下。
  • 文件格式和文件名与上传文件完全相同。
  • 每个文件存储在一个子文件夹中,文件夹名是随机生成的 UUID

        临时文件:

  • 保存在 upload 文件夹下,同时在tmp文件夹下生成一个临时文件。
  • upload 文件夹下的文件:文件格式和文件名与上传文件完全相同。
  • tmp 文件夹下的文件:tmp 格式,文件名是随机生成的 UUID,在 Servlet 运行到 fileItem.delete() 方法时被清除。、


三、文件下载解析:

1.文件下载源码实现:

        资源位置保存在web目录下的file文件目录!

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 下载的文件
        // 以’/'开头则是从工程路径下获取。
        String file = "/file/computer.png";
        // 获取下载的文件内容
        ServletContext servletContext = getServletContext();
        // 获取要下载文件的文件类型
        String mimeType = servletContext.getMimeType(file);
        // 通过响应头告诉客户端返回的数据类型
        resp.setContentType(mimeType);
         // 告诉客户端收到的数据适用于下载的
        // Content-Disposition表示收到的数据怎么处理
        // attachment表示下载使用,filename=文件名 表示指定下载文件的文件名
        // encode避免文件名为中文出现乱码
        resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.substring(file.lastIndexOf('/') + 1),"UTF-8"));
        // 获取需下载的文件的输入流
        InputStream inputstream = servletContext.getResourceAsStream(file);
        // 获取响应的输出流
        ServletOutputStream outputStream = resp.getOutputStream();
        // 输入流的数据复制给输出流,输出给客户端
        // org.apache.commons.io的工具类
        IOUtils.copy(inputstream, outputStream);

    }

        注意:getResourceAsStream 读取的文件路径只局限与工程的源文件夹中,但是如果配置文件路径是在除了源文件夹之外的其他文件夹中时,该方法是用不了的。

        如果省去了 resp.setHeader() 这行代码,图片会直接在该网页上显示

2.Base64 编码和解码操作:

final Base64.Decoder decoder = Base64.getDecoder();
final Base64.Encoder encoder = Base64.getEncoder();
final String text = "字串文字";
final byte[] textByte = text.getBytes("UTF-8");

//编码
final String encodedText = encoder.encodeToString(textByte);
System.out.println(encodedText);

//解码
System.out.println(new String(decoder.decode(encodedText), "UTF-8"));

final Base64.Decoder decoder = Base64.getDecoder();
final Base64.Encoder encoder = Base64.getEncoder();
final String text = "字串文字";
final byte[] textByte = text.getBytes("UTF-8");

//编码
final String encodedText = encoder.encodeToString(textByte);
System.out.println(encodedText);

//解码
System.out.println(new String(decoder.decode(encodedText), "UTF-8"));


  • 12
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃糖的范同学

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值