1.数据库建表
CREATE TABLE `sys_file` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'id',
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '文件名称',
`type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '文件类型',
`size` bigint DEFAULT NULL COMMENT '文件大小(kb)',
`url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '下载链接',
`md5` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.创建实体类
package com.example.demo.entity;
import lombok.Data;
@Data
public class Files {
private Integer id;
private String name;
private String type;
private Long size;
private String url;
private String md5;
}
3.mapper
package com.example.demo.mapper;
import com.example.demo.entity.Files;
import com.example.demo.entity.Permission;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface FileMapper {
@Select("SELECT * from sys_file")
List<Files> findFilesAll();
@Insert("insert into sys_file (name,type,size,url,md5) values(#{name},#{type},#{size},#{url},#{md5})")
void insert(Files files);
@Select("select *from sys_file where md5=#{md5}")
List<Files> selectList(String md5);
@Delete("delete from sys_file where id = #{id}")
Integer deleteFilesById(@Param("id") Integer id);
@Select("select * from sys_file where name like #{name} limit #{pageNum}, #{pageSize}")
List<Files> selectPage(@Param("pageNum") Integer pageNum, @Param("pageSize") Integer pageSize,
@Param("name") String name);
@Select("select count(*) from sys_file where name like concat('%', #{name}, '%') ")
Integer selectTotal(String name);
}
4.Controller
package com.example.demo.controller;
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.example.demo.mapper.FenjiMapper;
import com.example.demo.mapper.FileMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/file")
public class FileController {
@Value("${files.upload.path}")
private String fileUploadPath;
@Resource
private FileMapper fileMapper;
@PostMapping("/upload")
public String upload(@RequestParam MultipartFile file) throws IOException {
String originalFilename = file.getOriginalFilename();
String type = FileUtil.extName(originalFilename);
long size = file.getSize();
// 定义一个文件唯一的标识码
String uuid = IdUtil.fastSimpleUUID();
String fileUUID = uuid + StrUtil.DOT + type;
File uploadFile = new File(fileUploadPath + fileUUID);
// 判断配置的文件目录是否存在,若不存在则创建一个新的文件目录
File parentFile = uploadFile.getParentFile();
if (!parentFile.exists()) {
parentFile.mkdirs();
}
String url;
// 获取文件的md5
String md5 = SecureUtil.md5(file.getInputStream());
// 从数据库查询是否存在相同的记录
Files dbFiles = getFilesMd5(md5);
if (dbFiles != null) { // 文件已存在
url = dbFiles.getUrl();
} else {
// 上传文件到磁盘
file.transferTo(uploadFile);
// 数据库若不存在重复文件,则不删除刚才上传的文件
url = "http://localhost:9090/file/" + fileUUID;
}
//存储到数据库
Files saveFile = new Files();
saveFile.setName(originalFilename);
saveFile.setType(type);
saveFile.setSize(size/1024);
saveFile.setUrl(url);
saveFile.setMd5(md5);
fileMapper.insert(saveFile);
return url;
}
@GetMapping("/{fileUUID}")
public void download(@PathVariable String fileUUID, HttpServletResponse response) throws IOException {
// 根据文件的唯一标识码获取文件
File uploadFile = new File(fileUploadPath + fileUUID);
// 设置输出流的格式
ServletOutputStream os = response.getOutputStream();
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileUUID, "UTF-8"));
response.setContentType("application/octet-stream");
// 读取文件的字节流
os.write(FileUtil.readBytes(uploadFile));
os.flush();
os.close();
}
private Files getFilesMd5(String md5){
List<Files> filesList = fileMapper.selectList(md5);
return filesList.size() == 0 ? null : filesList.get(0);
}
@GetMapping
public List<Files> findAll() {
List<Files> all = fileMapper.findFilesAll();
return all;
}
@DeleteMapping("/{id}")
public Integer deleteId(@PathVariable("id") Integer id) {
return fileMapper.deleteFilesById(id);
}
@PostMapping("/del/batch")
public Integer deleteBatch(@RequestBody Integer[] id) {
for (Integer a: id)
{
fileMapper.deleteFilesById(a);
}
return 1;
}
// 分页查询
// 接口路径:/user/page?pageNum=1&pageSize=10
// @RequestParam接受
// limit第一个参数 = (pageNum - 1) * pageSize
// pageSize
@GetMapping("/page")
public Map<String, Object> findPage(@RequestParam(defaultValue = "") Integer pageNum,
@RequestParam(defaultValue = "") Integer pageSize,
@RequestParam (defaultValue = "")String name) {
pageNum = (pageNum - 1) * pageSize;
name = "%" + name + "%";
List<Files> data = fileMapper.selectPage(pageNum, pageSize, name);
Integer total = fileMapper.selectTotal(name);
Map<String, Object> res = new HashMap<>();
res.put("data", data);
res.put("total", total);
return res;
}
}
5.yml里还得配置一下文件保存的路径
files: upload: path: D:/springboot-vue/files/
6.前端页面实现
<template>
<div>
<div style="margin: 10px 0">
<el-upload action="http://localhost:9090/file/upload" :show-file-list="false" :on-success="handleFileUploadSuccess" style="display: inline-block">
<el-button type="primary" class="ml-5">上传文件 <i class="el-icon-upload"></i></el-button>
</el-upload>
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='我再想想'
icon="el-icon-info"
icon-color="red"
title="您确定批量删除这些数据吗?"
@confirm="delBatch"
>
<el-button type="danger" slot="reference">批量删除 <i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
</div>
<el-table :data="tableData" border stripe :header-cell-class-name="'headerBg'" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="id" label="ID" width="80"></el-table-column>
<el-table-column prop="name" label="文件名称"></el-table-column>
<el-table-column prop="type" label="文件类型"></el-table-column>
<el-table-column prop="size" label="文件大小(kb)"></el-table-column>
<el-table-column label="下载">
<template slot-scope="scope">
<el-button icon="el-icon-download" type="primary" @click="download(scope.row.url)">下载</el-button>
</template>
</el-table-column>
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='我再想想'
icon="el-icon-info"
icon-color="red"
title="您确定删除吗?"
@confirm="del(scope.row.id)"
>
<el-button type="danger" slot="reference">删除 <i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<div style="padding: 10px 0">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[2, 5, 10, 20]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</div>
</template>
<script>
export default {
name: "Files",
data() {
return {
tableData: [],
name: '',
multipleSelection: [],
pageNum: 1,
pageSize: 10,
total: 0,
id:"",
type: "",
size: "",
url: "",
}
},
created() {
this.load()
},
methods: {
load() {
this.request.get("/file/page", {
params: {
pageNum: this.pageNum,
pageSize: this.pageSize,
name: this.name,
}
}).then(res => {
this.tableData = res.data
this.total = res.data.total
})
},
del(id) {
this.request.delete("/file/" + id).then(res => {
if (res) {
this.$message.success("删除成功")
this.load()
} else {
console.log(res)
this.$message.error("删除失败")
}
})
},
handleSelectionChange(val) {
console.log(val)
this.multipleSelection = val
},
delBatch() {
let ids = this.multipleSelection.map(v => v.id) // [{}, {}, {}] => [1,2,3]
this.request.post("/file/del/batch", ids).then(res => {
if (res) {
this.$message.success("批量删除成功")
this.load()
} else {
this.$message.error("批量删除失败")
}
})
},
reset() {
this.name = ""
this.load()
},
handleSizeChange(pageSize) {
console.log(pageSize)
this.pageSize = pageSize
this.load()
},
handleCurrentChange(pageNum) {
console.log(pageNum)
this.pageNum = pageNum
this.load()
},
handleFileUploadSuccess(res) {
console.log(res)
this.load()
},
download(url) {
window.open(url)
}
}
}
</script>
<style scoped>
</style>
一套操作大功告成。