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

Java向Redis Stream发送实体自动转Base64问题及解决咨询

Redis Stream发送对象出现Base64编码的问题排查与修复

问题描述

使用Java 11向Redis 7.0.8的Stream发送NicknameEdit对象,代码实现如下:

package com.dolphin.soa.post.common.mq;

import com.dolphin.soa.post.model.custom.NicknameEdit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.stream.ObjectRecord;
import org.springframework.data.redis.connection.stream.RecordId;
import org.springframework.data.redis.connection.stream.StreamRecords;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

@Component
@Slf4j
@RequiredArgsConstructor
public class StreamMessageProducer {

    private final RedisTemplate<String, NicknameEdit> redisTemplate;

    public void sendRecord(String streamKey, String nickname) {
        NicknameEdit nicknameEdit = new NicknameEdit();
        nicknameEdit.setNickname(nickname);
        ObjectRecord<String, NicknameEdit> record = StreamRecords.newRecord()
                .in(streamKey)
                .ofObject(nicknameEdit)
                .withId(RecordId.autoGenerate());
        RecordId recordId = redisTemplate.opsForStream()
                .add(record);
    }
}

实体类定义:

package com.dolphin.soa.post.model.custom;

import lombok.Data;
import java.io.Serializable;

@Data
public class NicknameEdit implements Serializable {
    private Long userId;
    private String nickname;
}

但Redis中存储的数据是Base64编码格式:

{
    "\"X2NsYXNz\"": "\"Y29tLmRvbHBoaW4uc29hLnBvc3QubW9kZWwuY3VzdG9tLlN5c0V2ZW50\"",
    "\"ZGF0YS5fY2xhc3M=\"": "\"Y29tLmRvbHBoaW4uc29hLnBvc3QubW9kZWwuY3VzdG9tLk5pY2tuYW1lRWRpdA==\"",
}

原因分析

出现Base64编码的核心原因是Spring Data Redis默认使用JdkSerializationRedisSerializer序列化对象:

  • 该序列化器基于JDK自带机制,会将Java对象转为字节数组
  • Redis Stream存储字节数组时,会自动将其编码为Base64字符串
  • 同时会额外添加类元数据字段(如_class),这些字段也会被Base64编码,导致存储内容完全不可读

修复方案

核心解决思路是替换序列化器为JSON序列化,以下两种方案均可实现:

方案一:全局配置RedisTemplate使用JSON序列化器

创建Redis配置类,覆盖默认序列化逻辑,使用Jackson2JsonRedisSerializer处理对象序列化:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        // 配置JSON序列化器
        Jackson2JsonRedisSerializer<Object> jsonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        // 可按需配置ObjectMapper,比如忽略空值、指定日期格式等
        // ObjectMapper objectMapper = new ObjectMapper();
        // objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        // jsonSerializer.setObjectMapper(objectMapper);

        // Key和HashKey使用字符串序列化
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        // Value和HashValue使用JSON序列化
        template.setValueSerializer(jsonSerializer);
        template.setHashValueSerializer(jsonSerializer);

        template.afterPropertiesSet();
        return template;
    }
}

修改Producer中的RedisTemplate类型为RedisTemplate<String, Object>或RedisTemplate<String, NicknameEdit>,重新注入即可生效。

方案二:手动将对象序列化为JSON字符串发送

如果不需要全局修改RedisTemplate,可在Producer中手动将对象转为JSON字符串,使用RedisTemplate<String, String>发送:

package com.dolphin.soa.post.common.mq;

import com.dolphin.soa.post.model.custom.NicknameEdit;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.stream.MapRecord;
import org.springframework.data.redis.connection.stream.RecordId;
import org.springframework.data.redis.connection.stream.StreamRecords;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Component
@Slf4j
@RequiredArgsConstructor
public class StreamMessageProducer {

    private final RedisTemplate<String, String> redisTemplate;
    private final ObjectMapper objectMapper;

    public void sendRecord(String streamKey, String nickname) {
        NicknameEdit nicknameEdit = new NicknameEdit();
        nicknameEdit.setNickname(nickname);
        
        try {
            // 将对象转为JSON字符串
            String jsonStr = objectMapper.writeValueAsString(nicknameEdit);
            // 构造MapRecord发送
            Map<String, String> data = new HashMap<>();
            data.put("nicknameEdit", jsonStr);
            MapRecord<String, String, String> record = StreamRecords.newRecord()
                    .in(streamKey)
                    .ofMap(data)
                    .withId(RecordId.autoGenerate());
            RecordId recordId = redisTemplate.opsForStream().add(record);
        } catch (Exception e) {
            log.error("序列化对象失败", e);
        }
    }
}

这种方式下,Redis中会直接存储明文JSON字符串,无Base64编码。

是否可以关闭Base64编码直接发送明文JSON?

完全可以。通过上述两种方案将序列化方式从JDK序列化替换为JSON序列化后,Redis Stream中存储的就是可读的明文JSON内容,不会再出现Base64编码的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 10:57:53