无法从数据库加载图片到Thymeleaf页面的问题求助
Spring Boot + Thymeleaf 图片压缩存储后无法显示排查
问题概述
Spring Boot项目中使用Thymeleaf开发,图片经压缩后存入数据库,读取时先解压再转换为Base64格式,但Thymeleaf页面无法正常显示图片。
相关代码与逻辑
1. Thymeleaf页面(editprofile.html)
<form th:action="@{/updateProfile}" method="post" class="signin-form" th:object="${editprofile}" enctype="multipart/form-data"> <div class="title-main text-center mx-auto mb-md-5 mb-4" style="max-width:500px;"> <h5 class="footer-title-29">Personal Details</h5> <div class="col-sm-6 profile_Pic"> <img id="thumbnail" th:src="*{'data:image/jpg;base64,'+profile_pic}" width="200" /> </div> </div> <br><br> <div class="input-grids"> <label class="control-label" for="name">Name:</label> <input type="text" th:field="*{name}" id="name" class="contact-input" /> <div class="row"> <div class="col-sm-6"> <label class="control-label" for="mobileNumber">Mobile Number:</label> <input type="text" th:field="*{mobileNumber}" id="mobileNumber" class="contact-input" /> </div> <div class="col-sm-6"> <label class="control-label" for="email">Email:</label> <input type="text" th:field="*{email}" id="email" class="contact-input" /> </div> </div> </div> <div class="title-main text-center mx-auto mb-md-5 mb-4" style="max-width:500px;"> <h5 class="footer-title-29">Address Details</h5> </div> <div class="input-grids"> <label class="control-label" for="address1">Address Line 1:</label> <input type="text" th:field="*{address1}" id="address1" class="contact-input" /> <label for="address2">Address Line 2:</label> <input type="text" th:field="*{address2}" id="address2" class="contact-input" /> <label class="control-label" for="city">City:</label> <input type="text" th:field="*{city}" id="city" class="contact-input" /> <div class="row"> <div class="col-sm-6"> <label class="control-label" for="state">State:</label> <input type="text" th:field="*{state}" id="state" class="contact-input" /> </div> <div class="col-sm-6"> <label class="control-label" for="zipCode">Zip Code:</label> <input type="text" th:field="*{zipCode}" id="zipCode" class="contact-input" /> </div> <div class="col-sm-6"> <label class="control-label" for="fileImage">Upload image</label> <input type="file" name="fileImage" accept="image/*" id="fileImage" /> </div> </div> </div> <div class="col-md-8 login-center text-start"> <button class="btn btn-style btn-style-3 text-left">Update</button> <a th:href="@{/dashboard}" class="new-user text-right"> <button class="btn btn-style btn-style-3 text-left" th:formaction="@{/displayProfile}">BACK</button></a> </div> </form>
2. 图片压缩工具类(ImageUtil.java)
public static byte[] compressImage(byte[] data) { Deflater deflater = new Deflater(); deflater.setLevel(Deflater.BEST_COMPRESSION); deflater.setInput(data); deflater.finish(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length); byte[] tmp = new byte[1024]; while (!deflater.finished()) { int size = deflater.deflate(tmp); outputStream.write(tmp, 0, size); } try { outputStream.close(); } catch (Exception e) { } return outputStream.toByteArray(); } public static byte[] decompressImage(byte[] data) { Inflater inflater = new Inflater(); inflater.setInput(data); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length); byte[] tmp = new byte[1024]; try { while (!inflater.finished()) { int count = inflater.inflate(tmp); outputStream.write(tmp, 0, count); } outputStream.close(); } catch (Exception exception) { } return outputStream.toByteArray(); }
3. 图片上传逻辑
person.getAddress().setProfile_pic(ImageUtil.compressImage(file.getBytes())); personRepository.save(person);
4. 图片读取逻辑
图片已成功存入数据库,读取时执行以下逻辑仍无法显示:
byte[] decomImage = ImageUtil.decompressImage(person.getAddress().getProfile_pic()); byte[] encodeBase64 = Base64.getEncoder().encode(decomImage); String base64Encoded = new String(encodeBase64, "UTF-8");
将base64Encoded赋值给pojoprofile的encoded_image属性。
5. 控制器代码
编辑页面控制器
@RequestMapping(value = "/EditProfile") public ModelAndView EditProfile(Model model, HttpSession httpSession){ PersonPojo person=(PersonPojo) httpSession.getAttribute("loggedInPerson"); Profile pojoprofile1=new Profile(); pojoprofile1.setName(person.getName()); pojoprofile1.setEmail(person.getEmail()); pojoprofile1.setMobileNumber(person.getMobileNumber()); if(person.getAddress()!=null&&person.getAddress().getAddressId()>0){ pojoprofile1.setAddress1(person.getAddress().getAddress1()); pojoprofile1.setAddress2(person.getAddress().getAddress2()); pojoprofile1.setCity(person.getAddress().getCity()); pojoprofile1.setState(person.getAddress().getState()); pojoprofile1.setZipCode(person.getAddress().getZip_code()); pojoprofile1.setProfile_pic(Base64.getEncoder().encode(person.getAddress().getProfile_pic())); // pojoprofile1.setProfile_pic(person.getAddress().getProfile_pic()); } ModelAndView editprofile=new ModelAndView("EditProfile.html"); editprofile.addObject("editprofile",pojoprofile1); return editprofile; }
更新资料控制器
@RequestMapping(value = "/updateProfile") public String updateProfile(@RequestParam("fileImage") MultipartFile file, @Valid @ModelAttribute("editprofile") Profile profile, Errors errors, HttpSession httpSession) throws IOException { if(errors.hasErrors()){ return "EditProfile.html"; } PersonPojo person=(PersonPojo) httpSession.getAttribute("loggedInPerson"); person.setName(profile.getName()); person.setEmail(profile.getEmail()); person.setMobileNumber(profile.getMobileNumber()); if(person.getAddress() == null || !(person.getAddress().getAddressId()>0)){ person.setAddress(new AddressPoJO()); } person.getAddress().setAddress1(profile.getAddress1()); person.getAddress().setAddress2(profile.getAddress2()); person.getAddress().setCity(profile.getCity()); person.getAddress().setState(profile.getState()); person.getAddress().setZip_code(profile.getZipCode()); person.getAddress().setProfile_pic(ImageUtil.compressImage(file.getBytes())); personRepository.save(person); httpSession.setAttribute("loggedInPerson", person); return "redirect:/dashboard"; }
资料展示控制器
@RequestMapping("/displayProfile") public ModelAndView Myprofile(HttpSession httpSession) throws UnsupportedEncodingException { Profile pojoprofile=new Profile(); PersonPojo person=(PersonPojo) httpSession.getAttribute("loggedInPerson"); pojoprofile.setName(person.getName()); pojoprofile.setEmail(person.getEmail()); pojoprofile.setMobileNumber(person.getMobileNumber()); if(person.getAddress()!=null&&person.getAddress().getAddressId()>0){ log.info("Inside the if"+new MyProfile().getClass().toString()); pojoprofile.setAddress1(person.getAddress().getAddress1()); pojoprofile.setAddress2(person.getAddress().getAddress2()); pojoprofile.setCity(person.getAddress().getCity()); pojoprofile.setState(person.getAddress().getState()); pojoprofile.setZipCode(person.getAddress().getZip_code()); byte[] encodeBase64 = Base64.getEncoder().encode(ImageUtil.decompressImage(person.getAddress().getProfile_pic())); pojoprofile.setProfile_pic(encodeBase64); }else { pojoprofile.setAddress1(" Not available "); pojoprofile.setAddress2(" Not Available"); pojoprofile.setZipCode(" Not Available"); pojoprofile.setState(" Not Available"); pojoprofile.setCity(" Not Available"); } return new ModelAndView("profile.html").addObject("profile",pojoprofile); }
排查与修复方案
1. 核心问题:Base64数据类型不匹配
当前控制器中,部分逻辑将byte[]类型的Base64数据赋值给Profile的profile_pic字段,而Thymeleaf拼接字符串时,会调用byte[]的toString()方法,生成[B@xxxxxxx这类无效的内存地址字符串,而非正确的Base64编码。
修复步骤:
- 将
Profile类的profile_pic字段类型改为String; - 在控制器中直接生成Base64字符串赋值:
// 编辑页面控制器修正 byte[] decompressed = ImageUtil.decompressImage(person.getAddress().getProfile_pic()); String base64Str = Base64.getEncoder().encodeToString(decompressed); pojoprofile1.setProfile_pic(base64Str);// 展示控制器修正 String base64Str = Base64.getEncoder().encodeToString(ImageUtil.decompressImage(person.getAddress().getProfile_pic())); pojoprofile.setProfile_pic(base64Str);
2. 压缩/解压异常排查
ImageUtil中的异常被静默捕获,无法得知是否解压失败。修改工具类添加异常日志:
public static byte[] decompressImage(byte[] data) { Inflater inflater = new Inflater(); inflater.setInput(data); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length); byte[] tmp = new byte[1024]; try { while (!inflater.finished()) { int count = inflater.inflate(tmp); outputStream.write(tmp, 0, count); } outputStream.close(); } catch (Exception exception) { exception.printStackTrace(); throw new RuntimeException("图片解压失败", exception); } return outputStream.toByteArray(); }
3. 图片类型兼容性优化
页面中固定使用image/jpg,若上传PNG等其他格式图片会导致显示异常,可动态获取图片MIME类型,或改为image/*兼容更多类型:
<img id="thumbnail" th:src="*{'data:image/*;base64,'+profile_pic}" width="200" />
内容的提问来源于stack exchange,提问作者Nikhil Mathew
相关产品推荐
相关产品推荐

