1、前端(vue3+ts)
引入自定义组件
import UploadFile from "@/components/upload/UploadFile.vue";
<single-upload v-if="dialogForm.visible" v-model="form.deviceImageUrl"
@update:imageUrl="form.deviceImageUrl = $event" />
2、后端接口(springboot)
1、controller
这里使用到了前端静态文件访问:【spring boot静态资源访问】前端通过http请求访问静态资源-CSDN博客
/**
* 上传图片
*
* @param file 图片
* @return 路径
*/
@Transactional(rollbackFor = Exception.class)
@PostMapping("/upload/image")
public Resp upload(MultipartFile file) {
String url = UploadUtil.uploadFile(file, '需要存放的图片路径');
Map<String, String> map = new HashMap<>();
map.put("imageUrl", url);
//这里返回的是图片的http接口
map.put("imageHttpUrl", ServiceConfig.getBaseUrl() + "/api/resource/images/" + url);
return Resp.success(map);
}
2、utils
/**
* 上传文件到指定目录
*
* @param file 文件
* @param filePath 路径
* @return 文件路径
*/
public static String uploadFile(MultipartFile file, String filePath) {
try {
//获取文件名
String fileName = file.getOriginalFilename();
//获取图片后缀名
String suffixName = FileUtil.extName(fileName);
//获取时间戳(毫秒)
long currentTimeMillis = System.currentTimeMillis();
String path = DateUtil.today() + "/" + currentTimeMillis;
if (StrUtil.isNotBlank(suffixName)){
path = DateUtil.today() + "/" + currentTimeMillis + StrUtil.DOT + suffixName;
}
//判断文件夹是否存在,不存在则创建
if (!FileUtil.exist(filePath + DateUtil.today())) {
FileUtil.mkdir(filePath + DateUtil.today());
}
File uploadFile = new File(filePath + path);
//将临时文件转存到指定磁盘位置
file.transferTo(uploadFile);
//返回提示信息
return path;
} catch (Exception e) {
e.printStackTrace();
}
return filePath;
}
3、自定义upload组件 —— xxx.vue
<template>
<!-- 上传组件 -->
<el-upload
class="single-uploader"
:show-file-list="false"
list-type="picture-card"
:before-upload="handleBeforeUpload"
:http-request="uploadFile"
>
<img v-if="imageUrl" :src="imageUrl" class="single"/>
<el-icon v-else class="single-uploader-icon">
<i-ep-plus/>
</el-icon>
</el-upload>
</template>
<script setup lang="ts">
import {ElMessage, UploadRawFile, UploadRequestOptions} from "element-plus";
import request from "@/utils/request";
import {defineEmits} from "vue";
const emits = defineEmits(["update:imageUrl"]);
const props = defineProps({
modelValue: {
type: String,
default: ""
}
});
const imgUrlData = ref<any>([]);
const imageUrl = ref("");
onMounted(() => {
imageUrl.value = props.modelValue;
});
watch(imgUrlData, (newVal) => {
emits("update:imageUrl", newVal.imageUrl);
});
/**
* 自定义图片上传
*
* @param options
*/
async function uploadFile(options: UploadRequestOptions): Promise<any> {
request.postUpload("tool/upload/image", {file: options.file})
.then((response: any) => {
imageUrl.value = response.data.imageHttpUrl;
imgUrlData.value = response.data;
ElMessage.success(response.msg);
})
.catch((error) => {
console.log(error);
ElMessage.error("网络异常");
});
}
/**
* 限制用户上传文件的格式和大小
*/
function handleBeforeUpload(file: UploadRawFile) {
if (file.size > 10 * 1048 * 1048) {
ElMessage.warning("上传图片不能大于10M");
return false;
}
return true;
}
</script>
<style scoped>
.single-uploader .single {
display: block;
width: 178px;
height: 178px;
}
</style>
<style>
.single-uploader .el-upload {
position: relative;
overflow: hidden;
cursor: pointer;
border: 1px dashed var(--el-border-color);
border-radius: 6px;
transition: var(--el-transition-duration-fast);
}
.single-uploader .el-upload:hover {
border-color: var(--el-color-primary);
}
.el-icon.single-uploader-icon {
width: 178px;
height: 178px;
font-size: 28px;
color: #8c939d;
text-align: center;
}
</style>