Spring MVC如何展示多个从数据库读取后转Base64编码的图片
现有代码的问题
Iterable是一次性迭代对象,调用Iterables.size(postsMain)会遍历完整个集合,后续再调用iterator()获取到的迭代器已经没有元素了- 循环逻辑错误:每次循环都新建迭代器调用
next(),永远只会拿到第一个帖子的图片,所有元素都是同一张图 - 循环边界错误:
count <= size会多循环一次,触发NoSuchElementException异常 - 分开存储帖子列表和图片列表容易出现顺序不匹配的问题,后续维护难度高
正确实现方案(优先推荐)
直接给PostModel新增不映射数据库的临时字段存储对应图片的Base64编码,让每个帖子和自己的图片绑定,避免顺序错乱问题:
- 先修改
PostModel实体类,新增临时字段
// 加在PostModel类中,@Transient注解表示该字段不参与数据库ORM映射 @Transient private String base64Image; // 补上该字段的getter、setter方法 public String getBase64Image() { return base64Image; } public void setBase64Image(String base64Image) { this.base64Image = base64Image; }
- 修改控制器代码
@GetMapping("/") public ModelAndView home (Model model) { ModelAndView modelAndView = new ModelAndView("home"); Iterable<PostModel> postsMain = postRepository.findAll(); // 把Iterable转成List方便遍历处理 List<PostModel> postList = StreamSupport.stream(postsMain.spliterator(), false) .toList(); // 遍历每个帖子,给对应图片转Base64后存入自身临时字段 for (PostModel post : postList) { byte[] encodeBase64 = Base64.encodeBase64(post.getImage()); String base64Encoded = new String(encodeBase64, StandardCharsets.UTF_8); post.setBase64Image(base64Encoded); } // 仅需要传递处理好的帖子列表即可 modelAndView.addObject("posts_main", postList); return modelAndView; }
- 前端Thymeleaf渲染代码
直接遍历帖子列表,同时取出对应标题和图片即可:
<!-- 遍历所有帖子 --> <div th:each="post : ${posts_main}" class="post-item"> <h3 th:text="${post.title}">帖子标题</h3> <img class="post-image" th:src="@{'data:image/jpeg;base64,'+${post.base64Image}}"> </div>
不想修改实体类的替代方案
如果不希望改动PostModel,也可以保持两个列表传递,只要保证遍历顺序一致即可,控制器代码如下:
@GetMapping("/") public ModelAndView home (Model model) { ModelAndView modelAndView = new ModelAndView("home"); Iterable<PostModel> postsMain = postRepository.findAll(); List<PostModel> postList = StreamSupport.stream(postsMain.spliterator(), false) .toList(); List<String> contentImages = new ArrayList<>(); for (PostModel post : postList) { byte[] encodeBase64 = Base64.encodeBase64(post.getImage()); String base64Encoded = new String(encodeBase64, StandardCharsets.UTF_8); contentImages.add(base64Encoded); } modelAndView.addObject("contentImages", contentImages); modelAndView.addObject("posts_main", postList); return modelAndView; }
前端通过索引匹配对应图片:
<div th:each="post, iterStat : ${posts_main}" class="post-item"> <h3 th:text="${post.title}">帖子标题</h3> <img class="post-image" th:src="@{'data:image/jpeg;base64,'+${contentImages[iterStat.index]}}"> </div>
补充注意事项
- 建议用
StandardCharsets.UTF_8代替硬编码字符串"UTF-8",避免字符集不存在的异常 - 如果图片格式不只有jpeg,建议把图片格式也存在
PostModel字段中,动态拼接src前缀 - 大图片转Base64会导致页面体积大幅增加、加载变慢,流量消耗高,数据量大的场景建议改成单独的图片接口返回二进制流,前端用URL访问
内容的提问来源于stack exchange,提问作者Igor Gorski
相关产品推荐
相关产品推荐

