Spring中使用LocalDateTime、LocalDate等參數作為入參

Spring中使用LocalDateTime、LocalDate等參數作為入參

背景

項目中使用LocalDateTime系列作為dto中時間的類型,但是spring收到參數後總報錯,為了全局配置時間類型轉換,嘗試瞭如下3中方法。

注:本文基於Springboot2.0測試,如果無法生效可能是spring版本較低導致的。PS:如果你的Controller中的LocalDate類型的參數啥註解(RequestParam、PathVariable等)都沒加,也是會出錯的,因為默認情況下,解析這種參數使用ModelAttributeMethodProcessor進行處理,而這個處理器要通過反射實例化一個對象出來,然後再對對象中的各個參數進行convert,但是LocalDate類沒有構造函數,無法反射實例化因此會報錯!!!

當LocalDateTime作為RequestParam或者PathVariable時

這種情況要和時間作為Json字符串時區別對待,因為前端json轉後端pojo底層使用的是Json序列化Jackson工具(HttpMessgeConverter);而時間字符串作為普通請求參數傳入時,轉換用的是Converter,兩者有區別哦。

在這種情況下,有如下幾種方案:

1. 使用Converter

Spring中使用LocalDateTime、LocalDate等參數作為入參

以上兩個bean會注入到spring mvc的參數解析器(好像叫做ParameterConversionService),當傳入的字符串要轉為LocalDateTime類時,spring會調用該Converter對這個入參進行轉換。

2. 使用ControllerAdvice配合initBinder

Spring中使用LocalDateTime、LocalDate等參數作為入參

從名字就可以看出來,這是在controller做環切(這裡面還可以全局異常捕獲),在參數進入handler之前進行轉換;轉換為我們相應的對象。

當LocalDateTime作為Json形式傳入

這種情況下,如同上文描述,要利用Jackson的json序列化和反序列化來做:

Spring中使用LocalDateTime、LocalDate等參數作為入參

來個完整的配置吧

Spring中使用LocalDateTime、LocalDate等參數作為入參

Spring中使用LocalDateTime、LocalDate等參數作為入參

Spring中使用LocalDateTime、LocalDate等參數作為入參

深入研究SpringMVC數據綁定過程

接下來進入debug模式,看看mvc是如何將我們request中的參數綁定到我們controller層方法入參的:

寫一個簡單controller,下個斷點看看方法調用棧:

Spring中使用LocalDateTime、LocalDate等參數作為入參

斷住以後,我們看下方法調用棧中一些關鍵方法:

Spring中使用LocalDateTime、LocalDate等參數作為入參

根據上述分析,發現invokeForRequest:142, InvocableHandlerMethod這裡的代碼是用來拿到實際參數的:

Spring中使用LocalDateTime、LocalDate等參數作為入參

進入這個方法看看是什麼操作:

Spring中使用LocalDateTime、LocalDate等參數作為入參

進入resolveArgument看看:

Spring中使用LocalDateTime、LocalDate等參數作為入參

這裡根據參數獲取相應的參數解析器,看看內部如何獲取的:

Spring中使用LocalDateTime、LocalDate等參數作為入參

這裡,遍歷參數解析器,查找有沒有適合的解析器!那麼,有哪些參數解析器呢(我測試的時候有26個)???我列出幾個重要的看看,是不是很眼熟!!!

Spring中使用LocalDateTime、LocalDate等參數作為入參

我們進入最常用的一個解析器看看他的supportsParameter方法,發現就是通過參數註解來獲取相應的解析器的。

Spring中使用LocalDateTime、LocalDate等參數作為入參

也就是說,對於@RequestParam和@RequestBody以及@PathVariable註解的參數,SpringMVC會使用不通的參數解析器進行數據綁定!

那麼,這三種解析器分別使用什麼Converter解析參數呢?我們分別進入三種解析器看一看:

首先看下RequestParamMethodArgumentResolver發現內部使用WebDataBinder進行數據綁定,底層使用的是ConversionService (也就是我們的Converter注入的地方)

Spring中使用LocalDateTime、LocalDate等參數作為入參

Spring中使用LocalDateTime、LocalDate等參數作為入參

Spring中使用LocalDateTime、LocalDate等參數作為入參

然後看下RequestResponseBodyMethodProcessor發現使用的轉換器是HttpMessageConverter類型的:

Spring中使用LocalDateTime、LocalDate等參數作為入參

最後看下PathVariableMethodArgumentResolver發現 和RequestParam走的執行路徑一致(二者都是繼承自AbstractNamedValueMethodArgumentResolver解析器),因此代碼就不貼了。

總結

如果要轉換request傳來的參數到我們指定的類型,根據入參註解要進行區分:

  • 如果是RequestBody,那麼通過配置ObjectMapper(這個玩意兒會注入到Jackson的HttpMessagConverter裡面,即MappingJackson2HttpMessageConverter中)來實現Json格式數據的序列化和反序列化;
  • 如果是RequestParam或者PathVariable類型的參數,通過配置Converter實現參數轉換(這些Converter會注入到ConversionService中)。
作者:TinyThing
來源:簡書
商業用途請與原作者聯繫,本文只做展示分享,不妥侵刪!


分享到:


相關文章: