alibaba.fastjson内部已经提供了对Redis存储对象序列化的工具类GenericFastJsonRedisSerializer,但是该工具在反序列化时返回为Object,我们仿照GenericFastJsonRedisSerializer来自定义一个扩展的工具类,反序列化后自动转化为指定的java对象。

  • GenericFastJsonRedisSerializer 源码
package com.alibaba.fastjson.support.spring;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.util.IOUtils;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

/**
 * {@link RedisSerializer} FastJson Generic Impl
 * @author lihengming
 * @since 1.2.36
 */
public class GenericFastJsonRedisSerializer implements RedisSerializer<Object> {
    private final static ParserConfig defaultRedisConfig = new ParserConfig();
    static { defaultRedisConfig.setAutoTypeSupport(true);}

    public byte[] serialize(Object object) throws SerializationException {
        if (object == null) {
            return new byte[0];
        }
        try {
            return JSON.toJSONBytes(object, SerializerFeature.WriteClassName);
        } catch (Exception ex) {
            throw new SerializationException("Could not serialize: " + ex.getMessage(), ex);
        }
    }

    public Object deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        try {
            return JSON.parseObject(new String(bytes, IOUtils.UTF8), Object.class, defaultRedisConfig);
        } catch (Exception ex) {
            throw new SerializationException("Could not deserialize: " + ex.getMessage(), ex);
        }
    }
}

  • 自定义FastJsonRedisSerializer
import java.nio.charset.Charset;

import com.alibaba.fastjson.parser.ParserConfig;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;

/**
 * <Description> fastjson序列化<br>
 *
 * @author xubin<br>
 * @version 1.0<br>
 * @taskId <br>
 * @param <T> 泛化
 * @CreateDate Nov 8, 2018 <br>
 */

public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {

    private final static ParserConfig defaultRedisConfig = new ParserConfig();
    static { defaultRedisConfig.setAutoTypeSupport(true);}

    /**
     * DEFAULT_CHARSET <br>
     */
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    /**
     * clazz 反序列化类<br>
     */
    private Class<T> clazz;

    /**
     * <Description> 构造器<br>
     *
     * @param clazz 反序列化目标类
     */
    public FastJsonRedisSerializer(Class<T> clazz) {
        super();
        this.clazz = clazz;
    }

    /**
     * Description: 序列化<br>
     *
     * @author xubin<br>
     * @taskId <br>
     * @param t
     * @return
     * @throws SerializationException <br>
     */
    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (t == null) {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }


    /**
     * Description: 反序列化<br>
     *
     * @author xubin<br>
     * @taskId <br>
     * @param bytes
     * @return
     * @throws SerializationException <br>
     */
    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);
        return (T) JSON.parseObject(str, clazz, defaultRedisConfig);
    }

}

  • json报文示例
{
    "@type": "com.lucas.device.mqtt.protocol.MqttPacketCache",
    "id": 647682641483370500,
    "packet": {
        "@type": "com.lucas.device.mqtt.protocol.Packet",
        "body": {
            "@type": "com.lucas.device.mqtt.protocol.payload.BindFacesetBody",
            "facesetTokenList": [
                "630281772974575616"
            ]
        },
        "head": {
            "code": 114,
            "id": 647682641483370500,
            "type": 2,
            "version": 1
        }
    }
}

此处要注意的是defaultRedisConfig.setAutoTypeSupport(true)这段,在调用JSON.toJSONString(object, SerializerFeature.WriteClassName)时会在json报文中包含@type信息,反序列化时会根据 @type 对要映射的对象进行检查,所以请确保要反序列化的类型有默认构造器同时序列化工具打开了autoType的支持,否则反序列化会出现异常com.alibaba.fastjson.JSONException: autoType is not support。

  • RedisConfig 配置自定义的序列化工具类
   /**
     * Description: <br>
     *
     * @author xubin<br>
     * @taskId <br>
     * @param factory 工厂对象
     * @return <br>
     */
    @Bean
    public RedisTemplate<String, MqttPacketCache> packetRedisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, MqttPacketCache> redisTemplate = new RedisTemplate<>();
        StringRedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setConnectionFactory(factory);
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(new FastJsonRedisSerializer<>(MqttPacketCache.class));
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(new FastJsonRedisSerializer<>(MqttPacketCache.class));
        return redisTemplate;
    }

05-22 16:46