SpringMvc作用域相关

87 阅读2分钟

学习参考 :

HttpServletRequest [简称request作用域]

用于组件间跳转时传递数据,比如控制器方法中传递数据给jsp页面

request.setAttribute("name","value");

在jsp中通过EL表达式获取 ${name}

HttpSession [简称session作用域]

用于用户会话追踪,只能存储与用户相关的个人数据, 如:登录状态、令牌、购物车等, (不用于传递数据)

session.setAttribute("name","value");

ServletContext [简称application作用域]

全局唯一,框架底层使用,多用于存储全局唯一的对象
如:Spring的工厂(容器)、Hibernate(JPA)的SessionFactory、MyBatis的SqlSessionFactory等

application.setAttribute("name","value");

上面的几种作用域,在使用中 都是依赖于servlet的api 实现的 setAttribute(),存在耦合性

在SpringMvc中 提供了其他方式去处理

Model 于 ModelMap 方式在作用域中传递对象

在方法形参中声明 Model或者是ModelMap,在方法中就可以使用 (解决的都是request作用域的传值)

@RequestMapping("/view2")
public String view2(Model model) {
    model.addAttribute("name", "xiaojr");
    return "redirect:/result1.jsp";
}
@RequestMapping("/view3")
public String view3(ModelMap modelMap) {
    modelMap.addAttribute("name", "xiaowb");
    return "result1";
}

对应在jsp页面中通过EL表达式获取 ${request.name}

Model和ModelMap 细节分析
  1. 上面的request作用域的处理,使用springMvc提供的方式替换了原有的传值方式

但是在底层,当springMvc发现页面我们使用的是jsp技术,还是会先将model或者modelMap中的数据放到 request中,(虽然底层还是使用request传值,但是这种写法避免了耦合)

当页面不是使用jsp技术的时候,springMvc会自动识别,选取合适的传值方式,但是不影响我们后端中这种写法

  1. model和modelMap的区别

通过代码可以看到两者在底层的时候对应的都是BindingAwareModelMap

  1. 那为什么不直接使用BindingAwareModelMap?

BindingAwareModelMap是springMvc的写法, 如果直接用BindingAwareModelMap去传递参数,相当于和springMvc耦合了,如果想要替换另一种控制器的开发方式 ,这时候没法替换

  1. 更推荐使用Model传值,因为Model是一个接口,在后续种有更好的兼容性
解决session作用域的问题

上面的方式都是解决request作用域的耦合性问题,springMvc也提供了解决session作用域传值的耦合性问题

@SessionAttributes 注解

下面的代码种,依旧是在model种添加了 name属性和值,如果没有@SessionAttributes 注解,那么这种方式传递的值,是在request种,但是加上了@SessionAttributes 注解,并且value种声明了要传递的key,这样就也完成了session作用域的存储数据 (并且可以传递多个值)

@Controller
@RequestMapping("/view3")
@SessionAttributes(value={"name"})
public class View3Controller {

    @RequestMapping("/view1")
    public String view1(Model model) {
        model.addAttribute("name", "xiaojr");
        return "result2";
    }
}

这种方式下,request和session种都有name这个数据,存储的是同一个对象的引用

springMvc没有提供解耦ServletContext作用域的方法

因为上面几种方式,涉及到代码的耦合,都是指程序员开发种写的代码和servlet的api耦合了

但是ServletContext是全局的,多用于底层操作,而不需要程序员操作,所以也就没有提供对应的替换方法