【文件上传和下载教科书】JavaWeb文件上传和下载技术总结

前言

抽出时间,我会将文章系统的整理到GitHub上。目前已经整理好了JavaSE阶段的知识章节内容。我会持续的向GitHub中添加各类知识点。欢迎大家来我的GitHub查房!还请客官们给一个Star!GitHub中有我微信,可以添加我微信,我们在学习交流群中不见不散!
GitHub地址:https://github.com/Ziphtracks/JavaLearningmanual

一、文件上传

1.1 文件上传的核心思想

将电脑中的本地文件根据网络协议并通过IO流的读写传递到另一台电脑(服务器)中储存!

1.2 文件上传中JSP的三要素
  • 表单提交方式必须是post(method=post)
    • 原因get提交方式只能提交小文件,而给文件上传做了很大的限制;post可以提交大文件
  • 表单中需要文件上传项(<input type=“file”>)
    • 既然要实现文件上传,那么就需要文件上传按钮和上传文件框
  • 表单设置请求体格式(enctype=multipart/form-data)
    • 设置表单的MIME编码。默认情况编码格式是application/x-www-form-urlencoded,不能用于文件上传。只有设置了multipart/form-data,才能完整的传递文件数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件上传</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data">
    文件描述:<input type="text" name="description"><br>
    <input type="file" name="file"><br>
    <br>
    <button type="submit">上传</button>
</form>
</body>
</html>
1.3 上传文件核心jar包

此jar包可以自行下载,也可以在我的github中下载,我在github上的中也整理出来的jar包库!

  1. commons-fileupload-1.4.jar

  2. commons-io-2.6.jar

1.4 文件上传的细节处理
1.4.1 文件名重复覆盖问题

为了防止客户端传向服务器的文件名称一致发生文件的覆盖,我们需要将文件名称唯一化!

// 文件名称保证唯一性(文件名称 = 当前时间毫秒值 + 文件名称)
fileName = System.currentTimeMillis() + "-" + fileItem.getName();
1.4.2 使用目录分离算法存储文件

为了防止将大量文件存储在服务器的一个文件夹中,我们需要目录使用Hash的目录分离算法来存储文件(类似给存储文件的文件夹做了负载均衡)

注意:在后面的没有使用该工具类实现,而且嵌入到了Servlet中

image-20200507220349958

package com.mylifes1110.java.utils;

import java.io.File;

/**
 * 目录分离算法
 */
public class UploadUtils {
   

    // 为防止一个目录下文件过多,使用hash算法打散目录
    public static String newFilePath(String basePath, String fileName) {
   

        // 获取文件hash码
        int hashCode = fileName.hashCode();

        // 使用hash码进行与运算并生成二级目录
        int path2 = hashCode & 15;

        // 使用hash码进行与运算并生成三级目录
        int path3 = (hashCode >> 4) & 15;

        // 将一级、二级、三级目录拼接并生成完整目录路径
        String path = basePath + File.separator + path2 + File.separator + path3;
        File   file = new File(path);

        // 创建Hash打散后的多级目录
        if (!file.exists()) {
   
            file.mkdirs();
        }

        // 返回完整目录路径
        return path;
    }
}
1.4.3 文件上传jar包API

ServletFileUpload:核心解析类

方法 描述
parseRequest(HttpServletRequest request) 解析请求,并获取相关文件项
setHeaderEncoding(String encoding) 解决中文文件名乱码

FileItem:文件项

方法 描述
boolean isFormField() 返回为true为普通字段。返回为false为文件
String getFieldName() 获取表单字段
String getString(String encoding) 根据指定编码格式获取字段值
String getName() 获取上传文件名称
InputStream getInputStream() 获取上传文件对应的输入流

二、文件下载

2.1 文件下载的核心思想

将服务器中的文件根据网络协议并通过IO流读取传递到另外一台电脑中并储存!

2.2 文件下载的两种格式
  • 超链接
    • 如果浏览器支持这个格式的文件.可以在浏览器中打开.如果浏览器不支持这个格式的文 件才会提示下载
  • 手动编写代码的方式下载
2.3 手动编写代码方式的三要素
  • 设置响应对象的媒体类型
  • 设置下载窗口
    • 设置下载窗口是通过响应对象对响应头的操作(“Content-Disposition”)
  • IO流读写文件
2.4 文件下载的细节处理
2.4.1 解决下载文件后名称中文乱码问题

各种浏览器的编码解码都是不同的,所以不同的浏览器对文件名称的编码方式不同,我们要以Google浏览器为代表的是以utf-8对文件名称进行编码,其他的一些浏览器以base64对文件名称进行编码,这就需要判断响应头中使用的浏览器的类型(User-Agent)

/**
 * base64编码
 *
 * @param fileName 文件名称
 * @return 返回一个处理编码后的文件名称
 */
public String base64EncodeFileName(String fileName) {
   
    BASE64Encoder base64Encoder = new BASE64Encoder();

    try {
   
        return "=?UTF‐8?B?" + new String(base64Encoder.encode(fileName.getBytes("utf-8"))) + "?=";
    } catch (Exception e) {
   
        e.printStackTrace();

        throw new RuntimeException(e);
    }
}
		/**
         * 不同的浏览器对文件名称的编码方式不同,以google浏览器为代表的是以utf-8对文件名称进行编码
         * 其他的一些浏览器以base64对文件名称进行编码
         * 判断使用的浏览器的类型User-Agent
         */
        String userAgent   = request.getHeader("User-Agent");
        String newFileName = null;

        if (userAgent.contains("Chrome")) {
   

            // Google浏览器以utf-8进行编码
            newFileName = URLEncoder.encode(fileName, "utf-8");
        } else {
   

            // 其他浏览器以base64进行编码
            newFileName = base64EncodeFileName(fileName);
        }

        // Google浏览器:new String(fileName.getBytes("utf-8"), "ISO8859-1")
        // 注释中的Google浏览器的代码只针对Google浏览器,不具有普适性!
        // response.setHeader("Content-Disposition", "attachement;filename=" + new String(fileName.getBytes("utf-8"), "ISO8859-1"));
        response.setHeader("Content-Disposition", "attachement;filename=" + newFileName);

三、文件上传和下载案例

3.1 项目结构

image-20200507222126581

3.4 项目所用jar包

image-20200507222303518

3.3 项目代码演示
库表操作
create table tb_uploadfiles
(
    id          int auto_increment
        primary key,
    fileName    varchar(200) null,
    filePath    varchar(200) null,
    description varchar(200) null
);
c3p0.properties文件
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/temp?useUnicode=true&characterEncoding=utf-8
c3p0.user=root
c3p0.password=123456
c3p0连接池工具类
package com.mylifes1110.java.utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class DBUtils {
   
    private static ComboPooledDataSource dataSource;

    static {
   
        dataSource = new ComboPooledDataSource();
    }

    public static ComboPooledDataSource getDataSource() {
   
        return dataSource;
    }
}
Files实体类
package com.mylifes1110.java.bean;

public class Files {
   
    private Integer id;
    private String  fileName;
    private String  filePath;
    private String  description;

    public Files() {
   }

    public Files(Integer id, String fileName, String filePath, String description) {
   
        this.id          = id;
        this.fileName    = fileName;
        this.filePath    = filePath;
        this.description = description;
    }

    @Override
    public String toString() {
   
        return "Files{&#
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值