【文件上传/下载Java+vue3——MQ】
文件上传/下载Java+vue3
- 文件上传/下载Java+vue3
- 一、后端Java代码
- 二、前端Vue3代码
- 三、附:请求封装request.js代码
- 生活不易,在线卖艺 呜呜呜~~~~~
- 至此,大功告成!
文件上传/下载Java+vue3
本文将介绍Java+vue3进行文件的上传与文件下载,废话不多说,直接贴代码。
一、后端Java代码
package com.mo.server.controller;import com.mo.server.config.ResResult;
import com.mo.server.entity.SysFile;
import com.mo.server.service.SysFileService;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Date;
import java.util.Map;@RestController
@RequestMapping("/sysfile")
public class SysFileController {private static final Logger log = LoggerFactory.getLogger(SysFileController.class);@AutowiredSysFileService sysFileService;// 绝对路径private static final String FilePath = "/home/files/";// 文件上传@PostMapping("/upload")public ResResult upload(HttpServletRequest request) throws Exception {// 获取文件说明String remark = request.getParameter("remark");// 获取文件Part uploadfile = request.getPart("file");// 文件名称String filename = uploadfile.getSubmittedFileName();// 文件大小long filesize = uploadfile.getSize();// 文件大小 字节单位转MBdouble filesizeMB = filesize / (1024.0 * 1024.0);String filesizeMBStr = String.format("%.3f", filesizeMB) + "MB";// 创建父级目录File path = new File(FilePath);if (!path.exists()) {path.mkdirs();}// 保存到磁盘的实际文件名称String savename = System.currentTimeMillis() + "-" + filename;//文件最终保存全路径String targetPath = FilePath + savename;// 复制写入文件,保存到磁盘InputStream fileContent = uploadfile.getInputStream();Files.copy(fileContent, Paths.get(targetPath), StandardCopyOption.REPLACE_EXISTING);fileContent.close(); // 关闭输入流// 设置保存数据库信息SysFile sysFile = new SysFile();sysFile.setFilename(filename);sysFile.setRemark(remark);sysFile.setFilesize(filesizeMBStr);sysFile.setCreateAt(new Date());//保存到数据库SysFile add = sysFileService.add(sysFile);return ResResult.success(add);}// 查询列表 模糊+分页@GetMappingpublic ResResult list(@RequestParam Map<String, Object> paramMap) {return ResResult.success(sysFileService.list(paramMap));}// 删除@DeleteMapping("/{id}")public ResResult delete(@PathVariable String id) {SysFile byId = sysFileService.getById(id);String targetPath = FilePath + byId.getSavename();Path path = Paths.get(targetPath);try {Files.deleteIfExists(path); // 使用deleteIfExists避免文件不存在时的异常log.info("文件已删除: " + targetPath);} catch (IOException e) {log.error("删除文件时出错: " + e.getMessage());}return ResResult.success(sysFileService.delete(id));}// 文件下载@GetMapping("/download")public void download(@RequestParam String fileName, HttpServletResponse response) throws IOException {File file = new File(FilePath + fileName);if (file.exists()) {FileInputStream fileInputStream = new FileInputStream(file);ServletOutputStream outputStream = response.getOutputStream();// 获取文件扩展名String extension = fileName.substring(fileName.lastIndexOf(".") + 1);// 根据文件扩展名设置Content-TypeString contentType = getContentType(extension);response.setContentType(contentType);// 如果文件名为中文需要设置编码response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName, "utf8"));// 返回前端文件名需要添加response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");byte[] bytes = new byte[1024];int len;while ((len = fileInputStream.read(bytes)) != -1) {outputStream.write(bytes, 0, len);}}}// 根据文件扩展名获取Content-Typeprivate String getContentType(String extension) {if ("jpg".equalsIgnoreCase(extension) || "jpeg".equalsIgnoreCase(extension)) {return "image/jpeg";} else if ("png".equalsIgnoreCase(extension)) {return "image/png";} else if ("gif".equalsIgnoreCase(extension)) {return "image/gif";} else if ("txt".equalsIgnoreCase(extension)) {return "text/plain";} else if ("pdf".equalsIgnoreCase(extension)) {return "application/pdf";} else if ("doc".equalsIgnoreCase(extension) || "docx".equalsIgnoreCase(extension)) {return "application/msword";} else if ("xls".equalsIgnoreCase(extension) || "xlsx".equalsIgnoreCase(extension)) {return "application/vnd.ms-excel";} else if ("ppt".equalsIgnoreCase(extension) || "pptx".equalsIgnoreCase(extension)) {return "application/vnd.ms-powerpoint";} else if ("zip".equalsIgnoreCase(extension)) {return "application/zip";} else if ("tar".equalsIgnoreCase(extension)) {return "application/x-tar";} else if ("rar".equalsIgnoreCase(extension)) {return "application/x-rar-compressed";} else if ("gz".equalsIgnoreCase(extension)) {return "application/gzip";} else {return "application/octet-stream";}}}
二、前端Vue3代码
<script setup>
// 导入全局属性
import { getCurrentInstance } from 'vue'
const { proxy } = getCurrentInstance()
import { reactive, ref, onMounted, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'const uploadRef = ref()
// 自定义上传函数
const uploadFile = (params) => {// 文件暂存到addForm后面再一起提交addForm.file = params.file;hasFileTips.value = "";
}
// 覆盖原来的文件
const handleExceed = (files) => {uploadRef.value.clearFiles()const file = files[0]uploadRef.value.handleStart(file)addForm.file = file
}
// 删除时的回调
const handleRemove = (files) => {addForm.file = '';
}//新增
const addFormRef = ref('');
const addForm = reactive({remark: '',file: ''
})
const rules = reactive({remark: [{required: true, message: "请输入文件说明", tirgger: "blur"}]
})
const hasFileTips = ref('')
// 提交新增
function addSubmit() {if (!addForm.file) {console.log("请选择文件!");hasFileTips.value = "请选择文件!";return;} else {hasFileTips.value = "";}addFormRef.value.validate((valid) => {if (valid) {// 构建上传格式const formdata = new FormData();formdata.append("remark", addForm.remark);formdata.append("file", addForm.file);// 上传到服务器let res = proxy.$request.post("/sysfile/upload", addForm, {headers: { 'Content-Type': 'multipart/form-data' }}).then(res => {ElMessage.success(res.msg);getList();});} else {console.log("校验失败");return;}});
}// 文件下载
import { saveAs } from 'file-saver'
function downloadFile(data) {proxy.$request.get("/sysfile/download", { fileName: data.filename }, { responseType: 'blob' }).then((res) => {saveAs(res, data.filename);ElMessage.success("文件传输完成,检查您的下载目录");});
}</script><template><el-card><!-- 新增 --><div v-show="proxy.$hasPermis('file:add')"style="border: 1px dashed blue;border-radius: 2px;margin: 10px auto;height: 70px;width: 730px;padding-left: 10px;"><el-form :model="addForm" ref="addFormRef" :rules="rules" size="small"><div style="float: left;margin-top: 10px;"><el-upload ref="uploadRef" :limit="1" :http-request="uploadFile" :on-exceed="handleExceed":on-remove="handleRemove"><template #trigger><el-button style="width: 300px;">选 择 文 件</el-button></template><template #tip><el-text class="mx-1" type="danger">{{ hasFileTips }}</el-text></template></el-upload></div><el-form-item prop="remark"><el-input v-model="addForm.remark" type="text" placeholder="请输入文件说明..." style="width: 300px;" /><el-button type="primary" icon="Upload" @click="addSubmit" v-show="proxy.$hasPermis('file:add')">确认上传</el-button></el-form-item></el-form></div></el-card>
</template><style scoped>
</style>
三、附:请求封装request.js代码
/*** axio 封装*/
import axios from 'axios'
import storage from '@/config/storage'
import { ElMessage } from 'element-plus'
import router from '@/router'var myBaseUrl = "";
if (import.meta.env.MODE === 'production') {// console.log("我是生产环境")myBaseUrl = "/api";
} else {// console.log("我是开发")myBaseUrl = "/api";
}const service = axios.create({baseURL: myBaseUrl,timeout: 8000
})// 请求拦截处理
service.interceptors.request.use(reqConfig => {// 可以在这里添加请求头、显示加载动画等const headers = reqConfig.headers;if (!headers.Authorization) headers.Authorization = storage.getItem("Authorization");// 返回修改后的 reqConfigreturn reqConfig;},error => {ElMessage.error(error.message);return Promise.reject(error.message); // 返回错误})// 响应拦截处理
service.interceptors.response.use(resp => {//是文件直接返回if ("[object Blob]" == (resp.data + "")) {return resp.data;}// 不是文件就正常解析const { code, msg } = resp.data;if (code === 200) {return resp.data;} else if (code === 401) {// token失效返回登录页ElMessage.error("登录已过期,请重新登录");storage.clearAll();router.push('/login');return Promise.reject(msg)} else {ElMessage.error(msg);return Promise.reject(msg)}},error => {// 处理超时错误if (error.code === 'ECONNABORTED') {ElMessage.error(error.message);} else {ElMessage.error(error.message);}return Promise.reject(error); // 返回错误})// axios关键配置
function request(options) {options.method = options.method || 'get';if (options.method.toLowerCase() === 'get') {options.params = options.data;}return service(options);
}// 请求方式配置
// 使用时可以直接$request.get(url,data).then((res)=>{处理返回结果})
['get', 'put', 'post', 'delete', 'patch'].forEach((item) => {request[item] = (url, data, options) => {return request({url,data,method: item,...options,})}
})//导出request
export default request
生活不易,在线卖艺 呜呜呜~~~~~
有钱的捧个钱场,没钱的捧个人场,感谢各位老板大气!!!