文章目录
- 效果
- 前端代码
- 后端代码
- 组件封装
效果
前端代码
/views/file/file.vue
<template><el-row><el-uploadv-model:file-list="fileList"class="upload-demo"multiple:auto-upload="false":on-preview="handlePreview":on-remove="handleRemove"span="10"style="margin-right: 20px"><el-button type="primary">选择上传的文件</el-button></el-upload><el-button type="success" @click="submit">上传文件</el-button></el-row>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { ElMessage } from "element-plus";
import { uploadBatch } from "/src/api/file.ts";import type { UploadProps, UploadUserFile } from "element-plus";const fileList = ref<UploadUserFile[]>([]);const handleRemove: UploadProps["onRemove"] = (file, uploadFiles) => {console.log(file, uploadFiles);
};const handlePreview: UploadProps["onPreview"] = uploadFile => {console.log(uploadFile);
};const submit = () => {console.log(fileList.value);// 封装formDataconst data = new FormData();fileList.value.forEach(element => {data.append("fileList", element.raw);});uploadBatch(data).then(res => {console.log(res);if (res.code === 0) {ElMessage.success("上传成功");} else {ElMessage.error("上传失败: " + res.msg);}});
};
</script>
/src/api/file.ts
import { http } from "@/utils/http";
import { R, baseUrlApi } from "./utils";/** upload batch */
export const uploadBatch = (data: FormData) => {return http.request<R<any>>("post", baseUrlApi("common/file/uploadList"), {data,headers: {"Content-Type": "multipart/form-data"}});
};/** upload */
export const upload = (data: FormData) => {return http.request<R<any>>("post", baseUrlApi("common/file/upload"), {data,headers: {"Content-Type": "multipart/form-data"}});
};
/src/api/utils.ts
export const baseUrlApi = (url: string) => `/api_demo/${url}`;/** 后端返回通用数据类型 */
export type R<T> = {code: Number;msg: String;data: T;
};/** 同步休眠函数, 参数为毫秒 */
export const sleep = (ms: number): Promise<void> => {return new Promise(resolve => setTimeout(resolve, ms));
};/** 分页数据类型 */
export type PageUtils<T> = {/** 总记录数 */totalCount: number;/** 每页记录数 */pageSize: number;/** 总页数 */totalPage: number;/** 当前页数 */currPage: number;/** 列表数据 */list: Array<T>;
};export const getStoreUser = () => {const res = sessionStorage.getItem("user-info");// const res = sessionStorage.getItem("user-info");console.log(res);return JSON.parse(res);
};
后端代码
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.fgbg</groupId><artifactId>webrtc</artifactId><version>1.0-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.5</version><relativePath/></parent><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><mybatisplus.version>3.3.1</mybatisplus.version><mysql.version>8.0.28</mysql.version><mssql.version>4.0</mssql.version><oracle.version>11.2.0.3</oracle.version><druid.version>1.1.13</druid.version><quartz.version>2.3.0</quartz.version><commons.lang.version>2.6</commons.lang.version><commons.fileupload.version>1.2.2</commons.fileupload.version><commons.io.version>2.5</commons.io.version><commons.codec.version>1.10</commons.codec.version><commons.configuration.version>1.10</commons.configuration.version><shiro.version>1.9.0</shiro.version><jwt.version>0.7.0</jwt.version><kaptcha.version>0.0.9</kaptcha.version><qiniu.version>7.2.23</qiniu.version><aliyun.oss.version>2.8.3</aliyun.oss.version><qcloud.cos.version>4.4</qcloud.cos.version><swagger.version>2.7.0</swagger.version><joda.time.version>2.9.9</joda.time.version><gson.version>2.8.5</gson.version><hutool.version>4.1.1</hutool.version><lombok.version>1.18.4</lombok.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><!-- https://mvnrepository.com/artifact/commons-io/commons-io --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version></dependency><dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>${commons.lang.version}</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>
FileController.java
import com.fgbg.common.R;
import com.fgbg.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;@RestController
@RequestMapping("/common/file")
public class FileController {@Autowired@Qualifier("localFileService")private FileService fileService;/*** 批量文件上传接口*/@RequestMapping("/uploadList")public R uploadBatch(@RequestParam("fileList") List<MultipartFile> fileList) throws IOException {ArrayList<String> ans = new ArrayList<>();for (MultipartFile file : fileList) {String url = fileService.uploadFile(file, UUID.randomUUID().toString().substring(0, 10)+ "-" + file.getOriginalFilename());ans.add(url);}return R.ok().put("data", ans);}/*** 上传文件接口*/@RequestMapping("/upload")public R upload(@RequestParam("file") MultipartFile file) throws IOException {String url = fileService.uploadFile(file, UUID.randomUUID().toString().substring(0, 10)+ "-" + file.getOriginalFilename());return R.ok().put("data", url);}/*** 下载接口*/@RequestMapping("/download/{fileName}")public void download(@PathVariable("fileName") String fileName, HttpServletRequest request, HttpServletResponse response) {fileService.downloadFile(fileName, request, response);}/*** 删除接口*/@RequestMapping("/delete")public R deleteFile(@RequestParam String fileName) {boolean flag = fileService.deleteFile(fileName);return R.ok().put("data", flag);}
}
FileService.java
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public interface FileService {/*** 上传图片, 返回url*/String uploadFile(MultipartFile file, String fileName) throws IOException;/*** 下载图片*/void downloadFile(String fileName, HttpServletRequest request, HttpServletResponse response);/*** 删除图片*/boolean deleteFile(String fileName);
}
LocalFileServiceImpl.java
import com.fgbg.service.FileService;
import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;/*** 基于本地的文件管理服务*/
@Service("localFileService")
public class LocalFileServiceImpl implements FileService {/*** 文件访问域名(请求下载的接口)*/private static final String DOMAIN = "http://localhost:9006/api_demo/common/file/download/";/*** 文件物理存储位置*/private static final String STORE_DIR = "D:\\java_code\\webrtc\\src\\main\\resources\\file";/*** 上传图片, 返回url** @param file* @param fileName*/@Overridepublic String uploadFile(MultipartFile file, String fileName) throws IOException {// 获取文件流InputStream is = file.getInputStream();// 在服务器中存储文件FileUtils.copyInputStreamToFile(is, new File(STORE_DIR + fileName));// 返回文件urlString url = DOMAIN + fileName;System.out.println("文件url: " + url);return url;}/*** 下载图片** @param fileName*/@Overridepublic void downloadFile(String fileName, HttpServletRequest request, HttpServletResponse response) {// 获取真实的文件路径String filePath = STORE_DIR + fileName;System.out.println("++++完整路径为:"+filePath);try {// 下载文件// 设置响应头response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);// 读取文件内容并写入输出流Files.copy(Paths.get(filePath), response.getOutputStream());response.getOutputStream().flush();} catch (IOException e) {response.setStatus(404);}}/*** 删除图片** @param fileName*/@Overridepublic boolean deleteFile(String fileName) {// 获取真实的文件路径String filePath = STORE_DIR + fileName;System.out.println("++++完整路径为:"+filePath);File file = new File(filePath);return file.delete();}
}
组件封装
fileUpload.vue组件封装
<template><el-row><el-uploadv-model:file-list="localFileList"class="upload-demo"multiple:auto-upload="false":on-preview="handlePreview":on-remove="handleRemove"span="10"style="margin-right: 20px"><el-button type="primary">选择上传的文件</el-button></el-upload></el-row>
</template>
<script lang="ts" setup>
import { ref, watch } from "vue";
import type { UploadProps, UploadUserFile } from "element-plus";// 定义数据
const props = defineProps({fileList: {type: Array<UploadUserFile>,default: () => []}
});// 将父组件的数据拆解为子组件数据
const localFileList = ref(props.fileList);// 监听localFileList, 跟新父组件数据
watch(localFileList,newValue => {emits("update:fileList", newValue);},{deep: true}
);// 定义组件事件, 跟新fileList
const emits = defineEmits(["update:fileList"]);const handleRemove: UploadProps["onRemove"] = (file, uploadFiles) => {console.log(file, uploadFiles);
};const handlePreview: UploadProps["onPreview"] = uploadFile => {console.log(uploadFile);
};
</script>
组件调用
<script setup lang="ts">
import FileUpload from "./fileUpload.vue";
import { ref } from "vue";
import type { UploadUserFile } from "element-plus";
import { ElMessage } from "element-plus";
import { uploadBatch } from "/src/api/file.ts";const fileList = ref<Array<UploadUserFile>>();const submit = () => {console.log(fileList.value);// 封装formDataconst data = new FormData();fileList.value.forEach(element => {data.append("fileList", element.raw);});uploadBatch(data).then(res => {console.log(res);if (res.code === 0) {ElMessage.success("上传成功");} else {ElMessage.error("上传失败: " + res.msg);}});
};
</script><template><el-row><FileUpload v-model:fileList="fileList" /><el-button type="success" @click="submit">上传文件</el-button></el-row>
</template><style lang="scss" scoped></style>
封装组件使用的效果