Spring Boot中如何将BLOB转换为Base64编码字符串返回?
问题
我有一个LanguageController类,其中包含如下方法:
@GetMapping("/languages") public ResponseEntity<List<Language>> getAllLanguages(@RequestParam(required = false) String name) { try { List<Language> languages = new ArrayList<Language>(); if (name == null) { languageRepository.findAll().forEach(languages::add); } else { languageRepository.findByNameContaining(name).forEach(languages::add); } if (languages.isEmpty()) { return new ResponseEntity<>(HttpStatus.NO_CONTENT); } return new ResponseEntity<>(languages, HttpStatus.OK); } catch (Exception e) { return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR); } }
Language类定义如下(省略了getter和setter以简化展示):
@Entity @Table(name = "languages") public class Language { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; @Column(name = "name") private String name; @Column(name = "audio") @Lob private Blob audio; @Column(name = "script") @Lob private Blob script; public Language() { } public Language(String name, Blob audio, Blob script) { this.name = name; this.audio = audio; this.script = script; } }
调用API接口时,得到如下JSON返回结果:
[ { "id": 1, "name": "Test Language", "audio": { "binaryStream": {}, "wrappedBlob": { "binaryStream": {}, "traceId": 26, "traceObjectName": "blob26" } }, "script": { "binaryStream": {}, "wrappedBlob": { "binaryStream": {}, "traceId": 27, "traceObjectName": "blob27" } } } ]
目前返回的是BLOB流信息,没有实际使用价值。我希望将BLOB转换为Base64编码后返回,但不清楚应该在哪个环节进行编码处理,恳请提供帮助。
解决方案
推荐优先使用**DTO(数据传输对象)**的方式处理,这是最清晰、符合分层架构的做法,避免直接修改实体类带来的耦合问题。以下是几种可行的实现方式:
方式1:使用DTO转换(推荐)
- 创建
LanguageDTO类,专门用于向前端返回数据:
public class LanguageDTO { private long id; private String name; private String audioBase64; private String scriptBase64; // 构造方法、getter、setter public LanguageDTO(long id, String name, String audioBase64, String scriptBase64) { this.id = id; this.name = name; this.audioBase64 = audioBase64; this.scriptBase64 = scriptBase64; } }
- 在Controller中添加转换逻辑,将
Language实体转为LanguageDTO并完成Base64编码:
import java.util.stream.Collectors; import java.util.Base64; import java.io.InputStream; import java.io.IOException; import javax.sql.rowset.serial.SerialBlob; @GetMapping("/languages") public ResponseEntity<List<LanguageDTO>> getAllLanguages(@RequestParam(required = false) String name) { try { List<Language> languages = new ArrayList<>(); if (name == null) { languageRepository.findAll().forEach(languages::add); } else { languageRepository.findByNameContaining(name).forEach(languages::add); } if (languages.isEmpty()) { return new ResponseEntity<>(HttpStatus.NO_CONTENT); } // 转换为DTO并处理Base64编码 List<LanguageDTO> dtoList = languages.stream() .map(lang -> new LanguageDTO( lang.getId(), lang.getName(), blobToBase64(lang.getAudio()), blobToBase64(lang.getScript()) )) .collect(Collectors.toList()); return new ResponseEntity<>(dtoList, HttpStatus.OK); } catch (Exception e) { return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR); } } // 工具方法:Blob转Base64 private String blobToBase64(Blob blob) { if (blob == null) { return null; } try (InputStream inputStream = blob.getBinaryStream()) { byte[] bytes = inputStream.readAllBytes(); return Base64.getEncoder().encodeToString(bytes); } catch (SQLException | IOException e) { throw new RuntimeException("Failed to convert Blob to Base64", e); } }
方式2:在实体类中添加转换字段(适合简单场景)
如果不想创建DTO,可以在Language实体中添加用于返回的Base64字段,并忽略原始Blob字段的序列化:
import java.util.Base64; import java.io.InputStream; import java.io.IOException; import com.fasterxml.jackson.annotation.JsonIgnore; import javax.persistence.Transient; @Entity @Table(name = "languages") public class Language { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; @Column(name = "name") private String name; @Column(name = "audio") @Lob @JsonIgnore // 忽略该字段的JSON序列化 private Blob audio; @Column(name = "script") @Lob @JsonIgnore // 忽略该字段的JSON序列化 private Blob script; // 不映射到数据库的临时字段,用于返回Base64编码 @Transient private String audioBase64; @Transient private String scriptBase64; // 构造方法、其他字段的getter/setter // 获取Base64字段时自动完成转换 public String getAudioBase64() { if (audio == null) return null; try (InputStream inputStream = audio.getBinaryStream()) { byte[] bytes = inputStream.readAllBytes(); return Base64.getEncoder().encodeToString(bytes); } catch (SQLException | IOException e) { throw new RuntimeException("Failed to convert audio Blob to Base64", e); } } public String getScriptBase64() { if (script == null) return null; try (InputStream inputStream = script.getBinaryStream()) { byte[] bytes = inputStream.readAllBytes(); return Base64.getEncoder().encodeToString(bytes); } catch (SQLException | IOException e) { throw new RuntimeException("Failed to convert script Blob to Base64", e); } } }
此时Controller无需修改,返回的JSON会包含audioBase64和scriptBase64字段,原始Blob字段不会被序列化。
方式3:自定义Jackson序列化器
通过自定义序列化器,让Jackson在序列化实体时自动将Blob转为Base64字符串:
- 创建Blob的自定义序列化器:
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.util.Base64; import java.io.InputStream; import java.io.IOException; public class BlobBase64Serializer extends JsonSerializer<Blob> { @Override public void serialize(Blob blob, JsonGenerator gen, SerializerProvider serializers) throws IOException { if (blob == null) { gen.writeNull(); return; } try (InputStream inputStream = blob.getBinaryStream()) { byte[] bytes = inputStream.readAllBytes(); String base64 = Base64.getEncoder().encodeToString(bytes); gen.writeString(base64); } catch (SQLException e) { throw new IOException("Failed to convert Blob to Base64", e); } } }
- 在实体类的Blob字段上添加序列化注解:
import com.fasterxml.jackson.databind.annotation.JsonSerialize; @Column(name = "audio") @Lob @JsonSerialize(using = BlobBase64Serializer.class) private Blob audio; @Column(name = "script") @Lob @JsonSerialize(using = BlobBase64Serializer.class) private Blob script;
这样Controller返回实体类时,Jackson会自动将Blob序列化为Base64字符串。
内容的提问来源于stack exchange,提问作者software_dev_wannabe
相关产品推荐
相关产品推荐

