You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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);
        }
    }
}

关键注意事项

  1. 类路径必须包含目标事件类:反序列化时,JVM需要找到序列化时使用的类(包括父类、内部类),比如示例中的com.capone.bank.actors.PersistentBankAccount$BankAccountCreated,如果是Scala的case class,要注意编译后的类名格式(比如伴生对象的类名带$)。
  2. AWS Lambda打包要求:如果在Lambda中运行,需要把包含这些事件类的JAR包一起打包,确保Lambda的运行环境能加载到这些类。
  3. 序列化兼容性:如果事件类有修改,必须保证serialVersionUID和序列化时一致,否则会抛出InvalidClassException。Scala case class默认会自动生成serialVersionUID,但如果手动修改类结构,建议显式指定该值。
  4. 异常处理:实际代码中要添加异常捕获(比如ClassNotFoundException、IOException),避免程序崩溃。

内容的提问来源于stack exchange,提问作者STH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 18:24:43