开发思路
在做到这个需求的时候,首先想到的是模仿尚硅谷的谷粒学苑,使用oss存储,实现在数据库中能存储图片上传后的url这样是最方便的。
但是在开发过程中,发现获取到oss服务器存在困难,所以想到将图片上传功能改成简单的将图片保存到本地,数据库的字段存储的是保存图片的名称,再使前端动态渲染本地的图片即可
后端实现上传功能
在这里简单地实现了图片上传的功能
主要使用的就是java的IO流对图片的一系列操作,这样就可以将图片存储到本地
并且为了防止图片太大不能上传,要在springboot的配置文件中设置上传的最大大小
#单个数据的大小
spring.servlet.multipart.max-file-size = 100Mb
#总数据的大小
spring.servlet.multipart.max-request-size=100Mb
下方的java代码在swagger中测试的效果是
@RestController
@RequestMapping("/riskservice.MonitorData/patrolUpload")
@Api(description = "监测数据-巡视巡察数据-图片上传")
@CrossOrigin
@Slf4j
public class UploadPictureController {
// https://blog.csdn.net/qq_41725313/article/details/124678465
@PostMapping("/addCoverPic")
public R addCoverPic(@RequestParam("file") MultipartFile upload){
String filePath="C:/学校/刘老师任务/风险预警/2、项目源码/vue-admin-template-master/static/patrol_images/";
// String filePath="D:/Template/picture";
File file =new File(filePath);
if(!file.exists()){
file.mkdirs();
}
// 获取原始图片的扩展名
String originalFileName = upload.getOriginalFilename();
// 生成随机数防止图片重名
String newFileName = UUID.randomUUID()+originalFileName;
// 去掉随机生成的名字中的特殊字符
newFileName = newFileName.replace("(","");
newFileName = newFileName.replace(")","");
// 设置图片的存储地址
String newFilePath = filePath+newFileName;
String newFileName2 = "/picture/"+newFileName;
try {
upload.transferTo(new File(newFilePath));
//将传来的文件写入新建的文件
}catch (IllegalStateException | IOException e) {
//处理异常
}
log.info("图片保存的地址是",newFilePath);
return R.ok().data("fileName", newFileName).data("filePath",filePath);
}
}
前端实现上传以及回显
前端实现上传
index.vue,图片上传功能的组件 使用效果是
<template>
<!--
如果要改成自动上传的话
action 要加上
action="http://localhost:8081/riskservice.MonitorData/patrolUpload/addCoverPic"
并且
:auto-upload
要改成
:auto-upload="true"
-->
<el-upload
class="custom_el_upload"
:drag="drag"
action=""
:accept="accept.toString()"
:limit="limit"
:on-exceed="exceedHandle"
:on-change="handleUploading"
:on-remove="removeHandle"
:file-list="fileList"
:auto-upload="false"
list-type="picture"
>
<template v-if="drag">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
</template>
<el-button size="small" type="primary" v-else>点击上传</el-button>
<div class="el-upload__tip" slot="tip" v-if="intro">{{ intro }}</div>
<div class="el-upload__tip" slot="tip" v-else>
只能上传{{ accept.toString() }}文件,最多上传{{ limit }}个文件
</div>
</el-upload>
</template>
<script>
export default {
props: {
value: { default: "" },
intro: { default: "" },
limit: { type: Number, default: 1 },
drag: { type: Boolean, default: true },
accept: { type: Array, default: () => [".png", ".jpg", ".jpeg"] }
},
data() {
return {
fileList: []
};
},
mounted() {},
methods: {
handleUploading(file, fileList) {
this.updateList(file, fileList);
},
removeHandle(file, fileList) {
this.updateList(file, fileList);
},
updateList(file, fileList) {
if (!this.beforeUpload(file)) return; //上传文件不符要求
const list = fileList.map(item => {
return item.raw;
});
this.$emit("input", list);
},
//上传文件前检查文件类型和大小
beforeUpload(file) {
let type = file.name.substring(file.name.lastIndexOf("."));
const isExcel = this.accept.includes(type);
if (!isExcel) {
this.$message.error(`上传文件只能是 ${this.accept.toString()} 格式!`);
}
if (!isExcel) this.fileList = [];
return isExcel;
},
exceedHandle(files, fileList) {
this.$message.error(`上传失败,您已经超出上传文件的数量限制`);
}
}
};
</script>
<style scoped lang="scss">
.custom_el_upload {
::v-deep .el-upload-dragger {
height: 130px;
}
::v-deep .el-icon-upload {
margin-top: 20px;
}
}
</style>
1、参数的意义 :
v-model="pictureFileUpload" : 上传后文件存放的数据,此数据为数组类型,定义为pictureFileUpload :accept="accept.toString()" :上传文件的指定类型,定义为accept :drag="true" : 是否可以拖动上传
<el-form-item label="现场照片">
<uploadForm
v-model="pictureFileUpload"
:accept="accept.toString()"
:drag="true"
/>
</el-form-item>
2、参数定义
<script>
// 先在此处将我设置好的上传模板引用进来
import uploadForm from "./index.vue";
export default {
props: {
// accept上传文件的指定类型,这个直接复制粘贴即可
accept: {
type: Array,
default: () => [".png", ".PNG", ".jpg", "JPG", ".jpeg", ".JPEG"]
}
},
data() {
return {
// 最后上传完成的文件存放在这里
pictureFileUpload: [], // 上传图片辅助数组
};
},
components: {
// 将import的上传模板注册为可以使用的组件,所以上方可以直接用<uploadForm />使用组件
uploadForm
},
}
</script>
3、上传完成后将文件传送回后端
// 先上传图片,得到图片存储的路径
console.log("此时添加的图片是", this.pictureFileUpload[0]);
// 此步需要将原本的数据类型转成FormData类型,后端才可以接收到数据
let formdata = new FormData();
formdata.append("file", this.pictureFileUpload[0]);
// 转换FormData类型完成
// 直接调用接口传递参数到后端
// 此处的参数就是上方的后端代码
await patrolApi.patrolUpload(formdata).then(res => {
this.patrolInfo.photo = res.data.fileName;
console.log("上传完成, 文件的位置是", this.patrolInfo.photo);
});
4、传递到后端的接口
patrolUpload(data) {
return request({
// 此处一定要修改请求头,加上下面这几行代码,要不然会传送失败
headers: {
"Content-Type": "multipart/form-data"
},
// 添加请求头结束
url: `/riskservice.MonitorData/patrolUpload/addCoverPic`,
method: 'post',
data
})
}
图片回显讲解
由于文件是上传到项目中的static文件夹下,所以可以直接动态读取图片显示
1、数据封装
由于在数据库中存的只有文件名,方便发布之后修改代码,所以需要手动做路径的拼接
将图片的路径加上"/static/patrol_images/" 这样前端可以回显
getList() {
patrolApi.getAllInfo().then(res => {
this.list = res.data.list;
for (var item in this.list) {
this.list[item].photo = String(
"/static/patrol_images/" + this.list[item].photo
);
}
console.log("页面创建时获取到的数据是", this.list);
});
},
2、放在前端展示
数据回显直接读取文件即可显示加上vue注解 :src
注意,要让图片回显,路径一定要拼接正确,要是"/static/patrol_images/"+"正确的文件名"
<el-form-item label="现场照片">
<el-image class="table-td-thumb" :src="patrolInfo.photo"></el-image>
</el-form-item>
3、点击图片,使图片预览
在完成了上述操作后,应该就能使图片进行正常的回显,现在给图片组件添加上点击图片预览功能
1、首先给el-image组件加上:preview-src-lists属性使其能够进行预览
2、再给图片加上点击函数,使其点击后能触发预览
<el-image
class="table-td-thumb"
:src="scope.row.photo"
:preview-src-list="srcList"
@click="vbs(scope.row.photo)"
></el-image>
3、在data中定义存放预览图片的数组
data() {
return {
srcList: [] // 图片预览数组
};
},
4、编写点击后使图片预览的方法
methods: {
// 点击图片后添加预览
vbs(photo) {
// 清除原本的预览
this.srcList = [];
this.srcList.push(photo);
}
}
最后就能完成预览,实现的效果为
点击图片可实现图片预览