文件上传与文件下载

文章详细介绍了在Java中如何实现文件上传和下载的功能。当有文件服务器时,可以直接调用接口,否则需手动编写上传和下载接口,将文件存储在服务器指定路径。文中提供了Controller和Service层的代码示例,利用Hutool库处理文件流,并强调了文件路径配置和下载时的响应头设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文件上传与文件下载
在开发中项目难免会遇到文件上传和下载的情况,如果公司有部署文件服务器是再好不过啦,直接调用文件服务器上传和下载的接口,保留返回的文件id即可。
但是如果公司没有文件服务器就比较苦逼了,得手写文件上传和下载的接口把文件存储在服务器的某个位置,以便使用。
直接把代码贴出来以供记录笔记。
首先配置文件定义服务器文件存储路径

uploadfile.extendedstorageperiod.path=/home/szfmimp/uploadfiles/extendedstorageperiod
uploadfile.wzk.path=/home/szfmimp/uploadfiles/wzk
uploadfile.annualappraisal.path=/home/szfmimp/uploadfiles/annualappraisal
uploadfile.emergencydrill.path=/home/szfmimp/uploadfiles/emergencydrill
uploadfile.wzkreservegoal.path=/home/szfmimp/uploadfiles/wzkreservegoal

类似于这样,自己定义路径,这里仅做展示用。
然后定义文件类型枚举,自定义文件支持格式及大小

@Getter
@AllArgsConstructor
public enum FileTypeEnum {

    /**
     *
     */
    INSPECTION_PLAN_ZMWJ("inspection_plan_zmwj", Collections.singletonList("pdf"), 40L, "uploadfile.inspectionplan.path"),

    /**
     * 
     */
    INSPECTION_PLAN_ZMCL("inspection_plan_jczmcl", Arrays.asList("jpg", "png", "doc", "docx", "xls", "xlsx", "pdf"), 10L, "uploadfile.inspectionplan.path"),

    /**
     *
     */
    INSPECTION_PLAN_FJXX("inspection_plan_wjxx", Arrays.asList("jpg", "doc", "docx", "xls", "xlsx", "pdf"), 10L, "uploadfile.inspectionplan.path"),

    /**
     * 
     */
    USER_FEEDBACK_MECHANISM("user_feedback_cl", Arrays.asList("jpg", "png", "doc", "docx", "xls", "xlsx", "pdf"), 10L, "uploadfile.userfeedback.path"),

    /**
     * 
     */
    T_STOCK_AlARM("T_STOCK_AlARM", Arrays.asList("jpg", "png", "doc", "docx", "xls", "xlsx", "pdf"), 10L, "uploadfile.extendedstorageperiod.path"),

    /**
     * 
     */
    EXTENDED_STORAGE_PERIOD("extended_storage_period", Arrays.asList("doc", "docx", "xls", "xlsx", "pdf", "zip"), 10L, "uploadfile.extendedstorageperiod.path"),

    /**
     * 
     */
    WZK("wzk", Arrays.asList("doc", "docx", "xls", "xlsx", "pdf", "png", "jpg"), 10L, "uploadfile.wzk.path"),

    /**
     * 
     */
    ANNUAL_APPRAISAL("annual_appraisal", Arrays.asList("doc", "docx", "xls", "xlsx", "pdf", "png", "jpg"), 10L, "uploadfile.annualappraisal.path"),

    /**
     * 
     */
    WZK_RESERVE_GOAL("wzk_reserve_goal", Arrays.asList("doc", "docx", "xls", "xlsx", "pdf", "png", "jpg"), 10L, "uploadfile.wzkreservegoal.path"),
    /**
     * 
     */
    emergency_drill("emergency_drill", Arrays.asList("jpg", "png", "pdf", "zip"), 30L, "uploadfile.emergencydrill.path");

    /**
     * 枚举值
     */
    private final String value;

    /**
     * 允许上传的文件类型
     */
    private final List<String> fileTypes;

    /**
     * 最大文件大小(单位:M)
     */
    private final Long fileSize;

    /**
     * 文件保存路径
     */
    private final String savePath;

    public static FileTypeEnum getByValue(String value) {
        for (FileTypeEnum fileTypeEnum : FileTypeEnum.values()) {
            if (fileTypeEnum.value.equals(value)) {
                return fileTypeEnum;
            }
        }
        return null;
    }

}
然后controller层
	@Resource
    private FileService fileService;
	//从配置文件读取保存路径
	@Autowired
    private Environment environment;

@ApiOperation(value = "文件上传")
    @PostMapping("/uploadFile/{fileType}")
    public SwaggerAjaxResult<FileVO> uploadFile(@RequestParam("file") MultipartFile file, @PathVariable String fileType) {
        FileTypeEnum fileTypeEnum = FileTypeEnum.getByValue(fileType);
        if (fileTypeEnum == null) {
            return SwaggerAjaxResult.error(null, "文件类型错误");
        }
        String savePath = environment.getProperty(fileTypeEnum.getSavePath());
        if (StringUtils.isBlank(savePath)) {
            return SwaggerAjaxResult.error(null, "未找到文件存储路径");
        }
        return SwaggerAjaxResult.success(fileService.saveFile(file, fileTypeEnum.getFileTypes(), savePath, fileTypeEnum.getFileSize()));
    }

然后服务层

