springmvc的数据绑定

springmvc为我们提供了强大的数据绑定功能,但是一直都是只见其行形,不见其意,现在通过阅读源码来深入理解一下具体是怎么实现数据绑定的。

以如下方法为例:两个参数,一个是ModelMap,一个是标记为PathVariable的Integer类型

	@RequestMapping(value="/goEdit/{id}")
	public String goEdit(ModelMap model,@PathVariable Integer id){
		SysActivity sysActivity = sysActivityService.getById(id);	//根据ID读取
		model.addAttribute("act", sysActivity);
		return display("edit");
	}

数据绑定的入口顺序是DispatcherServlet类->doService->doDispatch->HandlerAdapter.handle()->RequestMappingHandlerAdapter类的handle方法(此处由父类AbstractHandlerMethodAdapter执行),然后调用handleInternal()->invokeHandleMethod()->invokeAndHandle()->invokeForRequest(),此时开始正式处理方法的参数。

public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
        //开始处理变量
		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			StringBuilder sb = new StringBuilder("Invoking [");
			sb.append(getBeanType().getSimpleName()).append(".");
			sb.append(getMethod().getName()).append("] method with arguments ");
			sb.append(Arrays.asList(args));
			logger.trace(sb.toString());
		}
        //方法调用,如getEdit方法开始执行
		Object returnValue = invoke(args);
		if (logger.isTraceEnabled()) {
			logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
		}
		return returnValue;
	}
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
        //获取方法所有的参数信息
		MethodParameter[] parameters = getMethodParameters();
        //根据参数个数创建对应个数的数组,用来存储request中参数的值
		Object[] args = new Object[parameters.length];
		for (int i = 0; i < parameters.length; i++) {
			MethodParameter parameter = parameters[i];
			parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
            
			GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());
			args[i] = resolveProvidedArgument(parameter, providedArgs);
			if (args[i] != null) {
				continue;
			}
			if (this.argumentResolvers.supportsParameter(parameter)) {
				try {
					args[i] = this.argumentResolvers.resolveArgument(
							parameter, mavContainer, request, this.dataBinderFactory);
					continue;
				}
				catch (Exception ex) {
					if (logger.isTraceEnabled()) {
						logger.trace(getArgumentResolutionErrorMessage("Error resolving argument", i), ex);
					}
					throw ex;
				}
			}
			if (args[i] == null) {
				String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
				throw new IllegalStateException(msg);
			}
		}
		return args;
	}
	public Object resolveArgument(
			MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
			throws Exception {
        //获取对应的argumentReslover
		HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
		Assert.notNull(resolver, "Unknown parameter type [" + parameter.getParameterType().getName() + "]");
        //根据获取的resolver类型找到对应的执行方法,如下图:
		return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
	}

145600_6r8j_2527296.png

因为第一个参数是ModalMap,所以返回的resolver是MapMethodProcessor

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

		return mavContainer.getModel();
	}

	public ModelMap getModel() {
       //判断是不是重定向的参数
		if (useDefaultModel()) {
			return this.defaultModel;
		}
		else {
			return (this.redirectModel != null) ? this.redirectModel : new ModelMap();
		}
	}

//BindingAwareModelMap是ModelMap的子类,modelMap是model的实现,所以用model,map,modelMap都可以保模型变量
private final ModelMap defaultModel = new BindingAwareModelMap();

通过上边代码逻辑,最终

同样,第二个参数是Integer,被,@PathVariable标记了,所以返回的参数resolver是PathVariableMethodArgumentResolver

151719_XKdh_2527296.png

protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
//获取uriTemplateVariables中的变量,返回
		Map<String, String> uriTemplateVars =
			(Map<String, String>) request.getAttribute(
					HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
//根据参数名,拿到对应的值
		return (uriTemplateVars != null) ? uriTemplateVars.get(name) : null;
	}

下边这几个类都是调用父类的resolveArgument方法,然后调用子类的resolveName方法

154859_vzYD_2527296.png

 

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

		Class<?> paramType = parameter.getParameterType();
		NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
        //执行子类的方法
		Object arg = resolveName(namedValueInfo.name, parameter, webRequest);
		if (arg == null) {
			if (namedValueInfo.defaultValue != null) {
				arg = resolveDefaultValue(namedValueInfo.defaultValue);
			}
			else if (namedValueInfo.required) {
				handleMissingValue(namedValueInfo.name, parameter);
			}
			arg = handleNullValue(namedValueInfo.name, arg, paramType);
		}
		else if ("".equals(arg) && (namedValueInfo.defaultValue != null)) {
			arg = resolveDefaultValue(namedValueInfo.defaultValue);
		}

		if (binderFactory != null) {
			WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
           //进行数据类型转换,前台传递都是String类型,需要转换成接收的数据类型
			arg = binder.convertIfNecessary(arg, paramType, parameter);
		}

		handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);

		return arg;
	}

下边是所有数据类型转换的代码:

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) {
			// 

			if (convertedValue != null) {
                //object类型转换
				if (Object.class.equals(requiredType)) {
					return (T) convertedValue;
				}
				if (requiredType.isArray()) {
					// 数组转换
					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) {
					// 集合转换
					convertedValue = convertToTypedCollection(
							(Collection) convertedValue, propertyName, requiredType, typeDescriptor);
					standardConversion = true;
				}
				else if (convertedValue instanceof Map) {
					// Map类型转换
					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<T> strCtor = requiredType.getConstructor(String.class);
							return 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;
	}

 

转载于:https://my.oschina.net/u/2527296/blog/864900

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值