每篇一句

改我们就改得:取其精华,去其糟粕。否则木有意义

前言

如果说知道@SessionAttributes这个注解的人已经很少了,那么不需要统计我就可以确定的说:知道@RequestAttribute注解的更是少之又少。我觉得主要有如下两个原因:

  1. @RequestAttribute这个注解很新,Spring4.3后才有
  2. 我们可以使用API调用的方式(ServletRequest.getAttribute())来达到目的,而不用注解。且成本也不太高

既然Spring推出了这个注解,那必然有它的优点。本文就带大家领略一下它的风骚之处。

Spring提供的这些注解比如@ModelAttribute@SessionAttributes@RequestAttribute都是为了简化开发,提高复用性。同时另外一个目的是希望完全屏蔽掉源生Servlet API,增加它的扩展性。

本文我以@RequestAttribute为例进行讲解,因为@SessionAttribute(也是Spring4.3后推出的注解)不管从使用和原理上都是一模一样的。你可以理解成唯一区别是ServletRequest.getAttribute()HttpSession.getAttribute()的区别

此处再强调一次,这里指的是:org.springframework.web.bind.annotation.SessionAttribute,而非org.springframework.web.bind.annotation.SessionAttributes

@RequestAttribute

它比前面介绍的那些@ModelAttribute@SessionAttributes等注解要简单很多,它只能使用在方法入参上。作用:从request中取对应的属性值

很多小伙伴对getParameter()getAttribute()相关方法傻傻分不清楚。建议你可以先弄清楚paramattribute的区别~

// @since 4.3
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestAttribute {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default ""; // 默认情况下 这个属性是必须的(没有就报错了)
boolean required() default true;
}

接下来这句话很重要@RequestAttribute只负责从request里面取属性值,至于你什么时候往里放值,是有多种方式的可以达到的:

  1. @ModelAttribute注解预存
  2. HandlerInterceptor拦截器中预存
  3. 请求转发带过来

下面分别按照这三种使用场景,给出使用Demo

@ModelAttribute注解预存

比较简单,在@ModelAttribute标注的方法上使用源生的HttpServletRequest放值即可

@RestController
@RequestMapping
public class HelloController { // 放置attr属性值
@ModelAttribute
public Person personModelAttr(HttpServletRequest request) {
request.setAttribute("myApplicationName", "fsx-application");
return new Person("非功能方法", 50);
} @GetMapping("/testRequestAttr")
public void testRequestAttr(@RequestAttribute("myApplicationName") String myApplicationName, HttpServletRequest request, ModelMap modelMap) {
System.out.println(myApplicationName); //fsx-application // 从request里获取
System.out.println(request.getAttribute("myApplicationName")); //fsx-application // 从model里获取
System.out.println(modelMap.get("myApplicationName")); // null 获取不到attr属性的
System.out.println(modelMap.get("person")); // Person(name=非功能方法, age=50)
}
}

请求/testRequestAttr,结果打印如下:

fsx-application
fsx-application
null
Person(name=非功能方法, age=50)

这里务必注意:@RequestAttribute("myApplicationName")注解如果省略,是绑定不到attr属性的哦(必须要有注解)~

但是,这样是可行的:@RequestAttribute String myApplicationName(若注解没有指定,Spring MVC会再去看形参的名字来确认自动绑定)

但若你写成了这样@RequestAttribute String aaa,那请求就直接400错误了抛出异常:org.springframework.web.bind.ServletRequestBindingException

HandlerInterceptor拦截器中预存

简单,直接上代码:

public class SimpleInterceptor implements HandlerInterceptor {

    @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
request.setAttribute("myApplicationName", "fsx-application");
return true;
}
...
}

测试代码:略。

forward请求转发带过来

形如这样:

request.setAttribute("myApplicationName", "fsx-application");
request.getRequestDispatcher("/index").forward(request, response);

其实往里放置属性值只需要遵循一个原则:在调用处理器目标方法之前(参数封装之前)任意地方放置即可,属性值是都能被取到的。


原理剖析

按照我的习惯,即使它很简单,我也会扒开来看看它的原理部分嘛。

根据经验很容易想到解析它的是一个HandlerMethodArgumentResolver,它就是RequestAttributeMethodArgumentResolver

RequestAttributeMethodArgumentResolver

很明显,它也是@since 4.3才出现的,命名上也很配套嘛。

public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {

	// 只处理标注了@RequestAttribute注解的入参
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestAttribute.class);
} // 封装此注解的属性到NamedValueInfo 这里关于参数名的处理有这么一个处理
// info.name.isEmpty()也就说如果自己没有指定,就用形参名parameter.getParameterName()
@Override
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
RequestAttribute ann = parameter.getParameterAnnotation(RequestAttribute.class);
Assert.state(ann != null, "No RequestAttribute annotation");
return new NamedValueInfo(ann.name(), ann.required(), ValueConstants.DEFAULT_NONE);
} // 从request请求域去找属性值
@Override
@Nullable
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request){
return request.getAttribute(name, RequestAttributes.SCOPE_REQUEST);
} // 若值不存在,抛出异常ServletRequestBindingException
@Override
protected void handleMissingValue(String name, MethodParameter parameter) throws ServletException {
throw new ServletRequestBindingException("Missing request attribute '" + name +
"' of type " + parameter.getNestedParameterType().getSimpleName());
} }

源码短小精悍,非常简单。

其实它解析入参方面的核心解析流程在其父类AbstractNamedValueMethodArgumentResolver身上,但并不是本文的重点,请详见HandlerMethodArgumentResolver的章节~

@RequestAttribute属性required默认为true, request.getAttribute获取不到参数就会抛出异常ServletRequestBindingException;required设置为false,即使没有从request中获取到就忽略跳过,赋值为null;

总结

这篇文章介绍了@RequestAttribute的使用Demo,以及它很简单的原理分析。相较于之前所有文章,这篇是非常轻松的,希望可以提供给大家一个思路,来使用@RequestAttribute提高你的逼格,哈哈(友情提示:装逼需谨慎哦~)

说明:因为@SessionAttribute的使用甚至原理几乎一毛一样,所以不用再重复篇幅了

总结

这篇文章介绍了@SessionAttributes的核心处理原理,以及也给了一个Demo来介绍它的基本使用,不出意外阅读下来你对它应该是有很好的收获的,希望能帮助到你简化开发~

相关阅读

从原理层面掌握HandlerMethod、InvocableHandlerMethod、ServletInvocableHandlerMethod的使用【一起学Spring MVC】

从原理层面掌握@SessionAttributes的使用【一起学Spring MVC】

从原理层面掌握@ModelAttribute的使用(核心原理篇)【一起学Spring MVC】

从原理层面掌握@ModelAttribute的使用(使用篇)【一起学Spring MVC】

知识交流

The last:如果觉得本文对你有帮助,不妨点个赞呗。当然分享到你的朋友圈让更多小伙伴看到也是被作者本人许可的~

若对技术内容感兴趣可以加入wx群交流:Java高工、架构师3群

若群二维码失效,请加wx号:fsx641385712(或者扫描下方wx二维码)。并且备注:"java入群" 字样,会手动邀请入群

从原理层面掌握@RequestAttribute、@SessionAttribute的使用【一起学Spring MVC】的更多相关文章

  1. 从原理层面掌握@InitBinder的使用【享学Spring MVC】

    每篇一句 大魔王张怡宁:女儿,这堆金牌你拿去玩吧,但我的银牌不能给你玩.你要想玩银牌就去找你王浩叔叔吧,他那银牌多 前言 为了讲述好Spring MVC最为复杂的数据绑定这块,我前面可谓是做足了功课, ...

  2. 从原理层面掌握@ModelAttribute的使用(使用篇)【一起学Spring MVC】

    每篇一句 每个人都应该想清楚这个问题:你是祖师爷赏饭吃的,还是靠老天爷赏饭吃的 前言 上篇文章 描绘了@ModelAttribute的核心原理,这篇聚焦在场景使用上,演示@ModelAttribute ...

  3. 从原理层面掌握@ModelAttribute的使用(核心原理篇)【一起学Spring MVC】

    每篇一句 我们应该做一个:胸中有蓝图,脚底有计划的人 前言 Spring MVC提供的基于注释的编程模型,极大的简化了web应用的开发,我们都是受益者.比如我们在@RestController标注的C ...

  4. 从原理层面掌握@SessionAttribute的使用【一起学Spring MVC】

    每篇一句 不是你当上了火影大家就认可你,而是大家都认可你才能当上火影 前言 该注解顾名思义,作用是将Model中的属性同步到session会话当中,方便在下一次请求中使用(比如重定向场景~). 虽然说 ...

  5. Spring MVC内容协商实现原理及自定义配置【享学Spring MVC】

    每篇一句 在绝对力量面前,一切技巧都是浮云 前言 上文 介绍了Http内容协商的一些概念,以及Spring MVC内置的4种协商方式使用介绍.本文主要针对Spring MVC内容协商方式:从步骤.原理 ...

  6. RestTemplate的使用和原理你都烂熟于胸了吗?【享学Spring MVC】

    每篇一句 人圆月圆心圆,人和家和国和---中秋节快乐 前言 在阅读本篇之前,建议先阅读开山篇效果更佳.RestTemplate是Spring提供的用于访问Rest服务的客户端工具,它提供了多种便捷访问 ...

  7. 从原理层面掌握HandlerMethod、InvocableHandlerMethod、ServletInvocableHandlerMethod的使用【一起学Spring MVC】

    每篇一句 想当火影的人没有近道可寻,当上火影的人同样无路可退 前言 HandlerMethod它作为Spring MVC的非公开API,可能绝大多数小伙伴都对它比较陌生,但我相信你对它又不是那么的生疏 ...

  8. spring MVC 及 AOP 原理

    SpringMVC工作原理https://www.cnblogs.com/xiaoxi/p/6164383.htmlspring MVC 原理https://blog.csdn.net/y199108 ...

  9. Spring MVC的工作原理,我们来看看其源码实现

    前言 开心一刻 晚上陪老丈人吃饭,突然手机响了,我手贱按了免提……哥们:快出来喝酒!哥几个都在呢!我:今天不行,我现在陪老丈人吃饭呢.哥们:那你抓紧喝,我三杯白酒,把我岳父放倒了才出来的,你也快点.看 ...

