遇到这样的一个业务场景:前端请求检查会员信息接口,后端用session保存会员信息以便后续业务使用。但输出的信息需要脱敏,在把会员信息对象存入session后,修改对象的属性值为脱敏值输出,但是在后续业务需要用到会员信息时再从session中获取,发现session中的对象的属性也被修改成了脱敏值,这是为什么呢?
大体代码如下:
@Data
public class User {
private Integer id;
private String name;
}
/**
* 得到request对象
*/
public HttpServletRequest getRequest() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
return request;
}
/**
* 保存session
*
* @param key
* @param value
*/
public void setSessionAttr(String key, Object value) {
HttpSession session = getRequest().getSession();
session.setAttribute(key, value);
}
/**
* 获取session值
*
* @param key
* @return
*/
public <T> T getSessionAttr(String key) {
HttpSession session = getRequest().getSession();
return (T) session.getAttribute(key);
}
@RequestMapping("/test4")
public Object test4() throws Exception{
User user = new User();
user.setId(100);
user.setName("王二狗");
setSessionAttr("user",user);
//脱敏
user.setName("王*狗");
return user;
}
@RequestMapping("/test6")
public void test6() throws Exception{
User user = getSessionAttr("user");
System.out.println("user: "+user);
}
测试结果如下:
发现明明没有再保存进入,但从session中获取出来的值却被改变了!
原因分析:
session底层其实是用ConcurrentHashMap保存数据的,下面就以Map集合进行分析
@Test
public void test35() throws Exception{
User user = new User();
user.setName("王二狗").setAge(18);
Map<String,User> map = new HashMap<>();
map.put("user",user);
System.out.println(map.get("user"));
user.setName("王三狗").setAge(20);
System.out.println(map.get("user"));
}
由此可见,在Map集合中保存的对象并不是对象本身,而是对象的引用地址。当对象放入Map集合后修改对象的属性值,然后再次从Map中取值,实际上是根据的引用地址去找此对象。同理,session中保存的数据也是一样。
参考: