最近项目有个需求需要在前端vue上传图片,然后在后端将图片存到本地的一个文件夹下。
1、vue
这里是将上传图片封装成了一个组件来使用,组件名为 upload-image.vue
<template>
<div class="clearfix">
<!--
name —— 向后端传递数据时会要用到
action —— 后端路径
-->
<a-upload
name="faceImage"
:headers="headers"
:action="fileurl"
list-type="picture-card"
v-model:file-list="fileList"
:before-upload="beforeUpload"
@preview="handlePreview"
@change="handleChange"
>
<div v-if="fileList.length < imgNum">
<a-icon type="plus" />
<div class="ant-upload-text">
上传图片
</div>
</div>
</a-upload>
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
<img alt="example" style="width: 100%" :src="previewImage" />
</a-modal>
</div>
</template>
<script>
import mitt from "@/utils/mitt";
function getBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
export default {
name: "uoload-image",
data(){
return{
imgNum:1, //设置最多可以上传的图片数量
headers: {
'token': localStorage.getItem('token'),
},
fileurl:"/api/file/upload", //上传到后端的路径
previewVisible: false,
previewImage: '',
fileList: []
}
},
methods:{
handleCancel() {
this.previewVisible = false;
},
async handlePreview(file) {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj);
}
this.previewImage = file.url || file.preview;
this.previewVisible = true;
},
// 检查图片格式和图片大小
beforeUpload(file){
//图片格式限制为 jpeg、png
const isJpgOrPng = file.type === 'image/jpeg' || file.type === "image/png";
if (!isJpgOrPng){
this.$message.error("请选择jpg/png图片");
}
//图片大小限制为 2M以内
const isLt2M = file.size/1024/1024 <= 2;
if (!isLt2M){
this.$message.error("图片大小不能超过2MB,请重新上传");
}
return isJpgOrPng && isLt2M;
},
handleChange ({ file, fileList }) {
this.fileList = fileList;
if (file.hasOwnProperty('error')){
this.$message.error("图片上传失败");
return;
}
},
}
}
</script>
<style scoped>
.ant-upload-select-picture-card i {
font-size: 32px;
color: #999;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
</style>
注意:后端路径有个地方需要注意,关于这里的 ' /api ',我在vue.config.js做了跨域处理
2、后端springboot
@RestController
@RequestMapping("/file")
public class UploadImageController {
//这里的 faceImage 就是 a-upload 的 name 属性
@PostMapping("/upload")
public void uploadImage(@RequestParam("faceImage") MultipartFile pic) {
/*
* 编码为字符串
*/
String base64Str = "";
try {
base64Str = Base64Utils.encodeToString(pic.getBytes()); //将图片转化为base64格式
String imgName = pic.pic.getOriginalFilename(); //获取到图片原本的名字
storeImageAtLocal(base64Str, imgName); //为了方便在其他地方调用,这里封装成了一个工具类
}catch (IOException e){
e.printStackTrace();
}
}
}
public class UploadUtil {
//这里的pathName表示 你要存到哪,图片名叫啥,如D:\\resources\\image\\smile.jpg
public static void storeImageAtLocal(String base64ImgData,String pathName){
Base64.Decoder decoder = Base64.getDecoder();
byte[] bytes = decoder.decode(base64ImgData);
/*
* 字节流转文件
*/
FileOutputStream fos = null;
try {
fos = new FileOutputStream(pathName);
fos.write(bytes);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//本地图片转base64编码数据
public static String getImageBase64Data(String localPath){
File file = new File(localPath); //URL url = new URL(src);
byte[] data = null;
try {
InputStream in = new FileInputStream(file); //InputStream in = url.openStream();
data = new byte[in.available()];
in.read(data);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
Base64.Encoder encoder = Base64.getEncoder();
return encoder.encodeToString(data);
}
}