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

本文详细介绍了SpringMVC中@SessionAttribute和@SessionAttributes两个注解的使用,包括如何存取session数据,以及在重定向场景下的数据处理。@SessionAttribute用于从session中获取值,而@SessionAttributes则在类级别同步Model数据到session,便于跨请求访问。文章通过实例展示了如何存储、清空session数据,并强调了在不同页面调用sessionStatus.setComplete()方法的效果差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考资料

  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才能清除。

在这里插入图片描述

<think>好的,用户想了解Spring MVC中的@SessionAttributeGetSessionAttributeHandler的用法或区别。首先,我需要确认这两个组件的具体作用它们之间的关系。 首先,@SessionAttribute注解。根据用户提供的引用[2],@SessionAttribute用于方法参数,从会话中获取属性。比如在控制器方法中,使用@SessionAttribute("name")可以直接注入会话中的"name"属性到方法参数中。这看起来像是用来方便地访问会话属性的注解,简化代码,避免手动调用HttpSession.getAttribute()。 然后是GetSessionAttributeHandler。根据引用[1],GetSessionAttributeHandler是Spring MVC内部处理@SessionAttribute的组件。它属于HandlerMethodArgumentResolver体系,负责解析带有@SessionAttribute注解的参数。这说明GetSessionAttributeHandler是实现@SessionAttribute功能的后台机制,负责实际从会话中获取属性并注入到控制器方法中。 接下来需要区分两者的角色。@SessionAttribute是开发者在代码中使用注解,属于声明式编程的一部分,告诉框架需要从会话中获取某个属性。而GetSessionAttributeHandler是框架内部的解析器,实际执行获取属性的逻辑。也就是说,注解是接口,处理器是实现。 还要考虑使用场景区别。比如,@SessionAttribute主要用于控制器方法参数,而如果使用GetSessionAttributeHandler,可能需要直接操作参数解析器,但通常开发者不需要直接使用处理器,因为框架会自动处理。此外,错误处理方面,当会话属性不存在时,@SessionAttribute默认会抛出异常,而如果需要更灵活的处理,可能需要自定义解析器或结合其他注解如@RequestAttribute。 可能用户混淆了注解其背后的处理机制,需要明确它们的分工。同时,用户可能关心在实际开发中如何选择,或者遇到相关问题时的解决方法,比如属性不存在的情况。 总结,回答应分为两部分,分别解释@SessionAttributeGetSessionAttributeHandler,然后对比它们的角色区别,最后给出使用建议相关问题。</think>### @SessionAttribute 与 GetSessionAttributeHandler 的区别与用法 #### 1. **@SessionAttribute 的作用** - **声明式访问会话属性** `@SessionAttribute` 是 Spring MVC 提供的注解,用于直接从会话(`HttpSession`)中获取属性值并注入到控制器方法的参数中。例如: ```java @RequestMapping("/show") public String show(@SessionAttribute("name") String userName) { System.out.println("userName=" + userName); return "success"; } ``` 这里的 `userName` 会从会话中查找键为 `"name"` 的属性。如果属性不存在,会抛出 `HttpSessionRequiredException`[^2]。 - **与 `@SessionAttributes` 的关联** `@SessionAttributes` 用于控制器类级别,声明哪些模型属性需要存储到会话中,而 `@SessionAttribute` 则用于方法参数级别的读取[^1]。 #### 2. **GetSessionAttributeHandler 的作用** - **底层解析器实现** `GetSessionAttributeHandler` 是 Spring MVC 内部的一个 `HandlerMethodArgumentResolver`,负责解析带有 `@SessionAttribute` 注解的方法参数。它的核心逻辑包括: 1. 检查参数是否标注了 `@SessionAttribute`。 2. 从 `HttpSession` 中获取对应属性。 3. 处理属性不存在时的异常。 - **与框架的协作** 该解析器由框架自动注册,开发者通常无需直接操作。例如,当控制器方法被调用时,框架会遍历所有参数解析器,最终由 `GetSessionAttributeHandler` 处理符合条件的参数。 #### 3. **关键区别** | **特性** | **@SessionAttribute** | **GetSessionAttributeHandler** | |-------------------------|-------------------------------------------|----------------------------------------------| | **角色** | 开发者使用注解 | 框架内部实现的功能组件 | | **可见性** | 声明式(代码中直接可见) | 隐式(对开发者透明) | | **作用阶段** | 参数注入阶段 | 参数解析阶段 | | **自定义扩展** | 通过注解属性配置 | 需实现自定义 `HandlerMethodArgumentResolver` | #### 4. **使用建议** - **优先使用 `@SessionAttribute`** 在大多数场景中,直接使用注解即可满足需求。例如: ```java public String getUser(@SessionAttribute("user") User user) { // 直接使用会话中的 User 对象 } ``` - **处理属性不存在的情况** 若需避免抛出异常,可结合 `@RequestAttribute` 或通过 `required=false` 配置: ```java @SessionAttribute(name = "tempData", required = false) ``` - **自定义解析器** 若需要更复杂的逻辑(如动态属性名),可自定义 `HandlerMethodArgumentResolver`,但需谨慎覆盖默认行为。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值