1. 程式人生 > >springboot使用FastJson替換Redis的預設序列方式實現物件的序列化,及autoType is not support的解決辦法

springboot使用FastJson替換Redis的預設序列方式實現物件的序列化,及autoType is not support的解決辦法

自定義Redis的序列化方式需要實現 RedisSerializer<T> 這個介面

public interface RedisSerializer<T> {

	@Nullable
	byte[] serialize(@Nullable T t) throws SerializationException;

	@Nullable
	T deserialize(@Nullable byte[] bytes) throws SerializationException;
}

FastJson序列化器實現:

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

    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    private Class<T> clazz;

    public FastJson2JsonRedisSerializer(Class<T> clazz) {
        super();
        this.clazz = clazz;
    }

    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (t == null) {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }

    @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);
    }
}

設定RedisTemplate及序列化方式

@Bean
public RedisSerializer<Object> fastJson2JsonRedisSerializer() {
    return new FastJson2JsonRedisSerializer<Object>(Object.class);
}

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisCF) {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
    redisTemplate.setConnectionFactory(redisCF);
    redisTemplate.setKeySerializer(new StringRedisSerializer());
    redisTemplate.setValueSerializer(fastJson2JsonRedisSerializer());
    redisTemplate.afterPropertiesSet();
    return redisTemplate;
}

注意事項:

2017年3月15日,fastjson官方釋出安全升級公告,該公告介紹fastjson在1.2.24及之前的版本存在程式碼執行漏洞,當惡意攻擊者提交一個精心構造的序列化資料到服務端時,由於fastjson在反序列化時存在漏洞,可導致遠端任意程式碼執行。自1.2.25及之後的版本,禁用了部分autotype的功能,也就是@type這種指定型別的功能會被限制在一定範圍內使用。而由於反序列化物件時,需要檢查是否開啟了autotype。所以如果反序列化檢查時,autotype沒有開啟,就會報錯。所以採用上述序列化方式時需要在專案配置fastjson時配置autotype相關內容本文選擇在程式碼中配置其他方式請參考:

enable_autotype

@Bean
public HttpMessageConverters fastJsonHttpMessageConverters() {
    FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
    FastJsonConfig fastJsonConfig = new FastJsonConfig();
    fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
    fastConverter.setFastJsonConfig(fastJsonConfig);
    //必須加否則會報com.alibaba.fastjson.JSONException: autoType is not sup這個錯        
    ParserConfig.getGlobalInstance().addAccept("需要序列化物件的包");
    HttpMessageConverter<?> converter = fastConverter;
    return new HttpMessageConverters(converter);
}

到此完成配置,專案中應用如下:

@Autowired
private RedisTemplate<String, Object> redisTemplate;
	
@RequestMapping(value = "set")
public void set() {
    UserInfo user = new UserInfo(1, "張三", "18758974838", new Date());
    redisTemplate.opsForValue().set("user", user);
    System.out.println(redisTemplate.opsForValue().get("user"));
}