SpringBoot3 + Vue3 前后端分离项目实现文件上传下载

1、数据库表设计

CREATE TABLE `files` (
  `id` varchar(40) NOT NULL COMMENT '主键',
  `name` varchar(255) DEFAULT NULL COMMENT '文件名',
  `url` varchar(255) DEFAULT NULL COMMENT '下载URL',
  `type` varchar(40) DEFAULT NULL COMMENT '文件类型',
  `size` bigint DEFAULT NULL COMMENT '文件大小(KB)',
  `md5` varchar(255) DEFAULT NULL COMMENT '文件唯一标识',
  `creator_id` varchar(40) DEFAULT NULL COMMENT '创建人ID',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `ts` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `delete_flag` int NOT NULL DEFAULT '0' COMMENT '逻辑删除字段(0:正常,1:删除)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='文件表';

2、Java 后端实现

2.1 application.yml 指定文件上传下载目录

server:
  port: 8080

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/xxx
    username: xxx
    password: xxx

# application.yml 指定文件上传下载目录
files:
  upload:
    path: D:/files/

 2.2 Files-实体类

package com.dragon.springboot3vue3.entity;

import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * 

* 文件表 *

*/ @Data @Schema(name = "Files", description = "文件表") public class Files implements Serializable { private static final long serialVersionUID = 1L; @Schema(description = "主键") @TableId(value = "id", type = IdType.ASSIGN_UUID) private String id; @Schema(description = "文件名") private String name; @Schema(description = "下载URL") private String url; @Schema(description = "文件类型") private String type; @Schema(description = "文件大小") private long size; @Schema(description = "文件唯一标识") private String md5; @Schema(description = "创建人ID") @TableField(fill = FieldFill.INSERT) private String creatorId; @Schema(description = "创建时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; @Schema(description = "更新时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime ts; @Schema(description = "逻辑删除字段(0:正常,1:删除)") @TableLogic private Integer deleteFlag; }

2.3 FilesController (注意:要放行 "/files/{fileName}" 接口)

package com.dragon.springboot3vue3.controller;

import cn.dev33.satoken.util.SaResult;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dragon.springboot3vue3.controller.dto.pageDto.FilesPageDto;
import com.dragon.springboot3vue3.entity.Files;
import com.dragon.springboot3vue3.service.IFilesService;
import com.dragon.springboot3vue3.utils.StringIdsDTO;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * 

* 文件表 前端控制器 *

* * @author dragon * @since 2024-05-25 */ @Tag(name = "文件上传下载接口") @RestController @RequestMapping("/files") public class FilesController { @Autowired private IFilesService filesService; @Value("${files.upload.path}") private String path; /** * 文件上传 * @param file * @return * @throws IOException */ @Operation(summary = "文件上传") @PostMapping("/upload") public SaResult upload(@RequestParam MultipartFile file) throws IOException { String originalFilename = file.getOriginalFilename(); String type = FileUtil.extName(originalFilename); long size = file.getSize(); // 如果文件目录不存在,则新建 File uploadParentFile = new File(path); if(!uploadParentFile.exists()){ uploadParentFile.mkdirs(); } // 保证存储的文件名唯一 String fileName=IdUtil.fastSimpleUUID() + StrUtil.DOT + type; File uploadFile = new File(path + fileName); // 设置下载的url String url = "http://localhost:8080/files/"+fileName; // 将文件存储到磁盘 file.transferTo(uploadFile); // 生成文件唯一标识 md5,保证不会在磁盘存储重复的文件 String md5 = SecureUtil.md5(uploadFile); List list = filesService.lambdaQuery().eq(Files::getMd5, md5).list(); if(CollectionUtil.isNotEmpty(list)){ url=list.getFirst().getUrl(); uploadFile.delete(); } // 文件信息存储到数据库 Files saveFile = new Files(); saveFile.setName(originalFilename); saveFile.setType(type); // 单位转换 B -> KB saveFile.setSize(size/1024); saveFile.setUrl(url); saveFile.setMd5(md5); filesService.save(saveFile); return SaResult.ok().setData(url); } @Operation(summary = "文件下载") @GetMapping("/{fileName}") public void download(@PathVariable String fileName, HttpServletResponse response) throws IOException { // 在指定目录下,根据文件名查找文件 File file = new File(path + fileName); ServletOutputStream outputStream = response.getOutputStream(); // 设置输出流格式 response.addHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8)); response.setContentType("application/octet-stream"); // 读取文件字节流 outputStream.write(FileUtil.readBytes(file)); outputStream.flush(); outputStream.close(); } @Operation(summary = "分页列表") @PostMapping("/list") public SaResult list(@RequestBody FilesPageDto pageDto){ // 创建分页对象 Page page=new Page<>(pageDto.getCurrentPage(), pageDto.getPageSize()); // 构造询条件 MPJLambdaWrapper qw=new MPJLambdaWrapper() .like(StringUtils.isNotBlank(pageDto.getName()),Files::getName, pageDto.getName()) .like(StringUtils.isNotBlank(pageDto.getType()),Files::getType, pageDto.getType()) .orderByDesc(Files::getCreateTime); // 根据查询条件,将结果封装到分页对象 Page response = filesService.page(page, qw); return SaResult.ok().setData(response); } @Operation(summary = "删除") @DeleteMapping("/remove") public SaResult remove(@RequestBody @Validated StringIdsDTO stringIdsDTO){ filesService.removeByIds(stringIdsDTO.getIds()); return SaResult.ok(); } }

2.4 IFilesService

package com.dragon.springboot3vue3.service;

import com.dragon.springboot3vue3.entity.Files;
import com.baomidou.mybatisplus.extension.service.IService;

/**
 * 

* 文件表 服务类 *

* */ public interface IFilesService extends IService { }

2.5 FilesServiceImpl 

package com.dragon.springboot3vue3.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dragon.springboot3vue3.entity.Files;
import com.dragon.springboot3vue3.mapper.FilesMapper;
import com.dragon.springboot3vue3.service.IFilesService;
import org.springframework.stereotype.Service;

/**
 * 

* 文件表 服务实现类 *

* */ @Service public class FilesServiceImpl extends ServiceImpl implements IFilesService { }

3、Vue 3 前端实现

3.1 前端实现效果

SpringBoot3 + Vue3 前后端分离项目实现文件上传下载_第1张图片

3.2 前端实现文件上传下载、图片预览





你可能感兴趣的:(Spring,Boot,3,Vue,3,java,spring,boot,vue)