shiro整合redis,反序列化必须使用jdk序列化的方式,否则,无法序列化。或者自定义序列化为字节数组。
自定义序列化:
/**
* @author: wangsaichao
* @date: 2018/6/20
* @description: redis的value序列化工具
*/
public class MySerializeUtil implements RedisSerializer {
private static Logger logger = LoggerFactory.getLogger(MySerializeUtil.class);
public static boolean isEmpty(byte[] data) {
return (data == null || data.length == 0);
}
/**
* 序列化为字节数组
* @param object
* @return
* @throws SerializationException
*/
@Override
public byte[] serialize(Object object) throws SerializationException {
byte[] result = null;
if (object == null) {
return new byte[0];
}
try (
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(128);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteStream)
){
if (!(object instanceof Serializable)) {
throw new IllegalArgumentException(MySerializeUtil.class.getSimpleName() + " requires a Serializable payload " +
"but received an object of type [" + object.getClass().getName() + "]");
}
objectOutputStream.writeObject(object);
objectOutputStream.flush();
result = byteStream.toByteArray();
} catch (Exception ex) {
logger.error("Failed to serialize",ex);
}
return result;
}
/**
* 反序列化
* @param bytes
* @return
* @throws SerializationException
*/
@Override
public Object deserialize(byte[] bytes) throws SerializationException {
Object result = null;
if (isEmpty(bytes)) {
return null;
}
try (
ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = new ObjectInputStream(byteStream)
){
result = objectInputStream.readObject();
} catch (Exception e) {
logger.error("Failed to deserialize",e);
}
return result;
}
}
使用jackson自定义序列化,其实还是序列化为字节数组:
/**
* 重写序列化 序列化为json字符串
* zhw
*/
public class JacksonRedisSerializer<T> implements RedisSerializer {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private Class<T> clazz;
public JacksonRedisSerializer(Class<T> clazz) {
super();
this.clazz = clazz;
}
@Override
public byte[] serialize(Object o) throws SerializationException {
if (o == null) {
return new byte[0];
}
try {
return JsonUtil.obj2json(o).getBytes();
} catch (Exception e) {
e.printStackTrace();
}
return new byte[0];
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length <= 0) {
return null;
}
String str = new String(bytes, DEFAULT_CHARSET);
try {
return JsonUtil.json2pojo(str,clazz);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
修改redis的序列化方式,key和value:
@Configuration
public class RedisConfig {
//自定义一个redisTemplate,固定模板,可以直接使用
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory)
throws UnknownHostException {
//为了开发方便,采用<String,Object>
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
//String的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
//hash的key采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
//value序列化方式采用jackson
template.setValueSerializer(new MySerializeUtil());
//hash的value采用...的序列化方式
template.setHashValueSerializer(new MySerializeUtil());
template.afterPropertiesSet();
return template;
}
}
可以将上述序列化方式进行修改。当反序列化时,根据sessionid获取redis的值,其实shiro是将用户信息封装在simpleSession对象中,将整个SimpleSession对象序列化到redis中,取出也是取出值,然后强转为SimpleSession,里面有个attributes属性,attributes是一个Map集合,再根据Map集合获取值,里面又有一个SimplePrincipalCollection对象,用户信息就是存在这个对象中的。