随机推荐

  1. Android使用Camera2获取预览数据

    一.Camera2简介 Camera2是Google在Android 5.0后推出的一个全新的相机API,Camera2和Camera没有继承关系,是完全重新设计的,且Camera2支持的功能也更加丰 ...

  2. SQL高度优化

      受同事dd之托,优化一条boss看的报表SQL.dd写复杂疑难SQL无数,如何写出优雅的SQL自有一番心得体会.能将一条7表含inner join,left join并含有关联子查询的.返回结果集 ...

  3. 我在工作中遇到的redis集群使用

    写次随笔,给自己工作学习中记录一个笔记 废话不多说,直接上代码: 功能:将相关信息存到redis中,并设置过期时间,如果redis中有,从redis获取,如果没有,从mysql中获取.redis配置了 ...

  4. 利用LDAP操作AD域

    LDAP操作代码样例  初始化LDAP 目录服务上下文 该例子中,我们使用uid=linly,ou=People,dc=jsoso,dc=net这个账号,链接位于本机8389端口的LDAP服务器(ld ...

  5. c++复杂桶排序Java版

    c++复杂桶排序Java版 题目和我的前几个排序一样 这次是Java版的 代码 + 注释 package com.vdian.qatest.supertagbiz.test.niu; /** * Cr ...

  6. 数字IC前后端设计中的时序收敛(四)--Max Capacitance违反的修复方法

    本文转自:自己的微信公众号<数字集成电路设计及EDA教程> 里面主要讲解数字IC前端.后端.DFT.低功耗设计以及验证等相关知识,并且讲解了其中用到的各种EDA工具的教程. 考虑到微信公众 ...

  7. Disruptor 详解 二

    Disruptor 的大名从很久以前就听说了,但是一直没有时间:看完以后才发现其内部的思想异常清晰,很容易就能前移到其他的项目,所以仔细了解一下还是很有必要的这.篇博客将主要从源码角度分析,Disru ...

  8. 算法学习笔记,几个简单的Demo

    算法初学的一些心得 前言:现在工作也快一年多了,有时间下班回家会学学算法,陆陆续续也接触了一些 貌似我知道的就冒泡排序其他的都不是很了解 最近买了一本书,边学边记录吧! 一些常用的方法 暴力破解 下面 ...

  9. SpringBoot | 第三十八章:基于RabbitMQ实现消息延迟队列方案

    前言 前段时间在编写通用的消息通知服务时,由于需要实现类似通知失败时,需要延后几分钟再次进行发送,进行多次尝试后,进入定时发送机制.此机制,在原先对接银联支付时,银联的异步通知也是类似的,在第一次通知 ...

  10. Linux基础学习整理

    linux学习记录 下载地址 centos 下载地址: 网易镜像:http://mirrors.163.com/centos/6/isos/ 搜狐镜像:http://mirrors.sohu.com/ ...