基于ruoyi-vue框架,新增一个简单的系统通用文件模块,服务与各个模块涉及到文件上传信息的记录和相关展示
运行sql,创建数据库表
DROP TABLE IF EXISTS `sys_file_info`;
CREATE TABLE `sys_file_info` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`link_obj_id` int(11) DEFAULT NULL COMMENT '关联对象id',
`name` varchar(255) DEFAULT NULL COMMENT '文件名称',
`file_type` varchar(255) DEFAULT NULL COMMENT '文件类型',
`type` char(10) DEFAULT NULL COMMENT '归属类型(预留字段,比如归属某个模块)',
`file_size` varchar(255) DEFAULT NULL COMMENT '文件大小',
`file_path` varchar(255) DEFAULT NULL COMMENT '文件路径',
`create_by` varchar(255) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
KEY `i_pof_type` (`link_obj_id`,`type`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='系统通用文件库';
生成代码
(按正常的若依分离版生成导入代码流程走)在系统工具生成代码,然后再编辑代码生成的内容,调整一下业务名,看自己的需求吧。
将生成后的后端代码加入系统模块相关位置,生成的前端代码内容如果不做台账管理则只用生成的api接口文件就行,后续要用到文件删除和请求。如果需要做台账则同样加到前端相应模块下,然后运行生成的sql文件(主要是生成相关路由菜单信息)即可,其他不多赘述。
java部分
1、在文件模块的controller层补充文件上传接口,代码如下:
重点:String linkObjId = map.get(“linkObjId”); String type = map.get(“type”); 获取前端组件额外传的参数,分别对应相关模块的数据id和模块类型,因为现在采用的id是1开始递增,不是全系统唯一uuid,因此可能不同模块会出现相同id,导致文件数据绑定异常,需要加上type来区分不同的模块。
@PostMapping(value = "/uploadFile")
@ResponseBody
public AjaxResult uploadFile(SysFileInfo pdFile, MultipartFile[] file, @RequestParam Map<String,String> map) {
String linkObjId = map.get("linkObjId");
String type = map.get("type");
try {
System.out.println("文件上传进入方法!");
List<SysFileInfo> list = new ArrayList<SysFileInfo>();
for (MultipartFile f : file) {
// 文件保存路径
String loadPath = FileUploadUtils.upload(RuoYiConfig.getUploadSysFilePath(), f);
pdFile.setFilePath(loadPath);
// 保存文件名
String f_name = f.getOriginalFilename();
pdFile.setName(f_name);
pdFile.setLinkObjId(Long.valueOf(linkObjId));
pdFile.setType(type);
pdFile.setFileSize(
FileUtils.getFileSize(RuoYiConfig.getProfile() + loadPath.replace(Constants.RESOURCE_PREFIX, ""))
+ " kb");
sysFileInfoService.insertSysFileInfo(pdFile);
list.add(pdFile);
}
return AjaxResult.success(list);
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("文件上传失败!" + e.getMessage());
}
}
2、RuoYiConfig.getUploadSysFilePath()爆红,为了和原来自带的上传路径(原来的是getUploadPath,按自己的需求调整,用原来的也行)做个区分,需要处理文件上传存储位置,在RuoYiConfig.java 补充以下代码。
/**
* 系统文件
* @return
*/
public static String getUploadSysFilePath()
{
return getProfile() + "/sysFile";
}
3、FileUtils.getFileSize()爆红,在FileUtils.java补充获取文件大小的方法, 没有这个需求就不用处理
/**
* 计算文件大小
* @param filePath
* @return 单位是byte
*/
public static long getFileSize(String filePath) {
long size = 0;
FileInputStream fis= null;
FileChannel fc= null;
try {
File f = new File(filePath);
if (f.exists() && f.isFile()){
fis= new FileInputStream(f);
fc= fis.getChannel();
size = fc.size();
}else{
// Constant.LOGGER.error("{},file doesn't exist or is not a file", filePath);
}
} catch (FileNotFoundException e) {
//Constant.LOGGER.error("文件大小检查发生异常,{}", e.getMessage());
e.getMessage();
} catch (IOException e) {
// Constant.LOGGER.error("文件大小检查发生异常,{}", e.getMessage());
e.getMessage();
} finally {
if (null!=fc){
try{
fc.close();
}catch(IOException e){
e.getMessage();
}
}
if (null!=fis){
try{
fis.close();
}catch(IOException e){
// Constant.LOGGER.error("FileInputStream资源关闭发生异常,{}", e.getMessage());
e.getMessage();
}
}
}
return size/1024;
}
4、将原来的批量删除、和删除方法调整如下,实现先删除文件,再删除数据信息
/**
* 批量删除系统通用文件库
*
* @param ids 需要删除的系统通用文件库主键
* @return 结果
*/
@Override
public int deleteSysFileInfoByIds(Long[] ids)
{
for(Long id :ids){
SysFileInfo sysFiles = selectSysFileInfoById(id);
String path= RuoYiConfig.getProfile() + sysFiles.getFilePath().replace(Constants.RESOURCE_PREFIX, "");
FileUtils.deleteFile(path);
}
return sysFileInfoMapper.deleteSysFileInfoByIds(ids);
}
/**
* 删除系统通用文件库信息
*
* @param id 系统通用文件库主键
* @return 结果
*/
@Override
public int deleteSysFileInfoById(Long id)
{
//删除本地文件
SysFileInfo sysFiles = selectSysFileInfoById(id);
String path= RuoYiConfig.getProfile() + sysFiles.getFilePath().replace(Constants.RESOURCE_PREFIX, "");
FileUtils.deleteFile(path);
// 删除数据库文件记录
return sysFileInfoMapper.deleteSysFileInfoById(id);
}
其他爆红导入相关类就行。
前端在需要文件上传的地方处理文件上传
1、组件引入
<el-form-item label="附件">
<el-upload
class="notice_upload"
ref="upload"
:limit="7"
accept=""
multiple
:data="upload.data"
:headers="upload.headers"
:action="upload.url"
:disabled="upload.isUploading"
:on-progress="handleFileUploadProgress"
:on-success="handleFileSuccess"
:on-preview="handleDownload"
:show-file-list="true"
:file-list="upload.fileList"
:auto-upload="false"
:before-remove="beforeRemove"
:on-remove="handleRemove"
>
<em v-if="!upload.isUploading">
<div
:style="{
width: '80px',
height: '30px',
lineHeight: '20px',
color: theme,
}"
>
<i class="el-icon-link"></i> 点击上传
</div>
</em>
</el-upload>
</el-form-item>
2、引入获取token
import { getToken } from "@/utils/auth";
3、引入api
import { listFileInfo,delFileInfo} from "@/api/system/fileInfo";
4、data中添加属性
upload: {
// 是否禁用上传
isUploading: false,
// 设置上传的请求头部
headers: { Authorization: "Bearer " + getToken() },
// 上传的地址(接口就是上文的文件上传接口)
url: process.env.VUE_APP_BASE_API + "/system/fileInfo/uploadFile",
// 上传的文件列表
fileList: [],
//携带参数
data: {
linkObjId: null,
type: 1,
}
},
5、添加对应事件
//文件提交处理
submitUpload() {
this.$refs.upload.submit();
},
// 文件上传中处理
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true;
},
// 文件上传成功处理
handleFileSuccess(response, file, fileList) {
this.upload.isUploading = false;
},
// 删除文件之前确认
beforeRemove(file, fileList) {
return this.$confirm(`是否确定永久移除文件 ${file.name}?`);
},
//文件删除
handleRemove(file, fileList) {
if (file.id) {
delFileInfo(file.id)
.then((res) => {
this.$message.success(res.msg);
console.log("res", res);
})
.catch((err) => {
this.$message.errer(err + "");
console.log("err", err);
});
}
},
// 文件下载处理
handleDownload(file) {
var name = file.name;
//先打印看文件信息再调整url构建
var url = process.env.VUE_APP_BASE_API + file.filePath;
const a = document.createElement("a");
a.setAttribute("download", name);
a.setAttribute("target", "_blank");
a.setAttribute("href", url);
a.click();
},
6、在表单提交时,调用文件上传方法,注意id的获取,this.upload.data.linkObjId
/** 提交按钮 */
submitForm(e) {
this.$refs["form"].validate((valid) => {
if (valid) {
if (this.form.id != null) {
updateWorkInfo(this.form).then((response) => {
console.log("修改:" + response)
this.$modal.msgSuccess("修改成功");
this.upload.data.linkObjId=this.form.id;
this.submitUpload()
this.open = false;
this.$emit("cancel")
});
} else {
addWorkInfo(this.form).then((response) => {
this.$modal.msgSuccess("新增成功");
this.upload.data.linkObjId=response.id;
this.submitUpload()
this.open = false;
this.$emit("cancel")
});
}
}
});
},
补充,后端处理新增返回id的方式,需求表单的id会自增:
@PostMapping
public AjaxResult add(@RequestBody WorkInfo workInfo ) {
workInfoService.insertWorkInfo (workInfo);
AjaxResult ajaxResult = new AjaxResult();
ajaxResult.put("id",workInfo.getId());
return ajaxResult;
}
7、附件回显,再点击修改或者查看事件的方法内给this.upload.fileList赋值请求到的文件列表信息就行
//查看
handleView(row) {
this.reset();
const id = row.id || this.ids;
getWorkInfo(id).then((response) => {
this.form = response.data;
//处理文件信息(可以在后端WorkInfo加个返回参数,也可以在这里请求文件信息数据再赋值,注意type和linkObjId的参数传值)
this.upload.fileList=response.data.sysFileInfoList
this.seeOpen = true;
this.title = "查看授权申请单";
});
},
8、文件列表重置,不然会有缓存问题
在this.reset()方法里加上this.upload.fileList=[]
注意事项
1、会使用若依分离版的代码生成功能
2、注意接口是否对应得上