亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

springmvc對同名參數處理-我們到底能走多遠系列(44)

2019-11-14 15:11:06
字體:
來源:轉載
供稿:網友

sPRingmvc對同名參數處理

扯淡:

中斷發博客幾個月,其實蠻不爽的,可能最近太忙太勞累了些,很多總結也沒時間寫,今天剛好遇到個小問題,就閱讀下源碼找找樂。因為考慮到網上大多是提供解決問題的方案,沒有實際去看spring源碼流程,所以就發個博文記錄下,萬一以后有同學搜到我的文章能深入看些東西吧。

 

問題描述:

前端有多個相同name的input:

<input type="text"  min="1" max="31" name="xName" value="1" /><input type="text"  min="1" max="31" name="xName" value="2" /><input type="text"  min="1" max="31" name="xName" value="3" />
 
提交時流程原理:
一般容器在HTTP協議的Request傳遞到ServletContainer中后,Container就會為該次請求生成一個HTTPServletRequest對象,在HTTPServletRequest對象中,參數和值,放入到了Map中。
tomcat源碼中放入map時的代碼:
   /**     * Put name and value pair in map.  When name already exist, add value     * to array of values.     *     * @param map The map to populate     * @param name The parameter name     * @param value The parameter value     */    private static void putMapEntry( Map map, String name, String value) {        String[] newValues = null;        String[] oldValues = (String[]) map.get(name);        if (oldValues == null) {            newValues = new String[1];            newValues[0] = value;        } else {            newValues = new String[oldValues.length + 1];            System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);            newValues[oldValues.length] = value;        }        map.put(name, newValues);    }

 

可見同名的name,都會被放入數組的value中,而在servlet中,獲取value的兩個方法:

request.getParameter request.getParameterValues

第一個獲取的是數組的第一個值,第二個則獲得整個數組。

springmvc框架在遇到這種同名參數提交,而參數中有逗號時,會出現問題:
比如我提交的值是 xname=123 和 xname=45,67
那么在進入action拿到參數時會變成string[] xname = ["123","45","67"]
就會影響業務邏輯正確執行。
 

解決方案:

就是在提交后臺前,將參數進行轉碼,后臺再進行解碼就可以了。至于采用哪一種轉碼解碼方式,其實沒有什么要求,只需要注意采用方案會將逗號轉碼即可,知道這個關鍵點就好了。
 
實踐方案:
前端代碼:
$("input[name='ssidName']").each(function(){                        $(this).val(encodeURIComponent($(this).val()));                    })

 

后端java代碼:

URLDecoder.decode(ssidNames [i], "UTF-8" )

 

靈活點的想法是:采用可逆轉的轉碼解碼也可,比如base64。有興趣的可以嘗試。
 

源碼閱讀:

 
雖然知道spring有這個自動組裝的功能,那么我就找到這段代碼:

關于springmvc原理分析這文章不錯:http://www.49028c.com/heavenyes/p/3905844.html

 

我就在它后面再更進一步分析同名參數是如何處理的。

完成request中的參數和方法參數上數據的綁定:

