springMvc參數綁定之list


public Map<String, Object> method(@NotNull List<String> list){ 
  //your code
}

在開發中, 遇到某些場景需要傳入一個集合參數, 當我理所應當的寫出上述代碼, 並且進行調試的時候, 卻出現了和意料中不一樣的結果:

HTTP Status 500 - Request processing failed; 
nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [java.util.List]: Specified class is an interface

  

 原來如此, 原來List是一個接口, 那么我換成實現就應該好了, 於是將代碼修改為:

public Map<String, Object> method(@NotNull ArrayList<String> list){ 
  //your code
}

  

當我使用swagger接口文檔進行調試, 輸入以下參數

這下應該好了吧, 但是實際上和我想的還是不一樣, 接口調用不報錯了, 但是:

接口中的參數是一個空集合, 經過胡亂探索發現, 在參數上做一點小改動就可以達到正確傳入:

public Map<String, Object> method(@NotNull @RequestParam List<String> list){ 
  //your code 
}

  

效果圖:

但是為什么?, 通過跟蹤源碼發現, 存在一個參數解析的過程, 不同的注解使用不同的解析器來解析, 其中這篇文章對我的啟發很大, 推薦大家看看

https://www.2cto.com/kf/201405/301660.html

經過追蹤分析源碼, 比對存在@RequestParam和不存在的情況, 發現參數解析是一種嘗試行為, 如果能解析出來, 那么正確賦值. 下面特出關鍵源碼, 源碼類為:

org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver

代碼如下:

@Override
	public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

		Class<?> paramType = parameter.getParameterType();
		NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);

          //從request中獲取參數 Object arg = resolveName(namedValueInfo.name, parameter, webRequest); if (arg == null) { if (namedValueInfo.defaultValue != null) { arg = resolveDefaultValue(namedValueInfo.defaultValue); } else if (namedValueInfo.required && !parameter.getParameterType().getName().equals("java.util.Optional")) { handleMissingValue(namedValueInfo.name, parameter); } arg = handleNullValue(namedValueInfo.name, arg, paramType); } else if ("".equals(arg) && namedValueInfo.defaultValue != null) { arg = resolveDefaultValue(namedValueInfo.defaultValue); }
         //如果綁定處理工廠不是空, 嘗試進行參數解析, 這里將會正確的將list參數解析為list, 本例中如果不加Requestparam那么是不會進入的. if (binderFactory != null) { WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name); try { arg = binder.convertIfNecessary(arg, paramType, parameter); } catch (ConversionNotSupportedException ex) { throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(), namedValueInfo.name, parameter, ex.getCause()); } catch (TypeMismatchException ex) { throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(), namedValueInfo.name, parameter, ex.getCause()); } } handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest); return arg; }

  

至此, 知其所以然. mark一下

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM