当前位置: 首页 > news >正文

SpringBoot3+Vue3+Mysql+Element Plus完成数据库存储blob类型图片,前端渲染后端传来的base64类型图片

前言

如果你的前后端分离项目采用SpringBoot3+Vue3+Element Plus,且在没有OSS(对象存储)的情况下,使用mysql读写图片(可能不限于图片,待测试)。

耗时三天,在踩了无数雷后,终于完成本功能。为你呈上。

本文完成功能:

  1. 前端采用Element发起上传图片请求,后端接收并将其存储到mysql。
  2. 后端相应图片base64数据,前端接收并渲染到页面。

1.前端上传到数据库

1.1前端上传图片

<el-form-item label="宠物照片" prop="pictureId">
<el-upload v-model="form.pictureId" :auto-upload="false" :action="''" :show-file-list="true" :on-change="handleAvatarChangeIcon"><el-button type="primary">选取文件</el-button>
</el-upload>
</el-form-item>

参数:

:auto-upload 是否自动上传

:action 自动上传的请求路径

:show-file-list 显示已上传的图片列表

:on-change 选中文件触发的change事件

自动上传与否都不影响,这里主要是判断一下图片的大小、后缀名。如下:

const handleAvatarChangeIcon = (file) => {// 限制文件后缀名const isJPG = file.raw.type === 'image/jpeg'const isPNG = file.raw.type === 'image/png'// 限制上传文件的大小const isLt5M = file.raw.size / 1024 / 1024 < 5if (!isPNG && !isJPG) {ElMessage.error('图片只能是 JPG/PNG 格式')return false} else if (!isLt5M) {ElMessage.error('图片应在5MB以内')return false} else {// 发起请求let param = new FormData();// 文件为form data格式param.append("file", file.raw);post('/api/file/upload', param, (res) => {ElMessage.success('上传成功');// 返回值为图片idform.pictureId = res})}
}

1.2后端接收并保存数据库

controller

@RestController
@RequestMapping("/api/file")
public class FileController {@Resourceprivate FileService fileService;@PostMapping("/upload")public RestBean<String> upload(@RequestParam MultipartFile file) {Integer res = fileService.upload(file);return RestBean.success(String.valueOf(res));}
}

serviceImpl

