Foreword
If your front-end and back-end separation project uses SpringBoot3 + Vue3 + Element Plus, and without OSS (object storage), use mysql to read and write images (may not be limited to images, to be tested).
It took three days and after stepping on countless minefields, this function was finally completed. Presented to you.
Complete functions of this article:
- The front end uses Element to initiate an image upload request, and the back end receives and stores it in mysql.
- The back-end corresponding image base64 data is received by the front-end and rendered to the page.
1. Upload the front end to the database
1.1 Front-end upload pictures
<el-form-item label="Pet Photo" prop="pictureId"> <el-upload v-model="form.pictureId" :auto-upload="false" :action="''" :show-file-list="true" :on-change="handleAvatarChangeIcon"> <el-button type="primary">Select file</el-button> </el-upload> </el-form-item>
parameter:
:auto-upload whether to automatically upload
:action request path for automatic upload
:show-file-list displays the uploaded image list
:on-change Change event triggered by selected file
It doesn’t matter whether it is automatically uploaded or not. The main thing here is to determine the size and suffix of the image. as follows:
const handleAvatarChangeIcon = (file) => {<!-- --> //Limit file suffix name const isJPG = file.raw.type === 'image/jpeg' const isPNG = file.raw.type === 'image/png' // Limit the size of uploaded files const isLt5M = file.raw.size / 1024 / 1024 < 5 if (!isPNG & amp; & amp; !isJPG) {<!-- --> ElMessage.error('Pictures can only be in JPG/PNG format') return false } else if (!isLt5M) {<!-- --> ElMessage.error('Picture should be within 5MB') return false } else {<!-- --> // Initiate request let param = new FormData(); //The file is in form data format param.append("file", file.raw); post('/api/file/upload', param, (res) => {<!-- --> ElMessage.success('Upload successful'); //The return value is the image id form.pictureId = res }) } }
1.2 backend receives and saves the database
controller
@RestController @RequestMapping("/api/file") public class FileController {<!-- --> @Resource private 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 {<!-- --> @Resource private FileMapper fileMapper; /** * Upload files to database */ @Override public Integer upload(MultipartFile file) throws IOException {<!-- --> // Get the original name of the file String originalFilename = file.getOriginalFilename(); // Get the file extension name String endName = "png"; if (originalFilename != null) {<!-- --> endName = originalFilename.substring(originalFilename.lastIndexOf(".")); } // Splice file names String filename = UUID.randomUUID() + endName; Integer pictureId; //Create image object byte[] fileBytes = file.getBytes(); Picture picture = new Picture(); picture.setName(filename); picture.setPicData(fileBytes); //Upload database fileMapper.upload(picture); pictureId = picture.getId(); // Return image id return 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>
Database Design
2. The front end obtains images from the database and renders them
2.1 backend gets from database
entity
public class PetAndBulVO {<!-- --> /** * photo */ private byte[] picData; }
controller
If an image data is directly encapsulated into an entity class, a lot of data is encapsulated into a collection.
@RequestMapping("/api/pet") public class PetController {<!-- --> @Resource private 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 {<!-- --> @Resource private PetMapper petMapper; @Override public List<PetAndBulVO> getAll() {<!-- --> return petMapper.getAll(); } }
mapper.xml
<mapper namespace="com.ycb.mapper.PetMapper"> <!-- The result set must be mapped --> <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 pet join `pet-adoption`.picture p on p.id = pet.picture_id </select>
The image data returned by the backend is as follows:
2.2 Front-end receives data and renders
The data transmitted from the backend is in base64 format and needs to be decoded.
// decoding const base64ToUrl = (base64) => { return 'data:image/png;base64,' + base64 } // retrieve data 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) })
The decoded image data is as follows:
Rendering is a big pitfall! Be sure to v-bind: bind src
// v-for loop to obtain picData, v-for="(pb) in pBList" <el-image v-bind:src="pb.picData"/>
“Link Cute Picture”
Write at the end
Although it is possible to read and write images using only mysql, its performance is worrying.
It’s difficult, but persistence is important.