若依框架(RuoYi)是一款基于Spring Boot和Spring Cloud的开源后台管理系统,其功能丰富且易于扩展。实现文件上传与下载功能是许多项目中的常见需求,下面将详细介绍如何在若依框架中实现这一功能。
前端可以通过表单提交或使用FormData
对象来发送文件数据。若依框架默认使用Vue.js作为前端框架,以下是一个简单的示例代码:
<template>
<div>
<el-upload
class="upload-demo"
action="/api/common/upload"
:on-success="handleSuccess"
:before-upload="beforeUpload">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
</div>
</template>
<script>
export default {
methods: {
handleSuccess(response, file, fileList) {
this.$message.success("文件上传成功!");
},
beforeUpload(file) {
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
this.$message.error("上传文件大小不能超过 2MB!");
}
return isLt2M;
}
}
};
</script>
action
属性指定了后端接口地址。on-success
回调函数用于处理上传成功后的逻辑。before-upload
钩子可以用来校验文件大小、类型等。在若依框架中,文件上传的核心逻辑位于com.ruoyi.common.controller.CommonController
类中。以下是关键代码解析:
@Log(title = "文件上传", businessType = BusinessType.UPLOAD)
@PostMapping("/upload")
public AjaxResult uploadFile(@RequestParam MultipartFile file) throws Exception {
try {
// 调用工具类方法保存文件
String fileName = FileUploadUtils.upload(RuoYiConfig.getProfile(), file);
String url = StringUtils.format("{}/{}", RuoYiConfig.getDomain(), fileName);
return AjaxResult.success(url);
} catch (Exception e) {
return AjaxResult.error(e.getMessage());
}
}
FileUploadUtils
工具类负责实际的文件保存操作:
public static final String UPLOAD_DIR = "upload";
public static String upload(String baseDir, MultipartFile file) throws IOException {
try {
// 验证文件是否为空
if (file == null || file.isEmpty()) {
throw new IllegalArgumentException("上传文件不能为空");
}
// 获取文件名和扩展名
String fileName = file.getOriginalFilename();
String extension = FilenameUtils.getExtension(fileName);
// 检查文件类型是否合法
if (!FileUploadUtils.isFileAllowed(extension)) {
throw new FileSizeLimitExceededException(FileUploadUtils.DEFAULT_ALLOWED_EXTENSION);
}
// 构建目标路径
String filePath = baseDir + "/" + UPLOAD_DIR + "/" + DateUtils.datePath() + "/";
File desc = new File(filePath + UUID.randomUUID().toString() + "." + extension);
// 如果目录不存在,则创建
if (!desc.getParentFile().exists()) {
desc.getParentFile().mkdirs();
}
// 保存文件
file.transferTo(desc);
returnStringUtils.substringAfterLast(desc.getAbsolutePath(), baseDir.replace("/", "\\"));
} catch (Exception e) {
throw new IOException("上传文件失败", e);
}
}
baseDir
:基础路径,通常从配置文件中读取。DateUtils.datePath()
:生成按日期分隔的文件夹路径,避免文件过多导致性能问题。UUID.randomUUID()
:为文件生成唯一标识符,防止文件名冲突。前端通过调用后端接口并触发浏览器下载行为即可完成文件下载。以下是一个示例代码:
downloadFile(url) {
window.location.href = url;
}
或者使用axios
进行更复杂的处理:
downloadFile(url) {
axios({
method: 'get',
url: url,
responseType: 'blob'
}).then((response) => {
const blob = new Blob([response.data]);
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'filename.ext'; // 自定义文件名
link.click();
});
}
后端需要提供一个接口用于响应文件下载请求:
@Log(title = "文件下载", businessType = BusinessType.DOWNLOAD)
@GetMapping("/download/{fileName:.+}")
public void download(HttpServletResponse response, @PathVariable String fileName) throws IOException {
try {
// 构建文件路径
String filePath = RuoYiConfig.getProfile() + "/upload/" + fileName;
// 检查文件是否存在
File file = new File(filePath);
if (!file.exists()) {
throw new FileNotFoundException("文件未找到!");
}
// 设置响应头
response.reset();
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
response.setContentType("application/octet-stream");
// 写入文件流
FileInputStream inputStream = new FileInputStream(file);
OutputStream outputStream = response.getOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, len);
}
inputStream.close();
outputStream.flush();
outputStream.close();
} catch (Exception e) {
log.error("文件下载异常:{}", e.getMessage());
}
}