基于若依实现文件上传、下载
文章目录
- 基于若依实现文件上传、下载
- 1、前端实现-文件上传
- 1.1 通用上传分析
- 1.2 修改实现上传接口
- 2、后端实现-文件上传
- 3、后端实现-文件下载
- 4、前端实现-文件下载
官网其实也写了,但是我是自己改造封装了一下,再次迈向全栈的一小步。下面是官网前后端分离版本文件上传的地址:
若依官方文档
1、前端实现-文件上传
1.1 通用上传分析
首先我这里有一个书籍列表的基础页面,我在它的修改这一栏加上了文件上传,这里前端其实就是用了若依封装的一个全局文件上传的组件,如果想看它的底层逻辑可以直接main.js,我这里就直接用了(但是后来发现全局组件不能行,还得自己封装elemntui的组件upload,这里只是先分析逻辑)
注意这里只是先分析,实现还在后面,因为若依自带的通用文件上传我们不能调用自己的上传接口,保存文件信息到数据库
这里就是找到对应的修改的dialog对话框中的form加上全局组件 <file-upload v-model="form.file"/>
就可以了
<!-- 添加或修改对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<!--这里其他不重要的字段只列举了一部分-->
<el-form-item label="图书类型" prop="bookType">
<el-select v-model="form.bookType" placeholder="请选择图书类型">
<el-option label="名著" value="1"></el-option>
<el-option label="历史" value="2"></el-option>
<el-option label="社科" value="3"></el-option>
</el-select>
</el-form-item>
<el-form-item label="出版日期" prop="publishDate">
<el-date-picker clearable
v-model="form.publishDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择出版日期">
</el-date-picker>
</el-form-item>
<!--文件上传字段-->
<el-form-item label="上传文件" prop="file">
<file-upload v-model="form.file"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
然后我们在修改对话框中点击上传文件,就会发现它直接调用了后端通用的上传文件的接口,已经把文件上传到了服务器,并且返回了上传后的地址
/**
* 通用上传请求(单个)
*/
@PostMapping("/upload")
public AjaxResult uploadFile(MultipartFile file) throws Exception
{
try
{
// 上传文件路径 ,已在配置文件配置D:/ruoyi/uploadPath
String filePath = RuoYiConfig.getUploadPath();
// 上传并返回新文件名称 这里其实就在电脑配置的地址 根据年月日可以看文件了
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName;
AjaxResult ajax = AjaxResult.success();
ajax.put("url", url);
ajax.put("fileName", fileName);
ajax.put("newFileName", FileUtils.getName(fileName));
ajax.put("originalFilename", file.getOriginalFilename());
return ajax;
}
catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
}
上面就是FileUploadUtils.upload(filePath, file);
上传后的文件,下面是通用上传接口返回的响应,自己可以先看清楚,对于这个新的文件名称fileName 其实就是去掉了前缀的配置地址然后加上了一个profile,这个是为了隐藏我们真实的配置的文件路径,把配置的地址映射为了profile
但是这里其实可能不是我们想要的,**因为我们想调用我们自己的上传接口,这样我们后端还可以对文件进行处理,比如拿到文件后缀,把文件存入数据库对应的字段等。
1.2 修改实现上传接口
所以我们只能自己基于elemntui 去做修改,这里我想上传成功后还要返显文件名称
在列表的form加一个文件名称字段,
<el-table-column label="文件名称" align="center" prop="fileName" />
首先对新增和修改的dialog做修改
<!-- 添加或修改对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<!--其他字段就省略了-->
<!--文件上传字段-->
<el-form-item label="上传文件" >
<!--这里上传成功后会绑定文件名到form.fileName字段传给后端的新增接口,uploadBookFile定义上传请求, :before-upload是上传前的回调,用于文件格式校验 -->
<el-upload
class="upload-demo"
action="#"
:http-request="uploadBookFile"
:drag="true"
:before-upload="uploadFileFun"
:headers="upload.headers"
:file-list="form.fileList">
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip fontSize12 colorRed" slot="tip">上传文件格式为word或pdf或者txt,文件大小在2M以内</div>
</el-upload>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
data 数据
upload: {
// 设置上传的请求头部
headers: { Authorization: "Bearer " + getToken() },
},
// 表单参数
form: {
},
javaScript方法
import { uploadBookFile} from "@/api/system/book";
//下面是method写在里面的, 这里就是上传功能向后端发送上传请求,参数是一个二进制文件
uploadBookFile(file){
console.log(file.file,151454)
// 创建formdata实例
let formData = new window.FormData();
// 将获取的文件通过append方法加入实例中
formData.append("file", file.file);
//发送axios请求
uploadBookFile(formData)
.then(res => {
console.log(res)
//拿到后端响应的文件名称反显到列表的form
this.form.fileName = res.originalFilename
})
},
//文件上传前的校验
uploadFileFun(file){
var test = /(doc|docx|pdf|txt)$/.test(file.name.split('.').pop().toLowerCase());
if (!test) {
this.$message.error("请上传正确的文档格式!");
return false;
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
this.$message.error("上传文件大小不能超过 2MB!");
return false;
}
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
updateBook(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addBook(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
api/book.js
import { getToken } from "@/utils/auth";
// 上传文件
export function uploadBookFile(data) {
return request({
url: '/system/book/uploadFile',
method: 'post',
data: data,
headers: {
'Content-Type': 'multipart/form-data',
'Authorization': "Bearer " + getToken(),
}
})
}
2、后端实现-文件上传
后端其实就比较简单了,我也没做一个专门的文件表,只是在业务表里面加了一个file_name字段,表结构如下**(这里只是做文件上传,所以不需要文件路径字段,后续做文件下载就必须要文件路径字段,后面我会再修改)**
controller 这里是前端的upload组件传过来了一个二进制文件,然后后端把文件上传到服务器,并把文件名也返回给了前端,这样前端就可以对响应结果做解析,把文件名字段绑定到新增、修改的dialog里面,然后点击保存再把文件名称字段传回后端保存到数据库。
/**
* 上传文件接口
* @param file
* @return
* @throws Exception
*/
@PostMapping("/uploadFile")
public AjaxResult uploadFile(MultipartFile file) throws Exception
{
try
{
// 上传文件路径 ,已在配置文件配置D:/ruoyi/uploadPath
String filePath = RuoYiConfig.getUploadPath();
// 上传并返回新文件名称 . "fileName": "/profile/upload/2024/07/06/紫金项目_20240706155317A001.txt",
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName;
//这些信息返回给前端之后,
AjaxResult ajax = AjaxResult.success();
ajax.put("url", url);
ajax.put("fileName", fileName);
// "newFileName": "紫金项目_20240706155317A001.txt",
ajax.put("newFileName", FileUtils.getName(fileName));
// "originalFilename": "紫金项目.txt",用于给前端列表回显
ajax.put("originalFilename", file.getOriginalFilename());
return ajax;
}
catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
}
/**
* 新增接口就是代码生成的看的,前端点击保存按钮的时候会读取Book实体类的fileName字段再保存到数据库
*/
@PreAuthorize("@ss.hasPermi('system:book:add')")
@Log(title = "新增", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody Book book)
{
return toAjax(bookService.insertBook(book));
}
3、后端实现-文件下载
由于实现文件下载,所以必不可少的就是文件路径
这个字段,所以我们还得加上文件路径
这个字段,所以现在表结构如下,还得给所有的增删改查字段加上文件路径这个字段
其他的直接使用通用的文件下载接口就可以了 ,前端传一个文件路径回来,后端就可以直接下载了
前端需要传的文件路径是这样的 /profile/upload/2024/07/06/紫金项目_20240706160309A002.txt
首先前端经过代理proxy之后就会拿到ip和端口,然后后端这时候有个拦截器,它会拦截/profile
,拦截之后把它再替换成配置文件中配置的绝对路径。
4、前端实现-文件下载
首先修改文件上传方法,加入一行 this.form.filePath = res.fileName
,这样上传后,把文件路径绑定到了西新增修改的dialong,在点击保存的时候,就可以把文件路径存入数据库。后续列表查询就可以读取到当前行的文件路径了。
uploadBookFile(file){
console.log(file.file,151454)
// 创建formdata实例
let formData = new window.FormData();
// 将获取的文件通过append方法加入实例中
formData.append("file", file.file);
uploadBookFile(formData)
.then(res => {
console.log(res)
// 保存到新增、修改的form里面再入数据库
this.form.fileName = res.originalFilename
this.form.filePath = res.fileName
})
},
加上下载按钮
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:book:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:book:remove']"
>删除</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleDownload(scope.row)"
>下载</el-button>
</template>
</el-table-column>
在method里面加上如下方法,这里就是直接调用了通用的文件下载,这里的filePanth就是前面保存的/profile/upload/2024/07/06/紫金项目_20240706160309A002.txt
handleDownload(row){
var name = row.fileName;
var url = row.filePath;
this.$download.resource(url,false)
}
最后值得注意的是我目前实现的都是单文件上传和下载,多文件我后续会继续写demo