Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 国产亚洲日本,国产一区二区,午夜激情免费视频

          整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          使用swagger 2.9.2版本,注解@ApiPa

          使用swagger 2.9.2版本,注解@ApiParam出現(xiàn)的問題

          前后端分離的項目中,為了便捷開發(fā),很多項目中會用到swagger這個工具,其中使用@ApiParam在項目啟動后訪問swagger頁面的時候出現(xiàn)了這樣一個問題。

          接口層代碼:

          @Api(description="運動等級體系接口")
          @Slf4j
          @RestController
          @RequestMapping("/SportSystem")
          public class SportSystemController {
          
              @Autowired
              private SportSystemService sportSystemService;
          
              @RequestMapping(value="/list", method=RequestMethod.GET)
              @ApiOperation(value="獲取所有sportSystem",notes="獲取所有sportSystem,無需參數(shù)", httpMethod="GET")
              public RetVO findAll(){
                  List<SportSystem> systemList=sportSystemService.findAll();
                  return new RetVO(RetCode.SUCCESS.getCode(),RetCode.MSG.getMsg(),systemList);
              }
          
              @RequestMapping(value="/get/{id}", method=RequestMethod.GET)
              @ApiOperation(value="獲取單個sportSystem",notes="獲取單個sportSystem,需參數(shù)", httpMethod="GET")
              public RetVO get(@ApiParam(name="id",value="id主鍵",required=true) @PathVariable ("id") Integer id) {
                  SportSystem system=sportSystemService.findById(id);
                  return new RetVO(RetCode.SUCCESS.getCode(),RetCode.MSG.getMsg(),system);
              }
          
              @RequestMapping(value="/insert", method=RequestMethod.POST)
              @ApiOperation(value="插入sportSystem",notes="插入sportSystem,需參數(shù)", httpMethod="POST")
              public RetVO insert(@ApiParam(name="sportSystem",value="運動等級體系實體",required=true) @RequestBody SportSystem sportSystem) {
                   sportSystemService.insert(sportSystem);
                  return new RetVO(RetCode.SUCCESS.getCode(),RetCode.MSG.getMsg());
              }
          
              @RequestMapping(value="/update", method=RequestMethod.PUT)
              @ApiOperation(value="修改sportSystem",notes="修改sportSystem,需參數(shù)", httpMethod="PUT")
              public RetVO update(@ApiParam(name="sportSystem",value="運動等級體系實體",required=true) @RequestBody SportSystem sportSystem) {
                      sportSystemService.update(sportSystem);
                      return new RetVO(RetCode.SUCCESS.getCode(),RetCode.MSG.getMsg());
              }
          
              @RequestMapping(value="/delete/{id}", method=RequestMethod.DELETE)
              @ApiOperation(value="刪除單個sportSystem",notes="刪除單個sportSystem,需參數(shù)", httpMethod="DELETE")
              public RetVO delete(@ApiParam(name="id",value="id主鍵",required=true) @PathVariable ("id") Integer id) {
                   sportSystemService.deleteById(id);
                   return new RetVO(RetCode.SUCCESS.getCode(),RetCode.MSG.getMsg());
              }
          
          }

          在訪問swagger網(wǎng)址時:http://localhost:8001/swagger-ui.html#/
          出現(xiàn)了一個異常:

          java.lang.NumberFormatException: For input string: ""
          	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
          	at java.lang.Long.parseLong(Long.java:601)
          	at java.lang.Long.valueOf(Long.java:803)
          	at io.swagger.models.parameters.AbstractSerializableParameter.getExample(AbstractSerializableParameter.java:412)
          	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
          	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          	at java.lang.reflect.Method.invoke(Method.java:498)
          	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:633)
          	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:678)
          	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
          	at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:119)
          	at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:79)
          	at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:18)
          	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:672)
          	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:678)
          	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
          	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:672)
          	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:678)
          	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
          	at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields(MapSerializer.java:616)
          	at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:519)
          	at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:31)
          	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:672)
          	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:678)
          	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
          	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:130)
          	at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3613)
          	at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:2980)
          	at springfox.documentation.spring.web.json.JsonSerializer.toJson(JsonSerializer.java:38)
          	at springfox.documentation.swagger2.web.Swagger2Controller.getDocumentation(Swagger2Controller.java:105)
          	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
          	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          	at java.lang.reflect.Method.invoke(Method.java:498)
          	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
          	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
          	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
          	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)
          	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
          	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
          	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
          	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
          	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
          	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
          	at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
          	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)

          經(jīng)過分析是swagger中類型轉(zhuǎn)換的問題,在@ApiParam注解中需要@PathVariable (“id”) Integer id映射的代碼中加入屬性

          example="1"對應(yīng)上即可。

          @Api(description="運動等級體系接口")
          @Slf4j
          @RestController
          @RequestMapping("/SportSystem")
          public class SportSystemController {
          
              @Autowired
              private SportSystemService sportSystemService;
          
              @RequestMapping(value="/list", method=RequestMethod.GET)
              @ApiOperation(value="獲取所有sportSystem",notes="獲取所有sportSystem,無需參數(shù)", httpMethod="GET")
              public RetVO findAll(){
                  List<SportSystem> systemList=sportSystemService.findAll();
                  return new RetVO(RetCode.SUCCESS.getCode(),RetCode.MSG.getMsg(),systemList);
              }
          
              @RequestMapping(value="/get/{id}", method=RequestMethod.GET)
              @ApiOperation(value="獲取單個sportSystem",notes="獲取單個sportSystem,需參數(shù)", httpMethod="GET")
              public RetVO get(@ApiParam(name="id",value="id主鍵",required=true,example="1") @PathVariable ("id") Integer id) {
                  SportSystem system=sportSystemService.findById(id);
                  return new RetVO(RetCode.SUCCESS.getCode(),RetCode.MSG.getMsg(),system);
              }
          
              @RequestMapping(value="/insert", method=RequestMethod.POST)
              @ApiOperation(value="插入sportSystem",notes="插入sportSystem,需參數(shù)", httpMethod="POST")
              public RetVO insert(@ApiParam(name="sportSystem",value="運動等級體系實體",required=true) @RequestBody SportSystem sportSystem) {
                   sportSystemService.insert(sportSystem);
                  return new RetVO(RetCode.SUCCESS.getCode(),RetCode.MSG.getMsg());
              }
          
              @RequestMapping(value="/update", method=RequestMethod.PUT)
              @ApiOperation(value="修改sportSystem",notes="修改sportSystem,需參數(shù)", httpMethod="PUT")
              public RetVO update(@ApiParam(name="sportSystem",value="運動等級體系實體",required=true) @RequestBody SportSystem sportSystem) {
                      sportSystemService.update(sportSystem);
                      return new RetVO(RetCode.SUCCESS.getCode(),RetCode.MSG.getMsg());
              }
          
              @RequestMapping(value="/delete/{id}", method=RequestMethod.DELETE)
              @ApiOperation(value="刪除單個sportSystem",notes="刪除單個sportSystem,需參數(shù)", httpMethod="DELETE")
              public RetVO delete(@ApiParam(name="id",value="id主鍵",required=true,example="1") @PathVariable ("id") Integer id) {
                   sportSystemService.deleteById(id);
                   return new RetVO(RetCode.SUCCESS.getCode(),RetCode.MSG.getMsg());
              }
          
          }

          再次啟動沒有異常拋出!

          HTML中,標(biāo)簽可以包含各種屬性,用于定義標(biāo)簽的特性和行為。例如,img標(biāo)簽可以有src屬性來指定要顯示的圖像的URL,a標(biāo)簽可以有href屬性來指定鏈接的目標(biāo)地址。通過獲取標(biāo)簽的屬性值,我們可以獲取到這些額外的信息,然后根據(jù)需要進行處理。

          定義方法

          /**
           * 提取富文本字符串某個標(biāo)簽的所有屬性
           * @param {String} str 要提取的html富文本
           * @param {Object} tagName 要提取的標(biāo)簽名稱
           * @param {Object} attrName 要提取的屬性名稱
           * @returns {Array} list 屬性列表
           */
          function getStrTagAttribute(str,tagName,attrName){
          	let attributeList=[]
          	const re=new RegExp(`<${tagName} [^>]*${attrName}=['"]([^'"]+)[^>]*>`,'g')
          	str.replace(re, (match, capture)=> {
          	  attributeList.push(capture);
          	});
          	return attributeList;
          }

          使用方法

          質(zhì)文章,及時送達(dá)

          前言

          SpringMVC是目前主流的Web MVC框架之一。SpringMVC中Controller的方法參數(shù)可以是Integer,Double,自定義對象,ServletRequest,ServletResponse,ModelAndView等等,非常靈活。本文將分析SpringMVC是如何對這些參數(shù)進行處理的,使讀者能夠處理自定義的一些參數(shù)。

          現(xiàn)象

          本文使用的demo基于maven。我們先來看一看對應(yīng)的現(xiàn)象。

          @Controller
          @RequestMapping(value="/test")
          public class TestController {
          @RequestMapping("/testRb")
          @ResponseBody
          public Employee testRb(@RequestBody Employee e) {
          return e;
          }
          @RequestMapping("/testCustomObj")
          @ResponseBody
          public Employee testCustomObj(Employee e) {
          return e;
          }
          @RequestMapping("/testCustomObjWithRp")
          @ResponseBody
          public Employee testCustomObjWithRp(@RequestParam Employee e) {
          return e;
          }
          @RequestMapping("/testDate")
          @ResponseBody
          public Date testDate(Date date) {
          return date;
          }
          }

          首先這是一個Controller,有4個方法。他們對應(yīng)的參數(shù)分別是帶有@RequestBody的自定義對象、自定義對象、帶有@RequestParam的自定義對象、日期對象。接下來我們一個一個方法進行訪問看對應(yīng)的現(xiàn)象是如何的。

          首先第一個testRb:

          第二個testCustomObj:

          第三個testCustomObjWithRp:

          第四個testDate:

          為何返回的Employee對象會被自動解析為xml,為何Employee參數(shù)會被解析,帶有@RequestParam的Employee參數(shù)不會被解析,甚至報錯?

          為何日期類型不能被解析?

          SpringMVC到底是如何處理這些方法的參數(shù)的?

          @RequestBody、@RequestParam這兩個注解有什么區(qū)別?

          帶著這幾個問題。我們開始進行分析。

          源碼分析

          本文所分析的源碼是Spring版本4.0.2

          在分析源碼之前,首先讓我們來看下SpringMVC中兩個重要的接口。

          兩個接口分別對應(yīng)請求方法參數(shù)的處理、響應(yīng)返回值的處理,分別是HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler,這兩個接口都是Spring3.1版本之后加入的。

          SpringMVC處理請求大致是這樣的:

          首先被DispatcherServlet截獲,DispatcherServlet通過handlerMapping獲得HandlerExecutionChain,然后獲得HandlerAdapter。

          HandlerAdapter在內(nèi)部對于每個請求,都會實例化一個ServletInvocableHandlerMethod進行處理,ServletInvocableHandlerMethod在進行處理的時候,會分兩部分別對請求跟響應(yīng)進行處理。

          之后HandlerAdapter得到ModelAndView,然后做相應(yīng)的處理。

          本文將重點介紹ServletInvocableHandlerMethod對請求以及響應(yīng)的處理。

          1. 處理請求的時候,會根據(jù)ServletInvocableHandlerMethod的屬性argumentResolvers(這個屬性是它的父類InvocableHandlerMethod中定義的)進行處理,其中argumentResolvers屬性是一個HandlerMethodArgumentResolverComposite類(這里使用了組合模式的一種變形),這個類是實現(xiàn)了HandlerMethodArgumentResolver接口的類,里面有各種實現(xiàn)了HandlerMethodArgumentResolver的List集合。

          2. 處理響應(yīng)的時候,會根據(jù)ServletInvocableHandlerMethod的屬性returnValueHandlers(自身屬性)進行處理,returnValueHandlers屬性是一個HandlerMethodReturnValueHandlerComposite類(這里使用了組合模式的一種變形),這個類是實現(xiàn)了HandlerMethodReturnValueHandler接口的類,里面有各種實現(xiàn)了HandlerMethodReturnValueHandler的List集合。

          ServletInvocableHandlerMethod的returnValueHandlers和argumentResolvers這兩個屬性都是在ServletInvocableHandlerMethod進行實例化的時候被賦值的(使用RequestMappingHandlerAdapter的屬性進行賦值)。

          RequestMappingHandlerAdapter的argumentResolvers和returnValueHandlers這兩個屬性是在RequestMappingHandlerAdapter進行實例化的時候被Spring容器注入的。

          其中默認(rèn)的ArgumentResolvers:

          默認(rèn)的returnValueHandlers:

          使用@ResponseBody注解的話最終返回值會被RequestResponseBodyMethodProcessor這個HandlerMethodReturnValueHandler實現(xiàn)類處理。

          我們通過源碼發(fā)現(xiàn),RequestResponseBodyMethodProcessor這個類其實同時實現(xiàn)了HandlerMethodReturnValueHandler和HandlerMethodArgumentResolver這兩個接口。

          RequestResponseBodyMethodProcessor支持的請求類型是Controller方法參數(shù)中帶有@RequestBody注解,支持的響應(yīng)類型是Controller方法帶有@ResponseBody注解。

          RequestResponseBodyMethodProcessor響應(yīng)的具體處理是使用消息轉(zhuǎn)換器。

          處理請求的時候使用內(nèi)部的readWithMessageConverters方法。

          然后會執(zhí)行父類(AbstractMessageConverterMethodArgumentResolver)的readWithMessageConverters方法。

          下面來我們來看看常用的HandlerMethodArgumentResolver實現(xiàn)類(本文粗略講下,有興趣的讀者可自行研究)。

          1. RequestParamMethodArgumentResolver

          支持帶有@RequestParam注解的參數(shù)或帶有MultipartFile類型的參數(shù)

          2. RequestParamMapMethodArgumentResolver

          支持帶有@RequestParam注解的參數(shù) && @RequestParam注解的屬性value存在 && 參數(shù)類型是實現(xiàn)Map接口的屬性

          3. PathVariableMethodArgumentResolver

          支持帶有@PathVariable注解的參數(shù) 且如果參數(shù)實現(xiàn)了Map接口,@PathVariable注解需帶有value屬性

          4. MatrixVariableMethodArgumentResolver

          支持帶有@MatrixVariable注解的參數(shù) 且如果參數(shù)實現(xiàn)了Map接口,@MatrixVariable注解需帶有value屬性

          5. RequestResponseBodyMethodProcessor

          本文已分析過

          6. ServletRequestMethodArgumentResolver

          參數(shù)類型是實現(xiàn)或繼承或是WebRequest、ServletRequest、MultipartRequest、HttpSession、Principal、Locale、TimeZone、InputStream、Reader、HttpMethod這些類。

          (這就是為何我們在Controller中的方法里添加一個HttpServletRequest參數(shù),Spring會為我們自動獲得HttpServletRequest對象的原因)

          7. ServletResponseMethodArgumentResolver

          參數(shù)類型是實現(xiàn)或繼承或是ServletResponse、OutputStream、Writer這些類

          8. RedirectAttributesMethodArgumentResolver

          參數(shù)是實現(xiàn)了RedirectAttributes接口的類

          9. HttpEntityMethodProcessor

          參數(shù)類型是HttpEntity

          從名字我們也看的出來, 以Resolver結(jié)尾的是實現(xiàn)了HandlerMethodArgumentResolver接口的類,以Processor結(jié)尾的是實現(xiàn)了HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler的類。

          下面來我們來看看常用的HandlerMethodReturnValueHandler實現(xiàn)類。

          1. ModelAndViewMethodReturnValueHandler

          返回值類型是ModelAndView或其子類

          2. ModelMethodProcessor

          返回值類型是Model或其子類

          3. ViewMethodReturnValueHandler

          返回值類型是View或其子類

          4. HttpHeadersReturnValueHandler

          返回值類型是HttpHeaders或其子類

          5. ModelAttributeMethodProcessor

          返回值有@ModelAttribute注解

          6. ViewNameMethodReturnValueHandler

          返回值是void或String

          其余沒講過的讀者可自行查看源碼。

          下面開始解釋為何本文開頭出現(xiàn)那些現(xiàn)象的原因:

          1. 第一個方法testRb以及地址 http://localhost:8888/SpringMVCDemo/test/testRb?name=1&age=3

          這個方法的參數(shù)使用了@RequestBody,之前已經(jīng)分析過,被RequestResponseBodyMethodProcessor進行處理。之后根據(jù)http請求頭部的contentType然后選擇合適的消息轉(zhuǎn)換器進行讀取。

          很明顯,我們的消息轉(zhuǎn)換器只有默認(rèn)的那些跟部分json以及xml轉(zhuǎn)換器,且傳遞的參數(shù)name=1&age=3,傳遞的頭部中沒有content-type,默認(rèn)使用了application/octet-stream,因此觸發(fā)了HttpMediaTypeNotSupportedException異常

          解放方案:我們將傳遞數(shù)據(jù)改成json,同時http請求的Content-Type改成application/json即可。

          完美解決。

          2. testCustomObj方法以及地址

          http://localhost:8888/SpringMVCDemo/test/testCustomObj?name=1&age=3

          這個請求會找到ServletModelAttributeMethodProcessor這個resolver。默認(rèn)的resolver中有兩個ServletModelAttributeMethodProcessor,只不過實例化的時候?qū)傩詀nnotationNotRequired一個為true,1個為false。這個ServletModelAttributeMethodProcessor處理參數(shù)支持@ModelAttribute注解,annotationNotRequired屬性為true的話,參數(shù)不是簡單類型就通過,因此選擇了ServletModelAttributeMethodProcessor,最終通過DataBinder實例化Employee對象,并寫入對應(yīng)的屬性。

          3. testCustomObjWithRp方法以及地址

          http://localhost:8888/SpringMVCDemo/test/testCustomObjWithRp?name=1&age=3

          這個請求會找到RequestParamMethodArgumentResolver(使用了@RequestParam注解)。RequestParamMethodArgumentResolver在處理參數(shù)的時候使用request.getParameter(參數(shù)名)即request.getParameter("e")得到,很明顯我們的參數(shù)傳的是name=1&age=3。因此得到,RequestParamMethodArgumentResolver處理missing value會觸發(fā)MissingServletRequestParameterException異常。[粗略講下,有興趣的讀者請自行查看源碼]

          解決方案:去掉@RequestParam注解,讓ServletModelAttributeMethodProcessor來處理。

          4. testDate方法以及地址 http://localhost:8888/SpringMVCDemo/test/testDate?date=2014-05-15

          這個請求會找到RequestParamMethodArgumentResolver。因為這個方法與第二個方法一樣,有兩個RequestParamMethodArgumentResolver,屬性useDefaultResolution不同。RequestParamMethodArgumentResolver支持簡單類型,ServletModelAttributeMethodProcessor是支持非簡單類型。最終步驟跟第三個方法一樣,我們的參數(shù)名是date,于是通過request.getParameter("date")找到date字符串(這里參數(shù)名如果不是date,那么最終頁面是空白的,因為沒有@RequestParam注解,參數(shù)不是必須的,RequestParamMethodArgumentResolver處理值返回)。最后通過DataBinder找到合適的屬性編輯器進行類型轉(zhuǎn)換。最終找到j(luò)ava.util.Date對象的構(gòu)造函數(shù) public Date(String s),由于我們傳遞的格式不是標(biāo)準(zhǔn)的UTC時間格式,因此最終觸發(fā)了IllegalArgumentException異常。

          解決方案:

          1. 傳遞參數(shù)的格式修改成標(biāo)準(zhǔn)的UTC時間格式:http://localhost:8888/SpringMVCDemo/test/testDate?date=Sat, 17 May 2014 16:30:00 GMT

          2.在Controller中加入自定義屬性編輯器。

          @InitBinder
          public void initBinder(WebDataBinder binder) {
          SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");
          binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
          }

          這個@InitBinder注解在實例化ServletInvocableHandlerMethod的時候被注入到WebDataBinderFactory中的,而WebDataBinderFactory是ServletInvocableHandlerMethod的一個屬性。在RequestMappingHandlerAdapter源碼的803行g(shù)etDataBinderFactory就是得到的WebDataBinderFactory

          之后RequestParamMethodArgumentResolver通過WebDataBinderFactory創(chuàng)建的WebDataBinder里的自定義屬性編輯器找到合適的屬性編輯器(我們自定義的屬性編輯器是用CustomDateEditor處理Date對象,而testDate的參數(shù)剛好是Date),最終CustomDateEditor把這個String對象轉(zhuǎn)換成Date對象。

          # 編寫自定義的HandlerMethodArgumentResolver

          通過前面的分析,我們明白了SpringMVC處理Controller中的方法的參數(shù)流程。現(xiàn)在,如果方法中有兩個參數(shù),且都是自定義類參數(shù),那該如何處理呢?很明顯,要處理這個只能自己實現(xiàn)一個實現(xiàn)HandlerMethodArgumentResolver的類。

          先定義1個注解FormObj:

          @Target({ElementType.PARAMETER})
          @Retention(RetentionPolicy.RUNTIME)
          public @interface FormObj {
          //參數(shù)別名
          String value default "";
          //是否展示, 默認(rèn)展示
          boolean show default true;
          }

          然后是HandlerMethodArgumentResolver:

          public class FormObjArgumentResolver implements HandlerMethodArgumentResolver {

          @Override
          public boolean supportsParameter(MethodParameter parameter) {
          return parameter.hasParameterAnnotation(FormObj.class);
          }

          @Override
          public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
          FormObj formObj=parameter.getParameterAnnotation(FormObj.class);

          String alias=getAlias(formObj, parameter);

          //拿到obj, 先從ModelAndViewContainer中拿,若沒有則new1個參數(shù)類型的實例
          Object obj=(mavContainer.containsAttribute(alias)) ?
          mavContainer.getModel.get(alias) : createAttribute(alias, parameter, binderFactory, webRequest);


          //獲得WebDataBinder,這里的具體WebDataBinder是ExtendedServletRequestDataBinder
          WebDataBinder binder=binderFactory.createBinder(webRequest, obj, alias);

          Object target=binder.getTarget;

          if(target !=) {
          //綁定參數(shù)
          bindParameters(webRequest, binder, alias);
          //JSR303 驗證
          validateIfApplicable(binder, parameter);
          if (binder.getBindingResult.hasErrors) {
          if (isBindExceptionRequired(binder, parameter)) {
          throw new BindException(binder.getBindingResult);
          }
          }
          }

          if(formObj.show) {
          mavContainer.addAttribute(alias, target);
          }

          return target;
          }


          private Object createAttribute(String alias, MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest webRequest) {
          return BeanUtils.instantiateClass(parameter.getParameterType);
          }

          private void bindParameters(NativeWebRequest request, WebDataBinder binder, String alias) {
          ServletRequest servletRequest=request.getNativeRequest(ServletRequest.class);

          MockHttpServletRequest newRequest=new MockHttpServletRequest;

          Enumeration<String> enu=servletRequest.getParameterNames;
          while(enu.hasMoreElements) {
          String paramName=enu.nextElement;
          if(paramName.startsWith(alias)) {
          newRequest.setParameter(paramName.substring(alias.length+1), request.getParameter(paramName));
          }
          }
          ((ExtendedServletRequestDataBinder)binder).bind(newRequest);
          }

          protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
          Annotation annotations=parameter.getParameterAnnotations;
          for (Annotation annot : annotations) {
          if (annot.annotationType.getSimpleName.startsWith("Valid")) {
          Object hints=AnnotationUtils.getValue(annot);
          binder.validate(hints instanceof Object ? (Object[]) hints : new Object {hints});
          break;
          }
          }
          }

          protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter parameter) {
          int i=parameter.getParameterIndex;
          Class<?> paramTypes=parameter.getMethod.getParameterTypes;
          boolean hasBindingResult=(paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));

          return !hasBindingResult;
          }

          private String getAlias(FormObj formObj, MethodParameter parameter) {
          //得到FormObj的屬性value,也就是對象參數(shù)的簡稱
          String alias=formObj.value;
          if(alias==|| StringUtils.isBlank(alias)) {
          //如果簡稱為空,取對象簡稱的首字母小寫開頭
          String simpleName=parameter.getParameterType.getSimpleName;
          alias=simpleName.substring(0, 1).toLowerCase + simpleName.substring(1);
          }
          return alias;
          }


          }

          對應(yīng)Controller:

          @Controller
          @RequestMapping(value="/foc")
          public class FormObjController {

          @RequestMapping("/test1")
          public String test1(@FormObj Dept dept, @FormObj Employee emp) {
          return "index";
          }

          @RequestMapping("/test2")
          public String test2(@FormObj("d") Dept dept, @FormObj("e") Employee emp) {
          return "index";
          }

          @RequestMapping("/test3")
          public String test3(@FormObj(value="d", show=false) Dept dept, @FormObj("e") Employee emp) {
          return "index";
          }

          }

          結(jié)果如下:

          # 總結(jié)

          寫了這么多,主要還是鞏固一下自己對SpringMVC對請求及響應(yīng)的處理做一個細(xì)節(jié)的總結(jié)吧,不知道大家有沒有清楚這個過程。

          想熟悉這部分內(nèi)容最主要的還是要熟悉HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler這兩個接口以及屬性編輯器、數(shù)據(jù)綁定機制。

          本文難免有錯誤,希望讀者能指出來。

          參考資料

          • http://www.iteye.com/topic/1127676

          • http://jinnianshilongnian.iteye.com/blog/1717180

          作者:format

          https://www.cnblogs.com/fangjian0423/p/springMVC-request-param-analysis.html

          -END-

          如果看到這里,說明你喜歡這篇文章,請轉(zhuǎn)發(fā)。同時標(biāo)星(置頂)本公眾號可以第一時間接受到博文推送。1. 使用IntelliJ IDEA看源碼?Spring為啥默認(rèn)把bean設(shè)計成單例的?3.簡潔RESTful API設(shè)計規(guī)范!!兩小時入門 Docker(好文推薦)


          主站蜘蛛池模板: 麻豆文化传媒精品一区二区| 国产99久久精品一区二区| 国产伦精品一区二区三区视频小说| 中文字幕av一区| 视频一区二区三区在线观看| 国产美女av在线一区| 99久久精品日本一区二区免费| 久久久久人妻精品一区三寸| 精品人体无码一区二区三区| 精品中文字幕一区二区三区四区| 濑亚美莉在线视频一区| 久久久91精品国产一区二区三区| 亚洲国产AV无码一区二区三区 | 波多野结衣一区视频在线| 日本高清一区二区三区| 国产乱码伦精品一区二区三区麻豆| 无码国产精品一区二区免费3p| 在线电影一区二区| 久久国产免费一区二区三区 | 一区二区高清在线观看| 怡红院一区二区在线观看| 中文字幕一区二区免费| 色国产在线视频一区| 人妻体内射精一区二区三四| 一区二区视频在线| 国产在线观看一区二区三区精品| 一区二区三区电影网| 97久久精品无码一区二区天美| 日日摸夜夜添一区| 濑亚美莉在线视频一区| 99久久精品日本一区二区免费 | 91福利一区二区| 日本一区频道在线视频| 久久精品免费一区二区三区| 免费在线观看一区| 日韩精品一区二区三区中文版| 国产一区二区精品久久岳√| 一区二区三区在线免费观看视频| 91国在线啪精品一区| 天堂资源中文最新版在线一区| 国产91久久精品一区二区|