本文描述场景为
展示:后端从数据库中查询图片对象列表,返回前端展示
多图片展示
先看一下后端表实体
import com.zpmc.common.domain.BaseEntity;
import io.swagger.annotations.ApiModel;
import lombok.*;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Blob;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ApiModel
@Entity
@Table(name = "tb_image")
public class Image extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "task_id")
private Integer taskId;
@Column(name = "directory", length = 200)
private String directory;
@Column(name = "file")
private Blob file;
@Column(name = "remark", length = 200)
private String remark;
@Column(name = "STATUS", length = 200)
private Integer status;
}
显然,图片在数据库中使用的是Blob类型,本人数据库用的是MediumBlob。
MySQL的四种BLOB类型
类型 大小(单位:字节)
TinyBlob 最大 255
Blob 最大 65K
MediumBlob 最大 16M
LongBlob 最大 4G
思路
- Blob属性先转成字节数组
- 字节数组转成base64字符串
- 前端接收base64解析展示
当然,后端返回给前端,还差个VO,因为Blob类型没法传。
后端
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ImageVO {
private static final long serialVersionUID = 1L;
private Integer id;
private Integer taskId;
private String directory;
private String file;
private String remark;
private Integer status;
}
Controller层
@ApiOperation("查看图片列表")
@GetMapping("getImageList")
public Result getImageList() throws Exception {
return imageService.getImageList();
}
Service层
@Override
public Result getImageList() throws SQLException {
List<ImageVO> voList=new ArrayList<>();
List<Image> all = imageRepo.findAll();
for (Image item : all) {
ImageVO vo = new ImageVO();
vo.setId(item.getId());
vo.setDirectory(item.getDirectory());
vo.setRemark(item.getRemark());
vo.setStatus(item.getStatus());
vo.setTaskId(item.getTaskId());
Blob blob = item.getFile();
// 将 Blob 数据转换为字节数组
byte[] data = blob.getBytes(1, (int) blob.length());
// 将字节数组转换为 Base64 编码字符串
vo.setFile(Base64.getEncoder().encodeToString(data));
voList.add(vo);
}
return Result.success(voList);
}
前端
<div v-for="image in images" :key="image.id" style="display: inline-block;">
<el-image class="selectEffect" :src="image.file" :fit="fit" alt="加载失败" :title="image.id" style="width: 200px; height: 200px; margin-right: 10px;cursor: pointer;"
@click="handleImageClick(image)">
</el-image>
<div>
<center>
{{ image.id }}
<!-- {{ image.file }} -->
<input type="checkbox" v-model="selectedImages" :value="image">
</center>
</div>
data() {
return {
fit: "fill",
selectedImages: [],
images: [],
};
},
beforeDestroy() {
// 在组件销毁前,释放URL对象
// URL.revokeObjectURL(this.image);
for (let i = 0; i < this.images.length; i++) {
URL.revokeObjectURL(this.images[i].file);
}
},
methods: {
getImageList() {
Image.getImageList()
.then((res) => {
let arr = res.data;
for (let i = 0; i < arr.length; i++) {
arr[i].file = "data:image/png;base64," + arr[i].file;
}
this.images = arr;
console.log("---------------");
console.log(this.images);
console.log("---------------");
})
.catch((err) => {
console.log("err", err);
});
}
}