Bootstrap

Spring Boot文件上传、下载、删除【代码分享+小坑】

话不多说,直接上代码

数据库(mysql)
create table uploaded_files
(
    file_id     int auto_increment comment '文件的唯一标识符'
        primary key,
    file_name   varchar(255)                        not null comment '上传的文件名',
    upload_date timestamp default CURRENT_TIMESTAMP null comment '文件上传的日期和时间,默认值为当前时间',
    file_path   varchar(255)                        not null comment '文件在服务器上的存储路径',
    file_type   varchar(255)                        null comment '文件类型'
)
    comment '用于存储上传文件信息的表' row_format = DYNAMIC;

controller层
public class UploadFileController {
    @Resource
    private UploadFileService uploadFileService;

   
    @PostMapping("/uploadFiles")
    @Operation(summary = "文件上传")
    public AjaxResult aptitudeVOImage(@Parameter(description = "文件", required = true)
                                      @RequestParam("fileData") MultipartFile fileData) {
        return uploadFileService.uploadFiles(fileData);
    }

   
    @Operation(summary = "删除文件")
    @PostMapping("/delete")
    public AjaxResult delete(@RequestBody IdDTO idDTO) {
        return uploadFileService.delete(idDTO);
    }

    
    @GetMapping("/eclipseFile")
    @Operation(summary = "文件下载")
    public void eclipseFile(Integer id, HttpServletResponse response) {
        uploadFileService.eclipseFile(id, response);
    }
}
service层
public interface UploadFileService extends IService<UploadedFiles>  {

    /*
    文件上传
     */
    AjaxResult uploadFiles(MultipartFile fileData);

    /*
    删除文件
     */
    AjaxResult delete(IdDTO idDTO);

    /*
    下载文件
     */
    void eclipseFile(Integer id, HttpServletResponse response);
}
实现类
public class UploadFileServiceImpl extends ServiceImpl<UploadFileMapper, UploadedFiles> implements UploadFileService {

    @Resource
    UploadFileMapper uploadFileMapper;

    @Override
    public AjaxResult uploadFiles(MultipartFile fileData) {
        String originalFilename = fileData.getOriginalFilename();
        // 获取文件扩展名
        assert originalFilename != null;
        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
        // 生成随机文件名,结合UUID和当前时间
        String randomFileName = UUID.randomUUID() + "_" + System.currentTimeMillis() + fileExtension;
        // 将文件数据存储到文件夹内
        String filePath = saveFileToProjectFolder(fileData, randomFileName);
        //正则表达式删除引号
        String folderPathWithoutQuotes = filePath.replaceAll("", "");
        UploadedFiles uploadedFiles = new UploadedFiles();
        uploadedFiles.setFileName(originalFilename);
        uploadedFiles.setFilePath(folderPathWithoutQuotes);
        uploadedFiles.setFileType(fileExtension);
        uploadedFiles.setUploadDate(LocalDateTime.now());
        uploadFileMapper.insert(uploadedFiles);
        return AjaxResult.success("上传成功", uploadedFiles);
    }

    /*
    将文件数据存储到文件夹内
     */
    private String saveFileToProjectFolder(MultipartFile fileData, String originalFilename) {
        try {
            // 获取项目根目录的绝对路径
            String projectDir = System.getProperty("user.dir");
            // 构建文件的完整路径
            String filePath = projectDir + File.separator + "path/upload/" + originalFilename;
            // 创建文件夹(如果不存在)
            File folder = new File(filePath).getParentFile();
            if (!folder.exists()) {
                folder.mkdirs();
            }
            // 写入文件
            try (FileOutputStream fos = new FileOutputStream(filePath)) {
                fos.write(fileData.getBytes());
            }
            return filePath;
        } catch (IOException e) {
            return "";
        }
    }

    /*
    删除文件
     */
    @Override
    public AjaxResult delete(IdDTO idDTO) {
        UploadedFiles uploadedFiles = uploadFileMapper.selectById(idDTO.getId());
        String url = uploadedFiles.getFilePath();
        File file = new File(url);
        // 检查文件是否存在
        if (file.exists() && !file.isDirectory()) {
            // 删除文件
            boolean delete = file.delete();
            System.out.println(delete);
            uploadFileMapper.deleteById(idDTO.getId());
            return AjaxResult.success("删除文件成功");
        }
        return AjaxResult.error("删除失败");
    }


    /*
    下载文件
     */
    @Override
    public void eclipseFile(Integer id, HttpServletResponse response) {
        UploadedFiles uploadedFiles = uploadFileMapper.selectById(id);
        if (uploadedFiles == null) {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        String fileUrl = uploadedFiles.getFilePath();
        String fileName = uploadedFiles.getFileName();
        String fileType = uploadedFiles.getFileType();

        File file = new File(fileUrl);
        if (!file.exists()) {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        // 设置Content-Type
        String contentType = getContentType(fileType);
        response.setContentType(contentType);

        // 如果是图片文件,设置Content-Disposition为inline
        if (isImageFile(fileType)) {
            response.setHeader("Content-Disposition", "inline; filename=\"" + fileName + "\"");
        } else {
            String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"; filename*=UTF-8''" + encodedFileName);
        }
        response.setContentLength((int) file.length());

        try (FileInputStream fis = new FileInputStream(file);
             BufferedInputStream bis = new BufferedInputStream(fis);
             OutputStream os = response.getOutputStream()) {

            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = bis.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
        } catch (IOException e) {
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    private String getContentType(String fileType) {
        return switch (fileType.toLowerCase()) {
            case ".jpg", ".jpeg" -> "image/jpeg";
            case ".png" -> "image/png";
            case ".gif" -> "image/gif";
            case ".pdf" -> "application/pdf";
            case ".txt" -> "text/plain; charset=UTF-8";
            case ".md" -> "text/markdown; charset=UTF-8";
            case ".html" -> "text/html; charset=UTF-8";
            case ".xlsx" -> "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            case ".docx" -> "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
            case ".excel" -> "application/vnd.ms-excel";
            case ".word" -> "application/msword";
            default -> "application/octet-stream";
        };
    }

    private boolean isImageFile(String fileType) {
        return fileType != null && (fileType.equalsIgnoreCase(".jpg") || fileType.equalsIgnoreCase(".jpeg") ||
                fileType.equalsIgnoreCase(".png") || fileType.equalsIgnoreCase(".gif"));
    }
}

注意:JDK17

注意:部署后确保拥有操作服务器文件夹的权限

注意:代码为正确版本

遇到的坑:在实现文件下载时,文件上传没有问题,此时上传的文件可以通过XFTP下载并且正常打开,但是问题来了,如果使用代码进行文件下载,就会出现文件能正常下载但是当打开文件时会出现文件已损坏的问题,文件无法打开,那下载就没有了意义,查资料试了多种方法但是都没成功,直到有一天我福至心灵。。。

解决方案:当时使用的请求方式为post,将@PostMapping修改为@GetMapping,嗯对,就这样,文件下载后可以正常打开了

反正咱也不知道为啥会这样,也不清楚错误的原因,如果路过的各位对此有所心得,望不吝赐教

;