SpringBoot @SessionAttribute注解和@SessionAttributes注解的使用

参考资料

  1. 从原理层面掌握@SessionAttributes的使用【享学Spring MVC】
  2. 从原理层面掌握@RequestAttribute、@SessionAttribute的使用【享学Spring MVC】


一. @SessionAttribute注解的使用

  • 用来从session中获取存入的值
  • ❗❗❗注意,@SessionAttribute注解和@SessionAttributes注解是两个不同的注解,作用不同。
@Controller
@RequestMapping("/test20")
public class Test20Controller {

    @Resource
    private HttpSession session;

    @GetMapping("/init")
    public ModelAndView init(HttpSession httpSession, Model model) {

        // 准备好要放入session中的值
        Map<String, String> userInfoMap = new HashMap<String, String>() {
            {
                put("name", "贾飞天");
                put("age", "18");
            }
        };

        // 向注入得到的session中存入用户的相关信息
        session.setAttribute("userInfo1", userInfoMap);
        // 向接口session中存入测试信息
        httpSession.setAttribute("testInfo", "jmw");

        // 指定跳转的页面
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("test20");

        return modelAndView;
    }


    @GetMapping("/getValueFromSession")
    public ResponseEntity<Void> gerValueFromSession(
            // 通过@SessionAttribute注解来获取session中的attribute所对应的值
            @SessionAttribute(value = "userInfo1", required = false) Map<String, String> userInfo1
    ) {
        // 通过@SessionAttribute注解获取到的值
        System.out.println(userInfo1);

        // 通过原生的servlet来获取到的session中attribute所对应的值
        Map userInfo2 = (Map)session.getAttribute("userInfo1");
        System.out.println(userInfo2);

        return ResponseEntity.status(HttpStatus.OK).build();
    }
}

在这里插入图片描述

二. @SessionAttributes注解的使用

  • 作用于类上,一般放在Controller层中
  • 该注解的作用是将Model中的属性同步到session会话当中,
    方便在下一次请求中使用(例如重定向场景)。
  • Controller层在向其模型ModelModelAndView中添加数据时,若该数据匹配@SessionAttributes注解指定的名称或者类型时,就会放入session中。
  • 在@SessionAttributes所在的Controller中调用SessionStatus.setComplete()方法可清除匹配到session中的数据
  • ❗❗❗注意,能从session清空的只是和@SessionAttributes注解匹配的数据,通过session原生的api放入的数据是不会被清除的。
  • 只能在本页面调用SessionStatus.setComplete()方法清空,若重定向到其他画面,然后在重定向的画面调用SessionStatus.setComplete()方法是不会清空的。此时只能调用原生session的api清空数据。

2.1 @SessionAttributes存入值,清空值示例

⏹Controller层

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

@Controller
@RequestMapping("/test20")
// 若向Model或ModelAndView中存入value中的值的话,会匹配到session中
@SessionAttributes(value = {"userInfoMap1", "userInfoMap2", "userInfoMap3"})
public class Test20Controller {
	
	// 注入得到的session对象
    @Resource
    private HttpSession session;

    @GetMapping("/init")
    public ModelAndView init(HttpSession httpSession, Model model) {
		// 省略......
    }
	
	@GetMapping("/redirectMethod")
    public String redirectMethod(Model model) {
    	// 省略......
    }

    @GetMapping("/clearSessionAttributes")
    @ResponseBody
    public void clearSessionAttributes(SessionStatus sessionStatus) {
		// 省略......
    }
}

2.1.1 ⏹Controller层-init方法

  • 向Model或ModelAndView中存入的数据,如果名称同@SessionAttributes的value值相匹配,会顺带存入session中。
@GetMapping("/init")
public ModelAndView init(HttpSession httpSession, Model model) {

    Map<String, String> userInfoMap = new HashMap<String, String>() {
        {
            put("name", "贾飞天");
            put("age", "18");
        }
    };

    // 向session中存入用户的相关信息,直接通过session的API放入
    session.setAttribute("userInfo1", userInfoMap);
    httpSession.setAttribute("testInfo", "jmw");
	
	// 向Model中放入数据,因为名称和@SessionAttributes中的value值匹配,所以会顺带放入session中
    HashMap<String, String> userInfoMap1 = new HashMap<String, String>() {
        {
            put("id", "110120");
            put("name", "枫叶红");
        }
    };
    model.addAttribute("userInfoMap1", userInfoMap1);

    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("test20");
    // 向ModelAndView中放入数据,因为名称和@SessionAttributes中的value值匹配,所以会顺带放入session中
    modelAndView.addObject("userInfoMap3", userInfoMap1);

    return modelAndView;
}

2.1.2 ⏹Controller层-clearSessionAttributes方法

@GetMapping("/clearSessionAttributes")
@ResponseBody
public void clearSessionAttributes(SessionStatus sessionStatus) {

    System.out.println(session.getAttribute("userInfo1"));
    System.out.println(session.getAttribute("testInfo"));
    System.out.println(session.getAttribute("userInfoMap1"));
    System.out.println(session.getAttribute("userInfoMap2"));
    System.out.println(session.getAttribute("userInfoMap3"));
	
	// 清空@SessionAttributes注解valu值所对应的session中的值
    sessionStatus.setComplete();
    System.out.println("------分割线------");

    /*
    * 执行完 sessionStatus.setComplete()方法 之后,还是可以获取到
    * 但是再一次执行clearSessionAttributes方法的时候,就获取不到了。
    * 因为已经被清空
    * */
    System.out.println(session.getAttribute("userInfo1"));
    System.out.println(session.getAttribute("testInfo"));
    System.out.println(session.getAttribute("userInfoMap1"));
    System.out.println(session.getAttribute("userInfoMap2"));
    System.out.println(session.getAttribute("userInfoMap3"));
}

