springMVC使用HandlerMethodArgumentResolver 自定义解析器实现请求参数绑定方法参数
来源:互联网 发布:java files.write 编辑:程序博客网 时间:2024/05/22 04:48
springMVC 数据绑定 多个对象 如何准确绑定?
遇到的问题:
我有Person和Cat两个类,他们都有name这个field,如果我有一个Controller的方法接收Cat和Person两个参数,我应该如何分别他们的name?
话说在页面写person.name和cat.name是没什么意义的,于是我看了一下stackOverFlow。
有人推荐我写一个类,并给这个类里增加Person和Cat类型的变量,这样就可以在页面里写person.name和cat.name以作区分了。
虽然解决问题,但并不高雅。
于是我找到了另一个方法——给method参数加annotation,使用HandlerMethodArgumentResolver。
SpringMVC3.1引入了HandlerMethodArgumentResolver接口,spring调用该接口实现Controller的参数装配。HandlerMethodArgumentResolver实现类中会调用DataBinder,Converter等。
常用的该接口实现类有:
ServletModelAttributeMethodProcessor:实体类的组装用它实现。
RequestParamMethodArgumentResolver:基本数据类型如String用它实现。
在我学习过程中,发现对List类型的参数SpringMVC没有提供默认实现。我参照Spring的示例 通过实现 HandlerMethodArgumentResolver接口,实现对List参数的组装
那么在说HandlerMethodArgumentResolver接口实现之前,要先说一个类:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
/*** An {@link AbstractHandlerMethodAdapter} that supports {@link HandlerMethod}s* with the signature -- method argument and return types, defined in* {@code @RequestMapping}.** <p>Support for custom argument and return value types can be added via* {@link #setCustomArgumentResolvers} and {@link #setCustomReturnValueHandlers}.* Or alternatively to re-configure all argument and return value types use* {@link #setArgumentResolvers} and {@link #setReturnValueHandlers(List)}.** @author Rossen Stoyanchev* @since 3.1* @see HandlerMethodArgumentResolver* @see HandlerMethodReturnValueHandler*/public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware,InitializingBean
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
看了说明大致明白,他可以用来定制method参数和返回值。
我这里需要修改的是参数,也就是需要用他的setCustomArgumentResolvers方法。
/*** Provide resolvers for custom argument types. Custom resolvers are ordered* after built-in ones. To override the built-in support for argument* resolution use {@link #setArgumentResolvers} instead.*/public void setCustomArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {this.customArgumentResolvers = argumentResolvers;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
参数List类型的泛型是HandlerMethodArgumentResolver,我需要有一个类去实现他。
实现类:
package ;import java.lang.annotation.Annotation;import java.util.Map;import javax.servlet.ServletRequest;import org.apache.commons.lang.StringUtils;import org.springframework.beans.BeanUtils;import org.springframework.core.MethodParameter;import org.springframework.core.annotation.AnnotationUtils;import org.springframework.validation.BindException;import org.springframework.validation.Errors;import org.springframework.validation.annotation.Validated;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.method.support.HandlerMethodArgumentResolver;import org.springframework.web.method.support.ModelAndViewContainer;import com.maigangle.erp.common.annotation.FormModel;/** * 解析obj.xx * * * * @version 1.0 * */public class FormObjectMethodArgumentsResolver implements HandlerMethodArgumentResolver { public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(FormModel.class); } public Object resolveArgument( MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { FormModel multi = parameter.getParameterAnnotation(FormModel.class); String name = StringUtils.isEmpty(multi.value()) ? parameter.getParameterName() : multi.value();// 参数名:默认去@Multi的value值 // 如果是""则去获取参数值的命名变量 // String name = ModelFactory.getNameForParameter(parameter); Object attribute = (mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) : createAttribute(name, parameter, binderFactory, webRequest)); if (!mavContainer.isBindingDisabled(name)) { ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class); if (ann != null && !ann.binding()) { mavContainer.setBindingDisabled(name); } } WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name); if (binder.getTarget() != null) { if (!mavContainer.isBindingDisabled(name)) { bindRequestParameters(binder, webRequest, name); } validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors() && 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.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter); } protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request, String parameterName) { ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class); ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder; // servletBinder.setFieldDefaultPrefix(servletBinder.getObjectName()+"."); servletBinder.setFieldDefaultPrefix(parameterName + "."); servletBinder.bind(servletRequest); } protected Object createAttribute(String attributeName, MethodParameter methodParam, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { return BeanUtils.instantiateClass(methodParam.getParameterType()); } protected void validateIfApplicable(WebDataBinder binder, MethodParameter methodParam) { Annotation[] annotations = methodParam.getParameterAnnotations(); for (Annotation ann : annotations) { Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class); if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) { Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann)); Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[]{hints}); binder.validate(validationHints); break; } } } protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter methodParam) { int i = methodParam.getParameterIndex(); Class<?>[] paramTypes = methodParam.getMethod().getParameterTypes(); boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1])); return !hasBindingResult; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
supportsParameter里判断参数是否满足我的Resolver。
而在resolveArgument里我们可以处理这些参数。
另外,FormModel就是我创建的annotation。
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;/** * * * * @version 1.0 **/@Target({ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface FormModel { String value();}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
另外,我需要将他配置到spring context中。
<!--自定义controller接受参数进行解析 --> <mvc:annotation-driven> <mvc:argument-resolvers> <bean class="com.common.util.FormObjectMethodArgumentsResolver" /> </mvc:argument-resolvers> </mvc:annotation-driven>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
或者中配置的方式:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"><property name="synchronizeOnSession" value="true" /><property name="customArgumentResolvers"><list><bean class="com.common.util.FormObjectMethodArgumentsResolver" /></list></property></bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
剩下的就是去使用他,controller中:
@RequestMapping(value="/index")public ModelAndView index(@FormModel("p")Person p){ModelAndView tmpMAV = new ModelAndView("index");System.out.println(p);tmpMAV.addObject("p.name",p.getName());return tmpMAV;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
页面中:
<form action="index" method="post"><input type="text" name="p.name" /><input type="text" name="name" /><input type="text" name="p.age" /><input type="text" name="weight" /><input type="text" name="p.height" /><input type="submit" value="提交"/></form>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
参考:http://blog.csdn.net/truong/article/details/30971317
问题点:
1.为什么开始要讲RequestMappingHandlerAdapter
DefaultAnnotationHandlerMapping和 AnnotationMethodHandlerAdapter是spring mvc 支持类注解和方法级别注解的两个处理类
DefaultAnnotationHandlerMapping用来解析Spring MVC里面的annotation对应的Controller,也就是通过这个类,给annotation设置映射关系,如@RequestMapping等
AnnotationMethodHandlerAdapter
对Annotation设置的方法进行处理的类,通过此类,解析annotation设置的类的处理,也就是有请求时,通过此类,可以调用annotation设置controller的方法,主要处理方法
一般配置为:
<!-- 处理在类级别上的@RequestMapping注解 --><bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"> <property name="interceptors"> <list> <!-- 多个拦截器,顺序执行 --> <ref bean="SpringMVCInterceptor" /> <ref bean="OpenSessionInViewInterceptor"/> </list> </property></bean><!-- 处理方法级别上的@RequestMapping注解 --><bean id="annotationMethodHandlerAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/html;charset=utf-8</value> <value>text/plain;charset=utf-8</value> </list> </property> </bean> <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverterv2"> <property name="objectMapper"> <bean class="net.pm.misc.Hibernate4AwareObjectMapper" /> </property> </bean> </list> </property></bean><!-- 表示使用cglib,而非JDK的动态代理,因为Controller没有实现接口,所以要配置这里 --><aop:aspectj-autoproxy proxy-target-class="true" />
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
xml配置中annotation-driven和DefaultAnnotationHandlerMapping/AnnotationMethodHandlerAdapter的关系
Spring 3.0.x中使用了annotation-driven后,缺省使用DefaultAnnotationHandlerMapping 来注册handler method和request的mapping关系。 AnnotationMethodHandlerAdapter来在实际调用handlermethod前对其参数进行处理。
在spring mvc 3.1中,对应变更为
DefaultAnnotationHandlerMapping -> RequestMappingHandlerMapping
AnnotationMethodHandlerAdapter -> RequestMappingHandlerAdapter
AnnotationMethodHandlerExceptionResolver -> ExceptionHandlerExceptionResolver
以上都在使用了annotation-driven后自动注册。
而且对应分别提供了AbstractHandlerMethodMapping , AbstractHandlerMethodAdapter和 AbstractHandlerMethodExceptionResolver以便于让用户更方便的实现自定义的实现类。
相当于注册了DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter两个bean,配置一些messageconverter。即解决了@Controller注解的使用前提配置。
这两个功能相似,不能一起使用
参考:http://starscream.iteye.com/blog/1098880
2.FormModel类上的注解都是什么意思
@Target,@Retention,@Documented详解
要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法。
1、元注解(meta-annotation):
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
1.@Target,
2.@Retention,
3.@Documented,
4.@Inherited
这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应分参数的使用说明。
@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。
作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
取值(ElementType)有:
1.CONSTRUCTOR:用于描述构造器
2.FIELD:用于描述域
3.LOCAL_VARIABLE:用于描述局部变量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述参数
7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
@Retention:
@Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。
作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
取值(RetentionPoicy)有:
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在运行时有效(即运行时保留)
@Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
详情参考:http://www.cnblogs.com/gmq-sh/p/4798194.html
- springMVC使用HandlerMethodArgumentResolver 自定义解析器实现请求参数绑定方法参数
- springMVC使用HandlerMethodArgumentResolver 自定义解析器实现请求参数绑定方法参数
- springMVC使用HandlerMethodArgumentResolver 自定义解析器实现请求参数绑定方法参数
- springMVC使用HandlerMethodArgumentResolver 自定义解析器实现请求参数绑定方法参数
- springMVC使用HandlerMethodArgumentResolver 自定义解析器实现请求参数绑定方法参数
- springMVC使用HandlerMethodArgumentResolver 自定义解析器实现请求参数绑定方法参数
- springMVC使用HandlerMethodArgumentResolver 自定义解析器实现请求参数绑定方法参数
- springMVC使用HandlerMethodArgumentResolver 自定义解析器实现请求参数绑定方法参数
- SpringMVC 使用HandlerMethodArgumentResolver自定义解析器实现请求数据绑定方法入参
- SpringMVC之分析HandlerMethodArgumentResolver请求对应处理器方法参数的解析过程(一)
- SpringMVC之分析HandlerMethodArgumentResolver请求对应处理器方法参数的解析过程(二)
- 通过实现HandlerMethodArgumentResolver接口,给springMvc的Controller的方法注入自定义参数
- springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)
- SpringMVC预处理方法参数HandlerMethodArgumentResolver类
- springMVC请求参数绑定
- springmvc请求参数绑定
- springmvc自定义参数绑定实现日期参数绑定
- SpringMVC自定义参数绑定
- codeforces 814D An overnight dance in discotheque(几何思维)
- JMeter中3种参数值的传递
- Linux系统中用命令行清空垃圾箱Trash
- AngularJS手势事件
- java 追踪调试
- springMVC使用HandlerMethodArgumentResolver 自定义解析器实现请求参数绑定方法参数
- MySql--数据库事务四大特性以及隔离级别
- 配置系统的本地yum源
- zip4j -- Java处理zip压缩文件的完整解决方案
- opencv基本图像运算
- CodeForces
- 内存恶鬼drawRect
- Ueditor上传图片,ssh和ssm框架下Ueditor整合
- 【STM32F103攻城笔记】输入捕捉实战