@Override
    public FileVO saveFile(MultipartFile uploadFile, List<String> fileTypeList, String savePath, long fileSize) {
        log.info("============== 保存上传文件接口 start ==============");
        log.info("上传文件保存的路径为:{}", savePath);
        Set<String> fileTypeSet = new HashSet<>(fileTypeList);
        log.info("上传文件允许的类型为:{}", JSONUtil.toJsonStr(fileTypeSet));
        Assert.isTrue(!uploadFile.isEmpty(), "文件不能为空");
        long uploadFileSize = uploadFile.getSize();
        if (uploadFileSize > (fileSize * 1024 * 1024)) {
            log.info("上传文件的大小超过允许上传的大小");
            Assert.isTrue(false, "上传文件的大小超过允许上传的大小:" + fileSize + "M");
        }

        String fileName = uploadFile.getOriginalFilename();
        log.info("上传文件的文件名为:{}", fileName);
        Assert.isTrue(StringUtils.isNotEmpty(fileName), "上传文件的名称不能为空");
        Assert.isTrue(fileName.length() <= 50, "上传文件名的长度不能超过50");

        String suffix = fileName.substring(fileName.lastIndexOf('.'));
        Assert.isTrue(suffix.length() > 1, "上传文件的扩展名为空");
        String extName = suffix.substring(1);
        log.info("上传文件的扩展名为:{}", extName);

        // 先判断文件名的扩展名是否符合要求
        Assert.isTrue(fileTypeSet.contains(extName), "上传的文件类型不允许,上传失败");
        String type = "";
        try {
            // 再根据文件流的头部信息获得文件类型
            type = FileTypeUtil.getType(uploadFile.getInputStream(), fileName);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        // 如果允许上传的文件类型包含docx和xlsx,fileTypeSet添加zip类型
        // 因为xlsx、docx本质上是各种XML打包为zip的结果,因此会被识别为zip格式
        if (fileTypeSet.contains("docx") || fileTypeSet.contains("xlsx")) {
            fileTypeSet.add("zip");
        }
        // 判断根据文件流的头部信息获得的文件类型是否符合要求
        Assert.isTrue(fileTypeSet.contains(type), "上传文件的真实文件类型不是允许上传的文件类型,上传失败");

        String id = SecureUtil.md5(fileName + System.currentTimeMillis());
        String saveName = id + suffix;
        log.info("上传文件保存的文件名为:{}", saveName);
        Assert.isTrue(StringUtils.isNotEmpty(savePath), "文件保存路径不能为空");
        String today = DateUtil.format(new Date(), "yyyy-MM-dd");
        String fileLink = savePath + File.separator + today + File.separator + saveName;

        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            log.info("保存上传附件的路径:{}", fileLink);
            File targetFile = new File(fileLink);

            if (!targetFile.getParentFile().exists()) {
                targetFile.getParentFile().mkdirs();
            }
            inputStream = uploadFile.getInputStream();
            outputStream = new FileOutputStream(targetFile);
            FileCopyUtils.copy(inputStream, outputStream);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("保存上传附件出错,错误原因:" + e.getMessage());
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }

        TFile entity = new TFile();
        Date date = new Date();
        entity.setId(id);
        entity.setFileName(fileName);
        entity.setSaveName(saveName);
        entity.setSavePath(savePath);
        entity.setFileLink(fileLink);
        entity.setExtName(extName);
        SysUser sysUser = tenantService.getLoginUser().getSysUser();
        entity.setCreateBy(sysUser.getNickName());
        entity.setCreateTime(date);
        log.info("保存上传文件的记录:{}", JSONUtil.toJsonStr(entity));
        save(entity);
        FileVO vo = new FileVO();
        vo.setId(id);
        vo.setFileName(fileName);
        vo.setCreateTime(date);
        vo.setCreateBy(sysUser.getNickName());
        log.info("上传文件保存成功");
        log.info("============== 保存上传文件接口 end ==============");
        return vo;
    }

注:需要注意的是 获取完整文件路径方法中的 uploadFilePath :是文件将要保存在服务器中的位置路径,可以在配置文件中配置好后引用。最后把返回的信息存在在表中使用。整个文件上传就完成了。其中用到了hutool的第三方包我使用的版本为5.8.6

	<dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-core</artifactId>
                <version>5.8.6</version>
            </dependency>
            <!--io常用工具类 -->
			<dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.11.0</version>
            </dependency>

文件下载

这个就没有什么好说的了,比较简单,就是流的操作而已。传入的参数为文件上传是保存的文件的id即可。

	@ApiOperation(value = "通过文件id下载文件")
    @PostMapping("/downloadById")
    public void downloadFileById(HttpServletRequest request, HttpServletResponse response, @RequestBody @Valid IdDTO idDTO) {
        String id = idDTO.getId();
        Assert.isTrue(StringUtils.isNotEmpty(id), "主表id不能为空");
        TFile tFile = fileService.getById(id);
        Assert.notNull(tFile, "要下载的文件不存在");
        String fileName = tFile.getFileName();
        request.getSession();

        //获取页面输出流
        try (ServletOutputStream out = response.getOutputStream()) {
            String path = tFile.getFileLink();
            File file = new File(path);
            byte[] bytes = FileUtils.readFileToByteArray(file);

            // 设置响应头
            response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");
            response.addHeader("Pargam", "no-cache");
            response.addHeader("Cache-Control", "no-cache");

            out.write(bytes);
            out.flush();
        } catch (IOException e) {
            log.error(e.getMessage());
            throw new RuntimeException("下载文件出错");
        }
    }

学习笔记仅供参考!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值