👉第一次执行,可以看到sessionStatus.setComplete()方法执行完毕之后,依旧能从session中获取到@SessionAttribute注解存入的session值。

在这里插入图片描述

👉第二次执行(此时sessionStatus.setComplete()方法已经在第一次被执行过一遍),可以看到
原生Session的API存入的值依然可以获取出来,但是通过@SessionAttributes注解放入session中的值已经被清空了。

在这里插入图片描述

2.2 重定向到其他页面示例

@GetMapping("/redirectMethod")
public String redirectMethod(Model model) {
	
	/*
		👉👉👉在重定向到其他页面之前,向Model中存入值
		因为userInfoMap2这个属性与@SessionAttributes的value值匹配
		因此会放到session中
	*/ 
    HashMap<String, String> userInfoMap2 = new HashMap<String, String>() {
        {
            put("id", "119120");
            put("name", "张三");
        }
    };
    model.addAttribute("userInfoMap2", userInfoMap2);
	
	// 重定向到其他页面
    return "redirect:/test21/init";
}

2.2.1 ⏹重定向到的页面-Controller层

import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.Map;

@Controller
@RequestMapping("/test21")
public class Test21Controller {

    @Resource
    private HttpSession session;

    @GetMapping("/init")
    public ModelAndView redirectMethod(
            // 通过@SessionAttribute注解来获取session中的attribute所对应的值
            @SessionAttribute(value = "userInfo1", required = false) Map<String, String> userInfo1FromSession,
            @SessionAttribute(value = "userInfoMap1", required = false) Map<String, String> userInfoMap1FromSessionAttributes,
            @SessionAttribute(value = "userInfoMap2", required = false) Map<String, String> userInfoMap2FromSessionAttributes,
            HttpSession httpSession
    ) {

        // 直接通过session对象来获取数据
        System.out.println(session.getAttribute("userInfo1"));
        System.out.println(httpSession.getAttribute("userInfo1"));
        Object testInfo = httpSession.getAttribute("testInfo");
        System.out.println(testInfo);

        System.out.println(userInfo1FromSession);
        System.out.println(userInfoMap1FromSessionAttributes);
        System.out.println(userInfoMap2FromSessionAttributes);

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("test21");
        return modelAndView;
    }

    @GetMapping("/sessionStatus")
    public ResponseEntity<Void> sessionStatus(HttpSession httpSession, SessionStatus sessionStatus) {
    	// 省略......
    }
}

2.2.2 ⏹重定向到的页面-前台HTML

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <button id="sessionStatus">调用sessionStatus.setComplete()方法</button>
</div>
<script th:src="@{/js/public/jquery-3.6.0.min.js}"></script>
<script th:inline="javascript">
    // 获取session中存入的值
    const {
        userInfo1,
        userInfoMap1,
        userInfoMap2
    } = [[${session}]];

    console.log(userInfo1);
    console.log(userInfoMap1);
    console.log(userInfoMap2);

    $("#sessionStatus").click(async function () {
        await fetch("/test21/sessionStatus");
    });
</script>
</body>
</html>

2.2.3 ⏹效果

在这里插入图片描述

2.3 在重定向到的页面调用sessionStatus.setComplete()方法

  • @SessionAttributes注解作用在的页面上调用sessionStatus.setComplete()方法才能清空对应的session中的值
@GetMapping("/sessionStatus")
public ResponseEntity<Void> sessionStatus(HttpSession httpSession, SessionStatus sessionStatus) {

    System.out.println(httpSession.getAttribute("userInfo1"));
    System.out.println(httpSession.getAttribute("testInfo"));

    System.out.println(httpSession.getAttribute("userInfoMap1"));
    System.out.println(httpSession.getAttribute("userInfoMap2"));
    System.out.println(httpSession.getAttribute("userInfoMap3"));

    /*
        尝试清空通过@SessionAttributes注解放入session中的值
        但是因为@SessionAttributes不是在本页面放入的,因此清空失败
        只有在原页面调用sessionStatus.setComplete()方法,session中对应的值才会被清空
     */
    sessionStatus.setComplete();

    // 手动清除session中的userInfoMap3对应的值,这种方式可以清空
    httpSession.removeAttribute("userInfoMap3");

    System.out.println(httpSession.getAttribute("userInfo1"));
    System.out.println(httpSession.getAttribute("testInfo"));
    System.out.println(session.getAttribute("userInfoMap1"));
    System.out.println(httpSession.getAttribute("userInfoMap2"));
    System.out.println(httpSession.getAttribute("userInfoMap3"));

    return ResponseEntity.noContent().build();
}

⏹ 尝试在在重定向到的页面调用sessionStatus.setComplete()方法清空对应的session中的值
👉第一次

在这里插入图片描述
👉第二次
可以看到根本就无法清除,只有手动调用session的API才能清除。

在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值