@Service
public class FileServiceImpl implements FileService {@Resourceprivate FileMapper fileMapper;/*** 文件上传到数据库*/@Overridepublic Integer upload(MultipartFile file) throws IOException {// 获取文件原始名String originalFilename = file.getOriginalFilename();// 获取文件后缀名String endName = "png";if (originalFilename != null) {endName = originalFilename.substring(originalFilename.lastIndexOf("."));}// 拼接文件名String filename = UUID.randomUUID() + endName;Integer pictureId;// 创建图片对象byte[] fileBytes = file.getBytes();Picture picture = new Picture();picture.setName(filename);picture.setPicData(fileBytes);// 上传数据库fileMapper.upload(picture);pictureId = picture.getId();// 返回图片idreturn pictureId;}
}

mapper.xml

<mapper namespace="com.ycb.mapper.FileMapper"><insert id="upload" useGeneratedKeys="true" keyProperty="id">insert into `pet-adoption`.picture(name, pic_data)value (#{name}, #{picData})</insert>
</mapper>

数据库设计

在这里插入图片描述

2.前端从数据库获取图片并渲染

2.1后端从数据库中获取

entity

public class PetAndBulVO {/*** 照片*/private byte[] picData;
}

controller

如果是一个图片数据直接封装到实体类,很多数据就封装成集合

@RequestMapping("/api/pet")
public class PetController {@Resourceprivate PetService petService;@GetMapping("/getAllPB")public RestBean<List<PetAndBulVO>> getAll() {List<PetAndBulVO> pets = petService.getAll();return RestBean.success(pets);}
}

serviceImpl

@Service
public class PetServiceImpl implements PetService {@Resourceprivate PetMapper petMapper;@Overridepublic List<PetAndBulVO> getAll() {return petMapper.getAll();}
}

mapper.xml

<mapper namespace="com.ycb.mapper.PetMapper"><!--  一定要映射结果集  --><resultMap type="com.ycb.entity.vo.response.PetAndBulVO" id="petAndBulVO"><id column="pic_data" property="picData" javaType="byte[]" jdbcType="BLOB" typeHandler="org.apache.ibatis.type.BlobTypeHandler"/></resultMap><select id="getAll" resultMap="petAndBulVO">select *from `pet-adoption`.pet petjoin `pet-adoption`.picture p on p.id = pet.picture_id</select>

后端返回的图片数据如下:

在这里插入图片描述

2.2前端接收数据并渲染

后端传来的数据是 base64 形式的,需要解码

// 解码
const base64ToUrl = (base64) => {return 'data:image/png;base64,' + base64
}// 获取数据
get('/api/pet/getAllPB', (data) => {for (let i = 0; i < data.length; i++) {data[i].picData = base64ToUrl(data[i].picData)}pBList.value = data
}, (err) => {ElMessage.error(err)
})

解码后的图片数据如下:

在这里插入图片描述

渲染是大坑!一定要 v-bind: 绑定 src

// v-for循环获取picData, v-for="(pb) in pBList"
<el-image v-bind:src="pb.picData"/>

《林克可爱图》
在这里插入图片描述

写在最后

虽然可以实现仅用mysql就能完成图片读写,但其性能堪忧。

很难,但贵在坚持。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • CSS 的 link 标签放在 head 标签之间的作用
  • 直播会议一体机安卓主板_5G智能会议一体机双屏异显设计
  • Delphi 12 重返雅典 (RAD Studio 12)
  • 华为云Ascend310服务器使用
  • Git系列之Git集成开发工具及git扩展使用
  • Android codec2 视频框架 之输入buffer
  • Perl语言用多线程爬取商品信息并做可视化处理
  • 网络安全之文件包含漏洞及其防护
  • Spring Boot 校验用户上传的图片文件
  • 安卓常见设计模式4------原型模式(Kotlin版)
  • 设备零部件更换ar远程指导系统加强培训效果
  • redis-cli 连接 sentinel架构的redis服务
  • 关于mac下pycharm旧版本没删除的情况下新版本2023安装之后闪退
  • 【AICFD案例教程】汽车外气动-AI加速
  • 一键创建PDF文档,高效管理您的文件资料
  • 《剑指offer》分解让复杂问题更简单
  • angular学习第一篇-----环境搭建
  • AzureCon上微软宣布了哪些容器相关的重磅消息
  • FastReport在线报表设计器工作原理
  • golang中接口赋值与方法集
  • Intervention/image 图片处理扩展包的安装和使用
  • java8 Stream Pipelines 浅析
  • javascript面向对象之创建对象
  • Markdown 语法简单说明
  • node-sass 安装卡在 node scripts/install.js 解决办法
  • 从零搭建Koa2 Server
  • 仿天猫超市收藏抛物线动画工具库
  • 基于MaxCompute打造轻盈的人人车移动端数据平台
  • JavaScript 新语法详解:Class 的私有属性与私有方法 ...
  • python最赚钱的4个方向,你最心动的是哪个?
  • 阿里云服务器购买完整流程
  • 扩展资源服务器解决oauth2 性能瓶颈
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • ​学习笔记——动态路由——IS-IS中间系统到中间系统(报文/TLV)​
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • #define 用法
  • #NOIP 2014# day.1 T3 飞扬的小鸟 bird
  • $(selector).each()和$.each()的区别
  • $nextTick的使用场景介绍
  • (12)Linux 常见的三种进程状态
  • (13)Latex:基于ΤΕΧ的自动排版系统——写论文必备
  • (2024最新)CentOS 7上在线安装MySQL 5.7|喂饭级教程
  • (Python) SOAP Web Service (HTTP POST)
  • (Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六
  • (zt)基于Facebook和Flash平台的应用架构解析
  • (动态规划)5. 最长回文子串 java解决
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (转载)CentOS查看系统信息|CentOS查看命令
  • .bat批处理(一):@echo off
  • .gitignore文件设置了忽略但不生效
  • .net Application的目录
  • .Net Core 笔试1
  • .Net Core 中间件验签
  • .NET MVC之AOP
  • .net php 通信,flash与asp/php/asp.net通信的方法