这篇文章主要介绍了Java中的文件批量上传、文件批量下载功能的实现,在开发中,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下


1 :MySql数据库:

1.1 :sftp_file 数据

在这里插入图片描述

1.2:sftp_file 表结构执行创建语句

CREATE TABLE `sftp_file` (
  `file_id` varchar(100) COLLATE utf8mb4_bin NOT NULL COMMENT '文件id',
  `file_name_up` varchar(300) COLLATE utf8mb4_bin NOT NULL COMMENT '文件名称',
  `file_name` varchar(300) COLLATE utf8mb4_bin NOT NULL COMMENT '上传文件名称',
  `file_type` varchar(20) COLLATE utf8mb4_bin NOT NULL COMMENT '文件类型',
  `file_size` varchar(30) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '文件大小 单位:B',
  `server_ip` varchar(300) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '文件服务器地址',
  `file_path` varchar(300) COLLATE utf8mb4_bin NOT NULL COMMENT '文件上传路径',
  `user_id` varchar(50) COLLATE utf8mb4_bin NOT NULL COMMENT '操作用户id',
  `create_time` datetime NOT NULL COMMENT '上传日期',
  PRIMARY KEY (`file_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='附件表';

2 :Controller 批量上传、批量下载 (所有的业务我在Controller 处理的、为了方便大家更直观的阅读代码)

2.1:批量上传文件

代码如下(示例):

import com.jeewechat.wechat.entity.SftpFile;
import com.jeewechat.wechat.mapper.FileMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;

@Api(value = "BatchFilesController", tags = {"文件(附件)信息表"})
@Log4j
@Controller
@RequestMapping("/batchFiles")
public class BatchFilesController {
    @Autowired
    private FileMapper fileMapper;

    /**
     * @param userId 用户ID
     * @param files  文件对象
     * @return java.lang.String
     * @description TODO 批量文件上传
     * @author WangTianLiang
     * @date 2021/5/21
     */
    @ApiOperation("批量文件上传")
    @RequestMapping(value = "batchUploadFile", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> batchUploadFile(@RequestParam("files") MultipartFile[] files, @RequestParam("userId") String userId) {
        Map<String, Object> mapData = new HashMap<>();
        //step 1: 判断校验文件流是否有文件
        if (files == null || files.length <= 0) {
            mapData.put("success", false);//false:成功,false:失败
            mapData.put("msg", "系统未检测到文件流");
            return mapData;
        }
        //step 2: 创建List集合用于存储文件对象
        List<SftpFile> sftpFileList = new ArrayList<>();
        //step 3: 创建List集合用于存储文件ID,返给前端
        List<String> sftpFileIdList = new ArrayList<>();

        for (MultipartFile file : files) {
            //step 4: 封装实例对象
            SftpFile sftpFile = new SftpFile();
            String fileId = SftpFile.createDbId();//随机生产主键ID
            sftpFile.setFileId(fileId);//文件id
            sftpFile.setUserId(userId);//操作用户id
            sftpFile.setCreateTime(new Date());//创建时间

            // 获取原始名字
            String fileNameUp = file.getOriginalFilename();
            sftpFile.setFileNameUp(fileNameUp);//上传文件名称

            sftpFile.setFileName(fileId);//存储文件的名称

            // 获取后缀名
            String suffixType = fileNameUp.substring(fileNameUp.lastIndexOf(".") + 1);
            sftpFile.setFileType(suffixType);//文件类型

            //获得文件大小
            Float size = Float.parseFloat(String.valueOf(file.getSize())) / 1024;
            BigDecimal b = new BigDecimal(size);
            size = b.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
            sftpFile.setFileSize(size.toString());//文件大小(字节单位)

            // 文件保存路径 你还可以在拼接一层路径,例如 20210521 每天上传的都会生成一个新的文件加里
            String filePath = "E://image//";
            sftpFile.setFilePath(filePath);//文件上传路径

            // 文件重命名,防止重复
            String filePathName = filePath + fileId + "." + sftpFile.getFileType();
            //本机ip 静态方法获取InetAddress对象。
            InetAddress ia = null;
            try {
                ia = ia.getLocalHost();// 获取本地主机
                sftpFile.setServerIp(ia.getHostAddress());
            } catch (UnknownHostException e) {
                log.error("文件传输服务器失败:", e);
            }
            //step 5: 创建文件对象
            File dest = new File(filePathName);
            //step 6: 判断路径是否存在,如果不存在则创建
            if (!dest.getParentFile().exists()) {
                dest.getParentFile().mkdirs();
            }

            //step 7: 文件存在,返回
            if (dest.exists()) {
                mapData.put("success", false);//false:成功,false:失败
                mapData.put("msg", "文件已存在,请重新上传" + fileNameUp);
                return mapData;
            }
            try {
                //step 8: 保存到服务器中
                file.transferTo(dest);
                //step 9: 将生产的文件ID 和文件对象分别存入对应的集合
                sftpFileIdList.add(fileId);
                sftpFileList.add(sftpFile);
            } catch (Exception e) {
                log.error("文件传输服务器失败:", e);
            }
        }
        //判断校验存储文件对象集合是否为空、集合长度是否大于0
        if (sftpFileList != null && sftpFileList.size() > 0) {
            //step 10: 批量添加文件对象
            int i = fileMapper.batchInsertFile(sftpFileList);
            //step 11: 判断是否添加成功  存储文件对象的集合长度是否等于数据库执行的条数
            if (sftpFileList.size() == i) {
                mapData.put("success", true);//false:成功,false:失败
                mapData.put("msg", "文件上传成功");
                mapData.put("data", sftpFileIdList);
                return mapData;
            }
        }
        mapData.put("success", false);//false:成功,false:失败
        mapData.put("msg", "文件上传失败");
        return mapData;
    }
}
2.1.1:批量上传文件结果

在这里插入图片描述

2.1.2:spring boot 项目中 appConfig.properties 中加入两个配置参数

配置如下(示例):

#设置单个文件的大小
spring.servlet.multipart.max-file-size=10Mb
#设置单次请求的文件的总大小
spring.servlet.multipart.max-request-size=1000Mb

我在项目中采用配置的是Spring Boot 2.0之后(示图):
在这里插入图片描述

2.2:批量下载文件

代码如下(示例):

import com.jeewechat.wechat.entity.SftpFile;
import com.jeewechat.wechat.mapper.FileMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Api(value = "BatchFilesController", tags = {"文件(附件)信息表"})
@Log4j
@Controller
@RequestMapping("/batchFiles")
public class BatchFilesController {
    @Autowired
    private FileMapper fileMapper;

    /**
     * @param files    文件ID集合
     * @param request  客户端请求对象
     * @param response 服务器响应对象
     * @return void
     * @description TODO 批量下载文件
     * @author WangTianLiang
     * @date 2021/5/21
     */
    @ApiOperation("批量下载文件")
    @RequestMapping(value = "batchDownloadFile", method = RequestMethod.GET)
    public void batchDownloadFile(@RequestBody List<String> files, HttpServletRequest request, HttpServletResponse response) {
        //step 1: 判断校验参数信息是否为空
        if (files == null || files.size() <= 0) {
            return;
        }

        //step 2: 响应头的设置
        response.reset();
        response.setCharacterEncoding("utf-8");
        response.setContentType("multipart/form-data");

        //step 3: 设置压缩包的名字
        String format = new SimpleDateFormat("yyyymmddhhmmsssss").format(new Date());//年+月+日+时+分+秒
        String billname = "压缩文件-" + format;
        String downloadName = billname + ".zip";

        //step 4: 返回客户端浏览器的版本号、类型
        String agent = request.getHeader("USER-AGENT");
        try {
            //step 5: 解决不同浏览器压缩包名字含有中文时乱码的问题
            //针对IE或者以IE为内核的浏览器:
            if (agent.contains("MSIE") || agent.contains("Trident")) {
                downloadName = java.net.URLEncoder.encode(downloadName, "UTF-8");
            } else {
                //非IE浏览器的处理:
                downloadName = new String(downloadName.getBytes("UTF-8"), "ISO-8859-1");
            }
        } catch (Exception e) {
            log.error("中文时乱码的问题处理异常:", e);
        }
        response.setHeader("Content-Disposition", "attachment;fileName=\"" + downloadName + "\"");

        //step 6: 设置压缩流:直接写入response,实现边压缩边下载
        ZipOutputStream zipos = null;
        try {
            zipos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
            zipos.setMethod(ZipOutputStream.DEFLATED); //设置压缩方法
        } catch (Exception e) {
            e.printStackTrace();
        }
        //循环将文件写入压缩流
        DataOutputStream os = null;

        //step 7: 根据文件ID批量查询数据库获取文件信息
        List<SftpFile> fileList = fileMapper.getFilesByIds(files);
        if (fileList == null || fileList.size() <= 0) {
            return;
        }
        //遍历文件信息(主要获取文件名/文件路径等)
        for (SftpFile sftpFile : fileList) {
            //文件路径 E://image//  +  20210521125816942FILE00000000004  +  .  +  PNG
            //拼接后的路径 E://image//20210521125816942FILE00000000004.PNG
            String filePath = sftpFile.getFilePath() + sftpFile.getFileName() + "." + sftpFile.getFileType();

            //step 8: 创建文件对象
            File file = new File(filePath);
            if (!file.exists()) {
                log.info("文件已不存在:" + sftpFile.getFileNameUp());
                continue;
            } else {
                try {
                    //step 9: 添加ZipEntry,并ZipEntry中写入文件流
                    String fileName = sftpFile.getFileNameUp(); //测试图片.PNG
                    zipos.putNextEntry(new ZipEntry(fileName)); //在压缩文件中建立名字为 测试图片.PNG 的文件
                    os = new DataOutputStream(zipos); //创建输出对象
                    InputStream is = new FileInputStream(file);
                    byte[] b = new byte[100];
                    int length = 0;
                    while ((length = is.read(b)) != -1) {
                        os.write(b, 0, length);
                    }
                    is.close();
                    zipos.closeEntry();//方法关闭当前的ZIP条目并定位流以读取下一个条目
                } catch (IOException e) {
                    log.error("ZipEntry写入文件流异常:", e);
                }
            }
        }

        try {
            //清空缓冲区数据
            os.flush();
            //关闭流
            os.close();
            zipos.close();
        } catch (IOException e) {
            log.error("清空关闭流异常:", e);
        }
    }
}
2.2.1:批量下载文件结果

①批量下载,浏览器生成ZIP文件 如下(示图):
在这里插入图片描述
②ZIP文件中的图片文件 如下(示图):
在这里插入图片描述

3 :其它附属代码 Mapper,Mapper.xml 代码如下

项目大致结构如下(如图示例):
在这里插入图片描述

3.1:Mapper:

代码如下(示例):

import com.jeewechat.wechat.entity.SftpFile;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface FileMapper {

    //批量添加文件对象
    int batchInsertFile(@Param("sftpFileList") List<SftpFile> sftpFileList);

    //根据文件ID批量查询文件信息
    List<SftpFile> getFilesByIds(@Param("fileIdList") List<String> fileIdList);
}

3.2 :Mapper.xml:

代码如下(示例):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jeewechat.wechat.mapper.FileMapper">

    <!--批量添加,附件表-->
    <insert id="batchInsertFile" parameterType="java.util.List">
        INSERT into sftp_file
        (file_id,file_name_up,file_name,file_type,file_size,server_ip,file_path,user_id,create_time)
        VALUES
        <foreach item="item" collection="sftpFileList" index="index" separator=",">
            (#{item.fileId,jdbcType=VARCHAR},
            #{item.fileNameUp,jdbcType=VARCHAR},
            #{item.fileName,jdbcType=VARCHAR},
            #{item.fileType,jdbcType=VARCHAR},
            #{item.fileSize,jdbcType=VARCHAR},
            #{item.serverIp,jdbcType=VARCHAR},
            #{item.filePath,jdbcType=VARCHAR},
            #{item.userId,jdbcType=VARCHAR},
            NOW())
        </foreach>
    </insert>
    
    <!--根据文件ID批量查询文件信息-->
    <select id="getFilesByIds" resultType="com.jeewechat.wechat.entity.SftpFile">
        select
        file_id as fileId,file_name_up as fileNameUp,file_name as fileName,
        file_type as fileType,file_size as fileSize,server_ip as serverIp,
        file_path as filePath,user_id asuserId,create_time as createTime
        from sftp_file
        where
        <foreach collection="fileIdList" item="fileId" index="index" open=" file_id IN (" close=")" separator=",">
            #{fileId,jdbcType=VARCHAR}
        </foreach>
        order by
        CREATE_TIME DESC
    </select>
    
</mapper>

希望可以帮助到您…

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