改咱們就改得:取其精華,去其糟粕。不然木有意義
若是說知道@SessionAttributes
這個註解的人已經不多了,那麼不須要統計我就能夠肯定的說:知道@RequestAttribute
註解的更是少之又少。我以爲主要有以下兩個緣由:java
@RequestAttribute
這個註解很新,Spring4.3
後纔有ServletRequest.getAttribute()
)來達到目的,而不用註解。且成本也不過高既然Spring推出了這個註解,那必然有它的優勢。本文就帶你們領略一下它的風騷之處。web
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
spring
它比前面介紹的那些@ModelAttribute
、@SessionAttributes
等註解要簡單不少,它只能使用在方法入參上。做用:從request中取對應的屬性值。架構
不少小夥伴對getParameter()
和getAttribute()
相關方法傻傻分不清楚。建議你能夠先弄清楚param
和attribute
的區別~
// @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裏面取屬性值,至於你何時往裏放值,是有多種方式的能夠達到的:app
@ModelAttribute
註解預存HandlerInterceptor
攔截器中預存下面分別按照這三種使用場景,給出使用Demo
:ide
@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
,結果打印以下:ui
fsx-application fsx-application null Person(name=非功能方法, age=50)
這裏務必注意:@RequestAttribute("myApplicationName")
註解若是省略,是綁定不到attr屬性的哦(必需要有註解)~spa
可是,這樣是可行的:@RequestAttribute String myApplicationName
(若註解沒有指定,Spring MVC
會再去看形參的名字來確認自動綁定)
但若你寫成了這樣@RequestAttribute String aaa
,那請求就直接400錯誤了拋出異常:org.springframework.web.bind.ServletRequestBindingException
HandlerInterceptor
攔截器中預存簡單,直接上代碼:.net
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
很明顯,它也是@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入羣"
字樣,會手動邀請入羣**
若文章格式混亂
或者圖片裂開
,請點擊`: 原文連接-原文連接-原文連接