`
DS_Mars
  • 浏览: 1892 次
社区版块
存档分类
最新评论

SpringMVC同名参数属性简单解决方案obj.property

阅读更多
首先 自定义注解ExtModelAttribute
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExtModelAttribute {

	String value() default "";

}


然后利用方法
void org.springframework.web.bind.WebDataBinder.setFieldDefaultPrefix(String fieldDefaultPrefix)
在对应自定义注解ExtModelAttribute的处理器ExtServletModelAttributeMethodProcessor.bindRequestParameters(WebDataBinder binder, NativeWebRequest request)
改变默认前缀
不过到3.2.8 还是有点小问题 前缀后面要加一个字符 比如“.”
另外这样改只适合 没有 value 的 ExtModelAttribute 扩展有限
如果参数中类相同就悲剧了
因为springmvc 很多地方限制死了只能处理 ModelAttribute
虽然注解处理器可以进入,但通过继承的方式其他的东西还是在处理ModelAttribute
比如获取bind 的名称,另外涉及的两个处理器类有final 方法无法通过继承扩展
只能重新定义

以下是自定义注解对应处理器ExtServletModelAttributeMethodProcessor
import javax.servlet.ServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.core.Conventions;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.DataBinder;
import org.springframework.validation.Errors;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.method.annotation.ModelFactory;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.ServletRequestDataBinderFactory;

public class ExtServletModelAttributeMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler{

	
	public ExtServletModelAttributeMethodProcessor() {
		this.annotationNotRequired = false;
	}
	
	public ExtServletModelAttributeMethodProcessor(boolean annotationNotRequired) {
		this.annotationNotRequired = annotationNotRequired;
	}
	//->From ModelAttributeMethodProcessor
	
	protected Log logger = LogFactory.getLog(this.getClass());

	private final boolean annotationNotRequired;

	/**
	 * @return true if the parameter is annotated with {@link ModelAttribute}
	 * or in default resolution mode also if it is not a simple type.
	 */
	public boolean supportsParameter(MethodParameter parameter) {
		if (parameter.hasParameterAnnotation(ExtModelAttribute.class)) {
			return true;
		}
		else if (this.annotationNotRequired) {
			return !BeanUtils.isSimpleProperty(parameter.getParameterType());
		}
		else {
			return false;
		}
	}

	/**
	 * Resolve the argument from the model or if not found instantiate it with
	 * its default if it is available. The model attribute is then populated
	 * with request values via data binding and optionally validated
	 * if {@code @java.validation.Valid} is present on the argument.
	 * @throws BindException if data binding and validation result in an error
	 * and the next method parameter is not of type {@link Errors}.
	 * @throws Exception if WebDataBinder initialization fails.
	 */
	public final Object resolveArgument(
			MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest request, WebDataBinderFactory binderFactory)
			throws Exception {
		//change here
		String name = ModelFactory_getNameForParameter(parameter);
		Object attribute = (mavContainer.containsAttribute(name)) ?
				mavContainer.getModel().get(name) : createAttribute(name, parameter, binderFactory, request);

		WebDataBinder binder = binderFactory.createBinder(request, attribute, name);
		if (binder.getTarget() != null) {
			bindRequestParameters(binder, request);
			validateIfApplicable(binder, parameter);
			if (binder.getBindingResult().hasErrors()) {
				if (isBindExceptionRequired(binder, parameter)) {
					throw new BindException(binder.getBindingResult());
				}
			}
		}

		// Add resolved attribute and BindingResult at the end of the model

		Map<String, Object> bindingResultModel = binder.getBindingResult().getModel();
		mavContainer.removeAttributes(bindingResultModel);
		mavContainer.addAllAttributes(bindingResultModel);

		return binder.getTarget();
	}

	//->Rename as native method! because ServletModelAttributeMethodProcessor has Override it,and use it!
	/**
	 * Extension point to create the model attribute if not found in the model.
	 * The default implementation uses the default constructor.
	 * @param attributeName the name of the attribute, never {@code null}
	 * @param parameter the method parameter
	 * @param binderFactory for creating WebDataBinder instance
	 * @param request the current request
	 * @return the created model attribute, never {@code null}
	 */
	protected Object ModelAttributeMethodProcessor_CreateAttribute(String attributeName, MethodParameter parameter,
			WebDataBinderFactory binderFactory,  NativeWebRequest request) throws Exception {

		return BeanUtils.instantiateClass(parameter.getParameterType());
	}

	//->Delete!  ServletModelAttributeMethodProcessor has Override it but not use it
	/**
	 * Extension point to bind the request to the target object.
	 * @param binder the data binder instance to use for the binding
	 * @param request the current request
	 */
//	protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
//		((WebRequestDataBinder) binder).bind(request);
//	}

	/**
	 * Validate the model attribute if applicable.
	 * <p>The default implementation checks for {@code @javax.validation.Valid}.
	 * @param binder the DataBinder to be used
	 * @param parameter the method parameter
	 */
	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;
			}
		}
	}

	/**
	 * Whether to raise a {@link BindException} on validation errors.
	 * @param binder the data binder used to perform data binding
	 * @param parameter the method argument
	 * @return {@code true} if the next method argument is not of type {@link Errors}.
	 */
	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;
	}

	/**
	 * Return {@code true} if there is a method-level {@code @ModelAttribute}
	 * or if it is a non-simple type when {@code annotationNotRequired=true}.
	 */
	public boolean supportsReturnType(MethodParameter returnType) {
		if (returnType.getMethodAnnotation(ModelAttribute.class) != null) {
			return true;
		}
		else if (this.annotationNotRequired) {
			return !BeanUtils.isSimpleProperty(returnType.getParameterType());
		}
		else {
			return false;
		}
	}

	/**
	 * Add non-null return values to the {@link ModelAndViewContainer}.
	 */
	public void handleReturnValue(
			Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws Exception {

		if (returnValue != null) {
			String name = ModelFactory.getNameForReturnValue(returnValue, returnType);
			mavContainer.addAttribute(name, returnValue);
		}
	}
	//<-From ModelAttributeMethodProcessor
	
	//->From ServletModelAttributeMethodProcessor
	/**
	 * Instantiate the model attribute from a URI template variable or from a
	 * request parameter if the name matches to the model attribute name and
	 * if there is an appropriate type conversion strategy. If none of these
	 * are true delegate back to the base class.
	 * @see #createAttributeFromRequestValue(String, String, MethodParameter, WebDataBinderFactory, NativeWebRequest)
	 */
	protected final Object createAttribute(String attributeName,
										   MethodParameter parameter,
										   WebDataBinderFactory binderFactory,
										   NativeWebRequest request) throws Exception {

		String value = getRequestValueForAttribute(attributeName, request);
		if (value != null) {
			Object attribute = createAttributeFromRequestValue(value, attributeName, parameter, binderFactory, request);
			if (attribute != null) {
				return attribute;
			}
		}

		return ModelAttributeMethodProcessor_CreateAttribute(attributeName, parameter, binderFactory, request);
	}

	/**
	 * Obtain a value from the request that may be used to instantiate the
	 * model attribute through type conversion from String to the target type.
	 * <p>The default implementation looks for the attribute name to match
	 * a URI variable first and then a request parameter.
	 * @param attributeName the model attribute name
	 * @param request the current request
	 * @return the request value to try to convert or {@code null}
	 */
	protected String getRequestValueForAttribute(String attributeName, NativeWebRequest request) {
		Map<String, String> variables = getUriTemplateVariables(request);
		if (StringUtils.hasText(variables.get(attributeName))) {
			return variables.get(attributeName);
		}
		else if (StringUtils.hasText(request.getParameter(attributeName))) {
			return request.getParameter(attributeName);
		}
		else {
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	protected final Map<String, String> getUriTemplateVariables(NativeWebRequest request) {
		Map<String, String> variables =
			(Map<String, String>) request.getAttribute(
					HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
		return (variables != null) ? variables : Collections.<String, String>emptyMap();
	}

	/**
	 * Create a model attribute from a String request value (e.g. URI template
	 * variable, request parameter) using type conversion.
	 * <p>The default implementation converts only if there a registered
	 * {@link Converter} that can perform the conversion.
	 * @param sourceValue the source value to create the model attribute from
	 * @param attributeName the name of the attribute, never {@code null}
	 * @param parameter the method parameter
	 * @param binderFactory for creating WebDataBinder instance
	 * @param request the current request
	 * @return the created model attribute, or {@code null}
	 * @throws Exception
	 */
	protected Object createAttributeFromRequestValue(String sourceValue,
												 String attributeName,
												 MethodParameter parameter,
												 WebDataBinderFactory binderFactory,
												 NativeWebRequest request) throws Exception {
		DataBinder binder = binderFactory.createBinder(request, null, attributeName);
		ConversionService conversionService = binder.getConversionService();
		if (conversionService != null) {
			TypeDescriptor source = TypeDescriptor.valueOf(String.class);
			TypeDescriptor target = new TypeDescriptor(parameter);
			if (conversionService.canConvert(source, target)) {
				return binder.convertIfNecessary(sourceValue, parameter.getParameterType(), parameter);
			}
		}
		return null;
	}
	
	//The ModelFactory only support ModelAttribute must change it!
	/**
	 * {@inheritDoc}
	 * <p>Downcast {@link WebDataBinder} to {@link ServletRequestDataBinder} before binding.
	 * @see ServletRequestDataBinderFactory
	 */
	protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
		ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);
		ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
		servletBinder.setFieldDefaultPrefix(servletBinder.getObjectName()+".");
		servletBinder.bind(servletRequest);
	}
	//->From ServletModelAttributeMethodProcessor
	
	
	//The ModelFactory only support ModelAttribute must change it!
	//->From ModelFactory
	public static String ModelFactory_getNameForParameter(MethodParameter parameter) {
		//ModelAttribute annot = parameter.getParameterAnnotation(ModelAttribute.class);
		ExtModelAttribute annot = parameter.getParameterAnnotation(ExtModelAttribute.class);
		String attrName = (annot != null) ? annot.value() : null;
		return StringUtils.hasText(attrName) ? attrName :  Conventions.getVariableNameForParameter(parameter);
	}
	//<-From ModelFactory
}


加入自定义注解ExtModelAttribute 的处理器ExtServletModelAttributeMethodProcessor
    <mvc:annotation-driven>
        <mvc:argument-resolvers>
            <bean class="ExtServletModelAttributeMethodProcessor"/>
        </mvc:argument-resolvers>
    </mvc:annotation-driven>


控制器中使用
        @RequestMapping(value="/test")
	public String ftl(@ExtModelAttribute("testVo1")TestVo testVo1,@ExtModelAttribute("testVo2")TestVo testVo2){
		System.out.println(testVo1.getValue());
System.out.println(testVo2.getValue());
		return "test";
	}


页面使用
        <form action="" method="post">
        testVo1.value<Input id="value1" name="testVo1.value" value="${testVo1.value}" />
        testVo2.value<Input id="value2" name="testVo2.value" value="${testVo2.value}" />
            <input type="submit" value="submit">
        </form>

分享到:
评论

相关推荐

    SpringMVC精品资源--基于springMVC实现的解决方案系统.zip

    在“SpringMVC精品资源--基于springMVC实现的解决方案系统.zip”这个压缩包中,我们可以推测包含了一系列关于SpringMVC开发的教程、示例代码或完整的项目模板,用于帮助开发者更好地理解和应用SpringMVC。...

    本科毕设-课设-基于SpringMVC+MyBatis开发学生管理系统.zip

    本科毕设-课设-基于SpringMVC+MyBatis开发学生管理系统.zip本科毕设-课设-基于SpringMVC+MyBatis开发学生管理系统.zip本科毕设-课设-基于SpringMVC+MyBatis开发学生管理系统.zip本科毕设-课设-基于SpringMVC+MyBatis...

    1、手写springmvc框架及分析springmvc源码.zip

    1、手写springmvc框架及分析springmvc源码.zip1、手写springmvc框架及分析springmvc源码.zip1、手写springmvc框架及分析springmvc源码.zip1、手写springmvc框架及分析springmvc源码.zip1、手写springmvc框架及分析...

    SpringMVC简介与多线程解决方案

    ### 多线程解决方案 在Java中,多线程是实现并发执行任务的关键。SpringMVC提供了一种在服务层实现多线程的方法,以提高程序的执行效率和响应速度。以下是一些关键概念: 1. **ThreadPoolTaskExecutor**:Spring...

    SpringMVC后台接收请求参数的几种方式Demo

    使用`@ModelAttribute`注解,我们可以将请求参数绑定到对象属性上: ```java @PostMapping("/save") public String saveUser(@ModelAttribute("user") User user) { // ... } ``` 用户类可能如下所示: ```...

    springmvc_4\springmvc_4.part1.rar

    springmvc_4\springmvc_4.part1.rar

    分析springmvc源码(2).zip

    分析springmvc源码(2).zip分析springmvc源码(2).zip分析springmvc源码(2).zip分析springmvc源码(2).zip分析springmvc源码(2).zip分析springmvc源码(2).zip分析springmvc源码(2).zip分析springmvc源码(2).zip分析...

    分析springmvc源码(5).zip

    分析springmvc源码(5).zip分析springmvc源码(5).zip分析springmvc源码(5).zip分析springmvc源码(5).zip分析springmvc源码(5).zip分析springmvc源码(5).zip分析springmvc源码(5).zip分析springmvc源码(5).zip分析...

    springmvc基础.docx

    springmvc基础 包含代码+知识点+详细解释 1. 什么是springmvc? 2. springmvc框架原理 前端控制器、处理器映射器、处理器适配器... 参数绑定(简单类型、pojo、集合类型) 自定义参数绑定 6. springmvc和struts2区别

    SpringMVC纯注解配置

    "SpringMVC纯注解配置"是SpringMVC框架的一种高级用法,旨在减少XML配置文件的使用,提高开发效率和代码可读性。在这个主题中,我们将深入探讨如何利用注解实现SpringMVC的配置以及jQuery如何处理后台返回的JSON对象...

    springmvc绑定Set的解决方案

    本文将详述如何在Spring MVC中实现对Set类型的参数进行绑定,以解决可能遇到的问题。 首先,理解Spring MVC的数据绑定机制是至关重要的。Spring MVC在接收到HTTP请求后,会尝试将请求参数与控制器方法的参数进行...

    一、SpringMVC尚硅谷的笔记.md

    springmvc 笔记

    SpringMVC参数收集及乱码处理.docx

    SpringMVC 参数收集及乱码处理 SpringMVC 框架提供了多种参数收集方式,以满足不同的应用场景需求。 ParametersCollector 是 SpringMVC 中负责收集参数的组件,它可以从 HttpServletRequest 中获取参数,并将其...

    springmvc_4\springmvc_4.part2.rar

    springmvc

    springmvc入门参数绑定ssm整合

    SpringMVC入门参数绑定SSM整合 SpringMVC是一种基于MVC模式的Web应用程序框架,它是Spring框架的一个模块,用于开发Web项目。下面是SpringMVC入门参数绑定SSM整合的知识点总结: 一、SpringMVC概述 SpringMVC是...

    SpringMVC Tomcat控制台乱码问题解决方案

    SpringMVC Tomcat控制台乱码问题解决方案 本文主要介绍了SpringMVC Tomcat控制台乱码问题解决方案,该解决方案通过示例代码进行了详细的介绍,对大家的学习或者工作具有一定的参考学习价值。下面将对该解决方案进行...

    SpringMVC原理共3页.pdf.zip

    SpringMVC是Spring框架的一个模块,它主要用于构建Web应用程序的后端控制器。作为一个成熟的MVC(Model-View-Controller)框架,SpringMVC通过解耦应用程序的业务逻辑、数据处理和用户界面,使得开发过程更加高效和...

    Java进阶之SpringMVC应用共16页.pdf.zi

    15. **与其他Spring模块的整合**:SpringMVC可以很好地与Spring的其他模块,如Spring AOP、Spring Security、Spring Data等集成,构建完整的应用解决方案。 学习和掌握这些核心概念是Java开发者进阶到SpringMVC领域...

    Springmvc+Mybatis精品教程 专用sql.rar

    Springmvc+Mybatis精品教程 专用sql。找了半天没找到。 所以上传下 配套教程地址:https://www.bilibili.com/video/BV1sb411x7VQ?p=4

Global site tag (gtag.js) - Google Analytics