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='文件表';
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/
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;
}
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();
}
}
package com.dragon.springboot3vue3.service;
import com.dragon.springboot3vue3.entity.Files;
import com.baomidou.mybatisplus.extension.service.IService;
/**
*
* 文件表 服务类
*
*
*/
public interface IFilesService extends IService {
}
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 {
}
首页
文件管理
上传文件
批量删除
搜索
重置
{{ row.type }} 文件,请下载查看