Jackson 默认启用 ESCAPE_NON_ASCII 特性将中文转为\u4f60\u597d形式,以确保JSON在任意编码环境下安全解析;可通过配置ObjectMapper关闭该特性,同时需避免StringRedisTemplate与RedisTemplate混用及类型丢失问题。

不是 Redis 或 Spring Boot 故意转义,而是 Jackson 默认对非 ASCII 字符做 Unicode 转义(\uXXXX),这是它的默认安全行为。
为什么 Jackson 会把中文变成 \u4f60\u597d 这种形式?
Jackson 的 ObjectMapper 默认启用 JsonGenerator.Feature.ESCAPE_NON_ASCII,目的是保证 JSON 字符串在任意编码环境下都能被安全解析。比如 HTTP header、旧版终端、某些 JS 环境不支持 UTF-8 字节流时,用 \u 形式最稳妥。
这不是 bug,是设计选择;但对调试、日志、Redis CLI 查看确实不友好。
- Redis 里存的确实是合法 JSON,只是“可读性差”
-
redis-cli get mykey显示 \u4f60\u597d,不代表取出来后 Java 对象有问题 - 只要反序列化时用的是同一个
ObjectMapper,还原出来的字符串仍是正确的中文
如何让 Jackson 输出原始中文而不是 \uXXXX?
在配置 RedisTemplate 用的 GenericJackson2JsonRedisSerializer 或 Jackson2JsonRedisSerializer 时,必须显式关闭该特性:
ObjectMapper mapper = new ObjectMapper(); mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, false); // 关键 // 后续再传给 serializer
如果你用的是 Spring Boot 自动配置的 RedisTemplate,需自定义 bean:
- 不要直接改
application.yml里的valueSerializer类名——它不接受参数 - 必须写 Java 配置类,new 出带配置的
ObjectMapper,再套进GenericJackson2JsonRedisSerializer - 注意:
GenericJackson2JsonRedisSerializer构造函数可传ObjectMapper,而Jackson2JsonRedisSerializer<t></t>也可传入已配置好的实例
StringRedisTemplate 和 RedisTemplate 混用导致的“假乱码”
常见错误是:用 StringRedisTemplate 存了 JSON 字符串(比如 stringRedisTemplate.opsForValue().set("k", jsonStr)),却用 RedisTemplate 去取(或反之)。两者底层序列化器完全不同:
-
StringRedisTemplate:key/value 都走StringRedisSerializer(UTF-8 字节直传) -
RedisTemplate(默认):key/value 默认走JdkSerializationRedisSerializer,若你配成 Jackson,则 key 仍可能被序列化为字节流(除非你也配了StringRedisSerializer给 key) - 混用会导致取出来是乱码字节或
ClassCastException,看起来像“转义”,实则是序列化协议错位
真正要警惕的不是转义,而是类型丢失
即使关掉了 ESCAPE_NON_ASCII,如果没配好反序列化类型信息,取出来还是 LinkedHashMap 而不是你的实体类。尤其是用 GenericJackson2JsonRedisSerializer 时:
- 它会在 JSON 里自动加
@class字段,但 Spring Boot 2.6+ 默认禁用DefaultTyping,导致该字段被忽略 - 更稳的方式是用
Jackson2JsonRedisSerializer<yourclass></yourclass>,明确指定类型 - 或者确保
ObjectMapper开启了白名单 + 安全的DefaultTyping(如OBJECT_AND_NON_FINAL),而非NON_FINAL全局开放
转义字符只是表象,类型擦除和序列化器错配才是线上缓存失效、取值失败的真正高发原因。











