如何将DynamoDB中Akka Journal事件列的Java对象字符串转为可读格式?
解决Akka Persistence DynamoDB事件序列化内容的反序列化问题
我正在使用Akka Persistence的DynamoDB实现,它不像Cassandra版那样提供Read Journal API。目前已成功将日志数据写入DynamoDB,但事件列存储的是Java对象序列化后的Base64字符串。现在需要基于AWS Lambda或AWS Java API构建CQRS,得把这些事件数据转换成人类可读格式。我尝试用Java ObjectInputStream转换但未成功,求具体转换方法。
示例事件数据
rO0ABXNyAD9jb20uY2Fwb25lLmJhbmsuYWN0b3JzLlBlcnNpc3RlbnRCYW5rQWNjb3VudCRCYW5rQWNjb3VudENyZWF0ZWQrGoMniq0AywIAAUwAC2JhbmtBY2NvdW50dAA6TGNvbS9jYXBvbmUuYmFuay9hY3RvcnMvUGVyc2lzdGVudEJhbmtBY2NvdW50JEJhbmtBY2NvdW50O3hwc3IAOGNvbS5jYXBvbmUuYmFuay5hY3RvcnMuUGVyc2lzdGVudEJhbmtBY2NvdW50JEJhbmtBY2NvdW5011CikshX3ysCAAREAAdiYWxhbmNlTAAIY3VycmVuY3l0ABJMamF2YS9sYW5nL1N0cmluZztMAAJpZHEAfgAETAAEdXNlcnEAfgAEeHBAj0AAAAAAAHQAA0VVUnQAJDM5M2M2NmRiLTJhYmItNDEwNS04NWUyLWMwZjc3MzExMDNlM3QAB3JjYXJkaW4=
我的Scala代码片段
val eventData:String = "rO0ABXNyAD9jb20uY2Fwb25lLmJhbmsuYWN0b3JzLlBlcnNpc3RlbnRCYW5rQWNjb3VudCRCYW5rQWNjb3VudENyZWF0ZWQrGoMniq0AywIAAUwAC2JhbmtBY2NvdW50dAA6TGNvbS9jYXBvbmUuYmFuay9hY3RvcnMvUGVyc2lzdGVudEJhbmtBY2NvdW50JEJhbmtBY2NvdW50O3hwc3IAOGNvbS5jYXBvbmUuYmFuay5hY3RvcnMuUGVyc2lzdGVudEJhbmtBY2NvdW50JEJhbmtBY2NvdW5011CikshX3ysCAAREAAdiYWxhbmNlTAAIY3VycmVuY3l0ABJMamF2YS9sYW5nL1N0cmluZztMAAJpZHEAfgAETAAEdXNlcnEAfgAEeHBAj0AAAAAAAHQAA0VVUnQAJDM5M2M2NmRiLTJhYmItNDEwNS04NWUyLWMwZjc3MzExMDNlM3QAB3JjYXJkaW4=" ??? (后续如何将上述字符串转为可读格式)
解决方案
这段字符串是Java对象序列化后再经过Base64编码的结果,所以需要先解码Base64得到字节数组,再反序列化为原始的事件对象。以下是具体实现:
Scala 实现代码
import java.io.{ByteArrayInputStream, ObjectInputStream} import java.util.Base64 val eventData: String = "rO0ABXNyAD9jb20uY2Fwb25lLmJhbmsuYWN0b3JzLlBlcnNpc3RlbnRCYW5rQWNjb3VudCRCYW5rQWNjb3VudENyZWF0ZWQrGoMniq0AywIAAUwAC2JhbmtBY2NvdW50dAA6TGNvbS9jYXBvbmUuYmFuay9hY3RvcnMvUGVyc2lzdGVudEJhbmtBY2NvdW50JEJhbmtBY2NvdW50O3hwc3IAOGNvbS5jYXBvbmUuYmFuay5hY3RvcnMuUGVyc2lzdGVudEJhbmtBY2NvdW50JEJhbmtBY2NvdW5011CikshX3ysCAAREAAdiYWxhbmNlTAAIY3VycmVuY3l0ABJMamF2YS9sYW5nL1N0cmluZztMAAJpZHEAfgAETAAEdXNlcnEAfgAEeHBAj0AAAAAAAHQAA0VVUnQAJDM5M2M2NmRiLTJhYmItNDEwNS04NWUyLWMwZjc3MzExMDNlM3QAB3JjYXJkaW4=" // 1. 解码Base64字符串为字节数组 val decodedBytes = Base64.getDecoder.decode(eventData) // 2. 通过ObjectInputStream反序列化为目标事件对象 val ois = new ObjectInputStream(new ByteArrayInputStream(decodedBytes)) // 替换为你实际的事件类路径,这里从序列化信息中提取的是BankAccountCreated类 val event = ois.readObject().asInstanceOf[com.capone.bank.actors.PersistentBankAccount$BankAccountCreated] ois.close() // 输出可读格式的事件信息 println(s"账户ID: ${event.id}") println(s"用户ID: ${event.user}") println(s"余额: ${event.balance}") println(s"货币类型: ${event.currency}") println(s"请求ID: ${event.requestId}")
Java 实现代码(适用于AWS Lambda)
import java.io.ByteArrayInputStream; import java.io.ObjectInputStream; import java.util.Base64; public class EventDeserializer { public static void main(String[] args) throws Exception { String eventData = "rO0ABXNyAD9jb20uY2Fwb25lLmJhbmsuYWN0b3JzLlBlcnNpc3RlbnRCYW5rQWNjb3VudCRCYW5rQWNjb3VudENyZWF0ZWQrGoMniq0AywIAAUwAC2JhbmtBY2NvdW50dAA6TGNvbS9jYXBvbmUuYmFuay9hY3RvcnMvUGVyc2lzdGVudEJhbmtBY2NvdW50JEJhbmtBY2NvdW50O3hwc3IAOGNvbS5jYXBvbmUuYmFuay5hY3RvcnMuUGVyc2lzdGVudEJhbmtBY2NvdW50JEJhbmtBY2NvdW5011CikshX3ysCAAREAAdiYWxhbmNlTAAIY3VycmVuY3l0ABJMamF2YS9sYW5nL1N0cmluZztMAAJpZHEAfgAETAAEdXNlcnEAfgAEeHBAj0AAAAAAAHQAA0VVUnQAJDM5M2M2NmRiLTJhYmItNDEwNS04NWUyLWMwZjc3MzExMDNlM3QAB3JjYXJkaW4="; // Base64解码 byte[] decodedBytes = Base64.getDecoder().decode(eventData); // 反序列化并读取事件对象 try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(decodedBytes))) { com.capone.bank.actors.PersistentBankAccount.BankAccountCreated event = (com.capone.bank.actors.PersistentBankAccount.BankAccountCreated) ois.readObject(); // 打印可读信息 System.out.println("账户ID: " + event.id); System.out.println("用户ID: " + event.user); System.out.println("余额: " + event.balance); System.out.println("货币类型: " + event.currency); System.out.println("请求ID: " + event.requestId); } } }
关键注意事项
- 类路径必须包含目标事件类:反序列化时,JVM需要找到序列化时使用的类(包括父类、内部类),比如示例中的
com.capone.bank.actors.PersistentBankAccount$BankAccountCreated,如果是Scala的case class,要注意编译后的类名格式(比如伴生对象的类名带$)。 - AWS Lambda打包要求:如果在Lambda中运行,需要把包含这些事件类的JAR包一起打包,确保Lambda的运行环境能加载到这些类。
- 序列化兼容性:如果事件类有修改,必须保证
serialVersionUID和序列化时一致,否则会抛出InvalidClassException。Scala case class默认会自动生成serialVersionUID,但如果手动修改类结构,建议显式指定该值。 - 异常处理:实际代码中要添加异常捕获(比如
ClassNotFoundException、IOException),避免程序崩溃。
内容的提问来源于stack exchange,提问作者STH
相关产品推荐
相关产品推荐

