SpringBoot项目 文件上传下载

1,015 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

SpringBoot文件管理上传下载思路

原则

首先对于一个后端项目来说文件上传下载相关的处理肯定是不可少的,所以也一定需要进行处理的,关于后端来说一般一个文件上传得有的概念:

  • 文件上传的格式校验 及 文件格式对不对;

  • 文件上传大小校验 及空文件| 超大型文件限制上传;

  • 文件类型校验 及涉及不涉及文件格式更改之后的垃圾文件;

  • 文件存储如果系统使用的的是mysql的话 不能使用数据库直接存储文件数据;

  • 升级: 其实对于文件还有权限一说 这个可以考虑谁能看之类的;

文件上传思路

对于文件上传,一般而言不管你存储设计如何 ,最后只需要将文件保存起来(非直接存储在比如mysql数据库中),然后返回文件业务id 文件名称 之类的数据就ok 了

image.png

{
"fileId":"",
"fileName":""
}

ps: 数据库中需要存储文件的基本信息eg: 文件大小 文件上传人 文件格式 ...

文件直接上传在某一个根路径

拿到文件之后直接存在指定的文件路径下面就行但是由于可能会设计文件重名问题 ,所以对于每一个文件你存好之后可以将原有的文件进行改名称

配合使用其他文件服务器

一般而言配合文件服务器来说: 文件服务器内容会提供相应的api 我们正常使用就行 ,人家会返回类似的文件地址关联路径 好比 fast dfs

简单的文件上传下载代码示例(非外部文件服务器方式)

以下代码: 格式校验 文件大小校验 ...

@ApiOperation(value = "上传单个文件")
@PostMapping("/upload")
public RestResult<FileVO> upload(@RequestPart MultipartFile file) {
    RestResult<FileVO> result = new RestResult<>();
    ArrayList<FileVO> fileList = new ArrayList<>(1);
    //文件类型不匹配
    String type = null;
    assert file != null;
    //格式校验
    if (file.getSize() == 0) {
        result.requestErrorWithMsg(result, FILE_SIZE_ERROR_STRING);
        return result;
    }
    //如果检测出的文件属于篡改的文件不支持上传
    String filename = file.getOriginalFilename();
    assert filename != null;
    String upType = filename.substring(filename.lastIndexOf(FILE_POINT) + 1);
    try {
        InputStream inputStream = file.getInputStream();
        try (BufferedInputStream bis = new BufferedInputStream(inputStream)) {
            AutoDetectParser parser = new AutoDetectParser();
            Detector detector = parser.getDetector();
            Metadata md = new Metadata();
            md.add(Metadata.RESOURCE_NAME_KEY, file.getOriginalFilename());
            MediaType mediaType = detector.detect(bis, md);
            type = TikaUtil.gainType(mediaType.toString(),
                    upType);
        } catch (Exception e) {
            log.error("文件格式校验失败", e);
        }
        inputStream.close();
    } catch (IOException e) {
        log.error("文件流解析失败", e);
    }
    if (!upType.equalsIgnoreCase(type)) {
        result.requestErrorWithMsg(result, FILE_TYPE_ERROR_STRING);
        return result;
    }
    if (StringUtils.isNotBlank(filename)) {
        String uuid = UUID.randomUUID().toString();
        //避免遇见重名文件导致系统错误
        String path = baseFileUploadPath + FILE_SEG + uuid + upType;
        //将文件存储在路径上面
        try {
            FileUtils.byteToFile(file.getBytes(), path);
            //进行真实文件存储
            SystemFileDO fileDO = new SystemFileDO();
            fileDO.setFileName(filename);
            fileDO.setSize(file.getSize());
            fileDO.setPath(path);
            LocalDateTime now = LocalDateTime.now();
            fileDO.setCreateTime(now);
            fileDO.setUpdateTime(LocalDateTime.now());
            Integer integer = systemFileService.saveAndReturnId(fileDO);
            FileVO fileVO = new FileVO();
            fileVO.setFileId(Long.parseLong(integer.toString()));
            fileVO.setFileName(filename);
            fileList.add(fileVO);
        } catch (IOException e) {
            log.error(FILE_UPLOAD_FAIL, e);
            result.requestErrorWithMsg(result, FILE_UPLOAD_FAIL);
            return result;
        }

    }
    result.setData(fileList);
    result.requestOk(result, String.valueOf(fileList.size()));
    return result;
}
@ApiOperation(value = "文件下载")
@GetMapping(value = "/download/{id}")
public void download(HttpServletResponse response, HttpServletRequest request, @PathVariable Long id) {
    SystemFileDO one = systemFileService.getById(id);
    if (null != one) {
        try {
            File file = new File(one.getPath());
            HttpResponseUtil.toWep(response, request, file,one.getFileName());
        } catch (IOException e) {
            log.error("文件读取失败", e);
        }
    }
}
/**
 * 用于excel 导出 转换给前端处理
 *
 * @param response xx
 * @param newFile  xx
 * @throws IOException xx
 */
public static void toWep(HttpServletResponse response, HttpServletRequest request, File newFile, String fileName) throws IOException {
    InputStream fis = new BufferedInputStream(new FileInputStream(newFile));
    byte[] buffer = new byte[fis.available()];
    fis.read(buffer);
    fis.close();
    // 先去掉文件名称中的空格,然后转换编码格式为utf-8,保证不出现乱码,这个文件名称用于浏览器的下载框中自动显示的文件名
    String userAgent = request.getHeader("user-agent").toLowerCase();
    userAgent = userAgent.toLowerCase();
    if (userAgent.contains("msie") || userAgent.contains("trident") || userAgent.contains("like gecko")) {
        // win10 ie edge 浏览器 和其他系统的ie
        fileName = URLEncoder.encode(fileName, "UTF-8");
    } else {
        // fe
        fileName = new String(fileName.getBytes("utf-8"), "iso-8859-1");
    }
    // 先去掉文件名称中的空格,然后转换编码格式为utf-8,保证不出现乱码,这个文件名称用于浏览器的下载框中自动显示的文件名
    response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
    response.addHeader("Content-Length", "" + newFile.length());
    OutputStream os = new BufferedOutputStream(response.getOutputStream());
    response.setContentType("application/octet-stream");
    os.write(buffer);
    os.flush();
    os.close();
}

END

基本的来说: 一个文件 API 大概率会存在 4接口 单个上传 ,批量上传 ,单个下载 ,批量下载;对于服务大的微服务系统来说还有很多文件相关的处理需求,解析word ,生成word 之类的....

本文结束 : 祝看见这篇半水不水的文章的 xdm 儿童节快乐!!!

image.png