项目初始集成redis使用的是默认的lettuce客户端,后来因为业务需要切换成redisson客户端
使用redisson客户端后获取原先存入redis中的值出现了报错:
JsonParseException: Unexpected character (‘a’ (code 97)): Expected space separating root-level value
获取所有数据的时候,无引号字符串无法通过JsonJacksonCodec进行解析导致后续报错,所以可以通过设置Codec的方式来进行处理
RMap<String, Object> map = redissonClient.getMap("key", StringCodec.INSTANCE);
Set<Map.Entry<String, Object>> entries = map.readAllEntrySet();
缺点:
如果原始数据中value存储的是对象,通过设置StringCodec取出的值也会是字符串格式,需要额外进行序列化操作。
默认JacksonCodec编码初始化包含有对象转换设置
protected void init(ObjectMapper objectMapper) {
objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.setVisibility(objectMapper.getSerializationConfig().getDefaultVisibilityChecker().withFieldVisibility(Visibility.ANY).withGetterVisibility(Visibility.NONE).withSetterVisibility(Visibility.NONE).withCreatorVisibility(Visibility.NONE));
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
objectMapper.enable(new JsonGenerator.Feature[]{Feature.WRITE_BIGDECIMAL_AS_PLAIN});
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
objectMapper.enable(new MapperFeature[]{MapperFeature.SORT_PROPERTIES_ALPHABETICALLY});
}
自定义Codec
public class RedissonCodec extends BaseCodec {
protected final ObjectMapper mapObjectMapper;
/**
* @see
*/
private final Encoder encoder = new Encoder() {
@Override
public ByteBuf encode(Object in) throws IOException {
ByteBuf out = ByteBufAllocator.DEFAULT.buffer();
try {
ByteBufOutputStream os = new ByteBufOutputStream(out);
mapObjectMapper.writeValue((OutputStream) os, in);
return os.buffer();
} catch (IOException e) {
out.release();
throw e;
} catch (Exception e) {
out.release();
throw new IOException(e);
}
}
};
private final Decoder<Object> decoder = new Decoder<Object>() {
@Override
public Object decode(ByteBuf buf, State state) throws IOException {
return mapObjectMapper.readValue((InputStream) new ByteBufInputStream(buf), Object.class);
}
};
public RedissonCodec(ObjectMapper mapObjectMapper) {
this(mapObjectMapper, true);
}
public RedissonCodec(ObjectMapper mapObjectMapper, boolean copy) {
if (copy) {
this.mapObjectMapper = mapObjectMapper.copy();
} else {
this.mapObjectMapper = mapObjectMapper;
}
}
@Override
public Decoder<Object> getValueDecoder() {
return decoder;
}
@Override
public Encoder getValueEncoder() {
return encoder;
}
@Override
public ClassLoader getClassLoader() {
if (mapObjectMapper.getTypeFactory().getClassLoader() != null) {
return mapObjectMapper.getTypeFactory().getClassLoader();
}
return super.getClassLoader();
}
}
自定义utils类
public final class RedisUtils {
public static final Codec REDISSON_CODEC;
static {
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
REDISSON_CODEC = new RedissonCodec(om);
}
private RedisUtils() {}
}
访问发现还存在报错
:
ERROR 20964 --- [isson-netty-2-2] o.r.client.handler.CommandDecoder : Unable to decode data. channel: [id: 0x0d57606b, L:/127.0.0.1:49377 - R:127.0.0.1/127.0.0.1:6379], reply: ReplayingDecoderByteBuf(ridx=47, widx=3583080), command: (HGETALL), promise: java.util.concurrent.CompletableFuture@6727c964[Not completed, 1 dependents], params: [SYS:USER]
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('a' (code 97)): Expected space separating root-level values
at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 12]
还是存在拜纳姆解析问题,显示的JsonParseException解析异常,查看redis中数据,分析原因为hashkey为无引号字符串导致,因此需要额外处理一下hashkey键。
RedissonCodec中添加合适编解码对象
private final Decoder<Object> mapKeyDecoder = new Decoder<Object>() {
public Object decode(ByteBuf buf, State state) {
String str = buf.toString(CharsetUtil.UTF_8);
buf.readerIndex(buf.readableBytes());
return str;
}
};
private final Encoder mapKeyEncoder = new Encoder() {
public ByteBuf encode(Object in) throws IOException {
ByteBuf out = ByteBufAllocator.DEFAULT.buffer();
out.writeCharSequence(in.toString(), CharsetUtil.UTF_8);
return out;
}
};
@Override
public Decoder<Object> getMapKeyDecoder() {
return mapKeyDecoder;
}
@Override
public Encoder getMapKeyEncoder() {
return mapKeyEncoder;
}
获取数据代码:
RMap<String, Object> map = redissonClient.getMap("key", RedisUtils.REDISSON_CODEC);
Set<Map.Entry<String, Object>> entries = map.readAllEntrySet();