文章目录
- 效果
- 前端代码
- 后端代码
- 组件封装
效果
前端代码
/views/file/file.vue
<template>
<el-row>
<el-upload
v-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);
// 封装formData
const 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
*/
@Override
public String uploadFile(MultipartFile file, String fileName) throws IOException {
// 获取文件流
InputStream is = file.getInputStream();
// 在服务器中存储文件
FileUtils.copyInputStreamToFile(is, new File(STORE_DIR + fileName));
// 返回文件url
String url = DOMAIN + fileName;
System.out.println("文件url: " + url);
return url;
}
/**
* 下载图片
*
* @param fileName
*/
@Override
public 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
*/
@Override
public 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-upload
v-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);
// 封装formData
const 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>
封装组件使用的效果