private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,            NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {     // 1.獲取方法參數類型的數組        Class[] paramTypes = handlerMethod.getParameterTypes();    // 聲明數組,存參數的值        Object[] args = new Object[paramTypes.length];    //2.遍歷參數數組,獲取每個參數的值        for (int i = 0; i < args.length; i++) {            MethodParameter methodParam = new MethodParameter(handlerMethod, i);            methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);            GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());            String paramName = null;            String headerName = null;            boolean requestBodyFound = false;            String cookieName = null;            String pathVarName = null;            String attrName = null;            boolean required = false;            String defaultValue = null;            boolean validate = false;            int annotationsFound = 0;            Annotation[] paramAnns = methodParam.getParameterAnnotations();       // 處理參數上的注解            for (Annotation paramAnn : paramAnns) {                if (RequestParam.class.isInstance(paramAnn)) {                    RequestParam requestParam = (RequestParam) paramAnn;                    paramName = requestParam.value();                    required = requestParam.required();                    defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());                    annotationsFound++;                }                else if (RequestHeader.class.isInstance(paramAnn)) {                    RequestHeader requestHeader = (RequestHeader) paramAnn;                    headerName = requestHeader.value();                    required = requestHeader.required();                    defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue());                    annotationsFound++;                }                else if (RequestBody.class.isInstance(paramAnn)) {                    requestBodyFound = true;                    annotationsFound++;                }                else if (CookieValue.class.isInstance(paramAnn)) {                    CookieValue cookieValue = (CookieValue) paramAnn;                    cookieName = cookieValue.value();                    required = cookieValue.required();                    defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue());                    annotationsFound++;                }                else if (PathVariable.class.isInstance(paramAnn)) {                    PathVariable pathVar = (PathVariable) paramAnn;                    pathVarName = pathVar.value();                    annotationsFound++;                }                else if (ModelAttribute.class.isInstance(paramAnn)) {                    ModelAttribute attr = (ModelAttribute) paramAnn;                    attrName = attr.value();                    annotationsFound++;                }                else if (Value.class.isInstance(paramAnn)) {                    defaultValue = ((Value) paramAnn).value();                }                else if ("Valid".equals(paramAnn.annotationType().getSimpleName())) {                    validate = true;                }            }             if (annotationsFound > 1) {                throw new IllegalStateException("Handler parameter annotations are exclusive choices - " +                        "do not specify more than one such annotation on the same parameter: " + handlerMethod);            }            if (annotationsFound == 0) {// 如果沒有注解                Object argValue = resolveCommonArgument(methodParam, webRequest);                if (argValue != WebArgumentResolver.UNRESOLVED) {                    args[i] = argValue;                }                else if (defaultValue != null) {                    args[i] = resolveDefaultValue(defaultValue);                }                else {                    Class paramType = methodParam.getParameterType();            // 將方法聲明中的Map和Model參數,放到request中,用于將數據放到request中帶回頁面                    if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) {                        args[i] = implicitModel;                    }                    else if (sessionStatus.class.isAssignableFrom(paramType)) {                        args[i] = this.sessionStatus;                    }                    else if (HttpEntity.class.isAssignableFrom(paramType)) {                        args[i] = resolveHttpEntityRequest(methodParam, webRequest);                    }                    else if (Errors.class.isAssignableFrom(paramType)) {                        throw new IllegalStateException("Errors/BindingResult argument declared " +                                "without preceding model attribute. Check your handler method signature!");                    }                    else if (BeanUtils.isSimpleProperty(paramType)) {                        paramName = "";                    }                    else {                        attrName = "";                    }                }            }       // 從request中取值,并進行賦值操作            if (paramName != null) {         // 根據paramName從request中取值,如果沒有通過RequestParam注解指定paramName,則使用asm讀取class文件來獲取paramName                args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler);            }            else if (headerName != null) {                args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler);            }            else if (requestBodyFound) {                args[i] = resolveRequestBody(methodParam, webRequest, handler);            }            else if (cookieName != null) {                args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler);            }            else if (pathVarName != null) {                args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler);            }            else if (attrName != null) {                WebDataBinder binder =                        resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);                boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));                if (binder.getTarget() != null) {                    doBind(binder, webRequest, validate, !assignBindingResult);                }                args[i] = binder.getTarget();                if (assignBindingResult) {                    args[i + 1] = binder.getBindingResult();                    i++;                }                implicitModel.putAll(binder.getBindingResult().getModel());            }        }     // 返回參數值數組        return args;    }

 

resolveRequestParam方法將參數取出:

 

private Object resolveRequestParam (String paramName, boolean required, String defaultValue,                MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall)                 throws Exception {           Class<?> paramType = methodParam.getParameterType();            if (Map. class.isAssignableFrom(paramType) && paramName.length() == 0) {                 return resolveRequestParamMap((Class<? extends Map>) paramType, webRequest);           }            if (paramName.length() == 0) {                paramName = getRequiredParameterName(methodParam);           }           Object paramValue = null;           MultipartRequest multipartRequest = webRequest.getNativeRequest(MultipartRequest.class );            if (multipartRequest != null) {                List<MultipartFile> files = multipartRequest.getFiles(paramName);                 if (!files.isEmpty()) {                     paramValue = (files.size() == 1 ? files.get(0) : files);                }           }            if (paramValue == null) {               //數組參數執行這行代碼,相當于執行了request.getParameterValues(name)                String[] paramValues = webRequest.getParameterValues(paramName);                 if (paramValues != null) {                    // 取出之后,如果是同名參數則賦值整個數組 paramValue此時是object                     paramValue = (paramValues. length == 1 ? paramValues[0] : paramValues);                }           }            if (paramValue == null) {                 if (defaultValue != null) {                     paramValue = resolveDefaultValue(defaultValue);                }                 else if (required) {                     raiseMissingParameterException(paramName, paramType);                }                paramValue = checkValue(paramName, paramValue, paramType);           }           WebDataBinder binder = createBinder(webRequest, null, paramName);           initBinder(handlerForInitBinderCall, paramName, binder, webRequest);             // 將paramValue根據參數類型進行一次轉換操作            return binder.convertIfNecessary(paramValue, paramType, methodParam);     }

 

最終會執行到TypeConverterDelegate的convertIfNecessary方法:

 

public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,                Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {           Object convertedValue = newValue;            // Custom editor for this type?           PropertyEditor editor = this. propertyEditorRegistry.findCustomEditor(requiredType, propertyName);           ConversionFailedException firstAttemptEx = null;            // No custom editor but custom ConversionService specified?           ConversionService conversionService = this. propertyEditorRegistry.getConversionService();            if (editor == null && conversionService != null && convertedValue != null && typeDescriptor != null) {                TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);                TypeDescriptor targetTypeDesc = typeDescriptor;                 if (conversionService.canConvert(sourceTypeDesc, targetTypeDesc)) {                      try {                            return (T) conversionService.convert(convertedValue, sourceTypeDesc, targetTypeDesc);                     }                      catch (ConversionFailedException ex) {                            // fallback to default conversion logic below                           firstAttemptEx = ex;                     }                }           }            // Value not of required type?            if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {                 if (requiredType != null && Collection.class.isAssignableFrom(requiredType) && convertedValue instanceof String) {                     TypeDescriptor elementType = typeDescriptor.getElementTypeDescriptor();                      if (elementType != null && Enum.class.isAssignableFrom(elementType.getType())) {                           convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);                     }                }                 if (editor == null) {                     editor = findDefaultEditor(requiredType);                }                convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);           }            boolean standardConversion = false;            if (requiredType != null) {                 // Try to apply some standard type conversion rules if appropriate.                 if (convertedValue != null) {                      // 因為我們的type是數組,所以執行這段邏輯,他會執行StringUtils.commaDelimitedListToStringArray                      if (requiredType.isArray()) {                            // Array required -> apply appropriate conversion of elements.                            if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {                                convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);                           }                            return (T) convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());                     }                      else if (convertedValue instanceof Collection) {                            // Convert elements to target type, if determined.                           convertedValue = convertToTypedCollection(                                     (Collection) convertedValue, propertyName, requiredType, typeDescriptor);                           standardConversion = true;                     }                      else if (convertedValue instanceof Map) {                            // Convert keys and values to respective target type, if determined.                           convertedValue = convertToTypedMap(                                     (Map) convertedValue, propertyName, requiredType, typeDescriptor);                           standardConversion = true;                     }                      if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {                           convertedValue = Array.get(convertedValue, 0);                           standardConversion = true;                     }                      if (String. class.equals(requiredType) && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {                            // We can stringify any primitive value...                            return (T) convertedValue.toString();                     }                      else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {                            if (firstAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {                                 try {                                     Constructor strCtor = requiredType.getConstructor(String.class );                                      return (T) BeanUtils.instantiateClass(strCtor, convertedValue);                                }                                 catch (NoSuchMethodException ex) {                                      // proceed with field lookup                                      if (logger.isTraceEnabled()) {                                            logger.trace( "No String constructor found on type [" + requiredType.getName() + "]", ex);                                     }                                }                                 catch (Exception ex) {                                      if (logger.isDebugEnabled()) {                                           logger.debug( "Construction via String failed for type [" + requiredType.getName() + "]" , ex);                                     }                                }                           }                           String trimmedValue = ((String) convertedValue).trim();                            if (requiredType.isEnum() && "".equals(trimmedValue)) {                                 // It's an empty enum identifier: reset the enum value to null.                                 return null;                           }                           convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);                           standardConversion = true;                     }                }                 if (!ClassUtils. isAssignableValue(requiredType, convertedValue)) {                      if (firstAttemptEx != null) {                            throw firstAttemptEx;                     }                      // Definitely doesn't match: throw IllegalArgumentException/IllegalStateException                     StringBuilder msg = new StringBuilder();                     msg.append( "Cannot convert value of type [").append(ClassUtils.getDescriptiveType (newValue));                     msg.append( "] to required type [").append(ClassUtils.getQualifiedName (requiredType)).append("]" );                      if (propertyName != null) {                           msg.append( " for property '").append(propertyName).append("'");                     }                      if (editor != null) {                           msg.append( ": PropertyEditor [").append(editor.getClass().getName()).append(                                      "] returned inappropriate value of type [").append(                                     ClassUtils. getDescriptiveType(convertedValue)).append( "]");                            throw new IllegalArgumentException(msg.toString());                     }                      else {                           msg.append( ": no matching editors or conversion strategy found");                            throw new IllegalStateException(msg.toString());                     }                }           }            if (firstAttemptEx != null) {                 if (editor == null && !standardConversion && requiredType != null && !Object.class.equals(requiredType)) {                      throw firstAttemptEx;                }                 logger.debug( "Original ConversionService attempt failed - ignored since " +                            "PropertyEditor based conversion eventually succeeded", firstAttemptEx);           }            return (T) convertedValue;     }

 

StringUtils.commaDelimitedListToStringArray代碼:

 

public static String[] commaDelimitedListToStringArray (String str) {            return  delimitedListToStringArray(str, ",");     }

 

最終執行代碼,也就是哪里把這個逗號的參數區分成兩個參數的地方,眾里尋他千百度?。?/span>

public static String[] delimitedListToStringArray (String str, String delimiter, String charsToDelete) {            if (str == null) {                 return new String[0];           }            if (delimiter == null) {                 return new String[] {str};           }           List<String> result = new ArrayList<String>();            if ( "".equals(delimiter)) {                 for ( int i = 0; i < str.length(); i++) {                     result.add( deleteAny(str.substring(i, i + 1), charsToDelete));                }           }            else {                 int pos = 0;                 int delPos;                // 逗號分隔,組裝新的list                 while ((delPos = str.indexOf(delimiter, pos)) != -1) {                     result.add( deleteAny(str.substring(pos, delPos), charsToDelete));                     pos = delPos + delimiter.length();                }                 if (str.length() > 0 && pos <= str.length()) {                      // Add rest of String, but not in case of empty input.                     result.add( deleteAny(str.substring(pos), charsToDelete));                }           }            return  toStringArray(result);     }

 

 

讓我們繼續前行

----------------------------------------------------------------------

努力不一定成功,但不努力肯定不會成功。

 

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲乱码av中文一区二区| 欧美成人精品影院| 国产精品69av| 久久久久久久影视| 国产精品高潮视频| 色综合伊人色综合网站| 91视频免费在线| 国产在线播放91| 欧美性猛交xxx| 日本成人激情视频| 国产精品久久久亚洲| 国产精品久久久久999| 日本精品久久久久久久| 亚洲va码欧洲m码| 欧美日韩成人在线播放| 亚洲一区中文字幕| 欧美精品一本久久男人的天堂| 韩日欧美一区二区| 国产在线观看精品| 伦理中文字幕亚洲| 日韩av大片在线| 国产美女久久精品| 国产日韩在线观看av| 91欧美日韩一区| 亚洲肉体裸体xxxx137| 欧美国产日本在线| 久久亚洲精品毛片| 综合136福利视频在线| 国产精品视频在线观看| 一区二区三区四区视频| 国产成人啪精品视频免费网| 亚洲精品国产精品久久清纯直播| 成人亚洲欧美一区二区三区| 亚洲第一页自拍| 精品国产拍在线观看| 欧美午夜精品久久久久久人妖| 欧美国产第一页| 日韩欧美大尺度| 国产视频精品va久久久久久| 亚洲影院污污.| 午夜精品久久久久久久99热| 九九精品视频在线观看| 美乳少妇欧美精品| 精品国内产的精品视频在线观看| 91精品国产91久久久| 尤物yw午夜国产精品视频明星| 91久久中文字幕| 国产精品成人一区二区三区吃奶| 日韩精品视频免费| 国产91精品黑色丝袜高跟鞋| 91精品视频一区| 高清欧美性猛交xxxx| 日韩在线观看网站| 亚洲美女免费精品视频在线观看| 欧美日韩精品在线视频| 久久久久久高潮国产精品视| 成人免费视频网| 成人春色激情网| 久久久久99精品久久久久| 精品国产自在精品国产浪潮| 中文字幕在线看视频国产欧美在线看完整| 久久理论片午夜琪琪电影网| 国产精品伦子伦免费视频| 精品丝袜一区二区三区| 日韩中文字幕免费看| 亚洲欧美在线免费观看| 伊人久久久久久久久久久| 亚洲精品国产品国语在线| 久久久久久久激情视频| 欧美激情在线视频二区| 欧美精品videofree1080p| 在线看片第一页欧美| 亚洲999一在线观看www| 精品国产拍在线观看| 一夜七次郎国产精品亚洲| 欧美丰满少妇xxxx| 久久精品国产精品亚洲| 国产精品美女网站| 久久久久久综合网天天| 在线观看日韩欧美| 亚洲国产美女精品久久久久∴| 久久亚洲精品小早川怜子66| 亚洲精品一区久久久久久| 欧美区在线播放| 国产精品日韩精品| 日韩电视剧免费观看网站| 国产精品观看在线亚洲人成网| 亚州国产精品久久久| 美女精品久久久| 亚洲在线第一页| 精品久久久一区| 国产一区二区三区在线| 欧美三级欧美成人高清www| 国产精品99久久99久久久二8| 中文字幕视频在线免费欧美日韩综合在线看| 国内精品久久久久| 福利一区福利二区微拍刺激| 久久久免费观看视频| 日韩av成人在线| 精品日本美女福利在线观看| 最好看的2019的中文字幕视频| 国产精品av免费在线观看| 97在线视频免费| 亚洲精品国产精品乱码不99按摩| 成人中文字幕在线观看| 91亚洲精品视频| 成人性生交大片免费看小说| 久久久精品国产亚洲| 国产精品久久久久久久app| 欧美在线视频在线播放完整版免费观看| 欧美激情中文字幕在线| 亚洲一区二区三区四区视频| 国产成人精品一区| 亚洲精品国产成人| 中文字幕亚洲天堂| 91性高湖久久久久久久久_久久99| 久久久精品国产亚洲| 国产精品久久久av| 亚洲综合中文字幕在线观看| 国产精品一区二区av影院萌芽| 亚洲国产精品高清久久久| 国产精品一区二区久久久| 亚洲第一免费播放区| 97久久久免费福利网址| 九九热这里只有精品免费看| 国产欧洲精品视频| 成人国内精品久久久久一区| 国产做受高潮69| 国产区亚洲区欧美区| 欧美一区二区.| 91精品国产91久久久久久久久| 精品国产网站地址| 久久久久久久成人| 精品免费在线视频| 欧美片一区二区三区| 欧美性xxxxxx| 国产精品视频最多的网站| 欧美激情精品久久久久久变态| 欧美日韩ab片| 久久久www成人免费精品张筱雨| 成人字幕网zmw| 国产精品人成电影在线观看| 精品国产一区二区三区四区在线观看| 欧美激情按摩在线| 欧美日韩亚洲激情| 亚洲一区制服诱惑| 一道本无吗dⅴd在线播放一区| 欧美性做爰毛片| 欧美多人乱p欧美4p久久| 亚洲色图17p| 国产亚洲精品美女久久久| xvideos亚洲| 57pao成人永久免费视频| 5566成人精品视频免费| 国产成人+综合亚洲+天堂| 国产成人精彩在线视频九色| 国产91精品黑色丝袜高跟鞋| 色久欧美在线视频观看| 91在线中文字幕| 伊人久久久久久久久久| 亚洲黄色www| 热久久这里只有精品| 欧美成人性生活| 97人人模人人爽人人喊中文字|