springMVC使用HandlerMethodArgumentResolver 自定义解析器实现请求参数绑定方法参数

时间:2021-02-18 09:47:04

平时工作用是struts2,近来试了下springMVC,感觉很方便。
然后遇到了问题:
我有Person和Cat两个类,他们都有name这个field,如果我有一个Controller的方法接收Cat和Person两个参数,我应该如何分别他们的name?
话说在页面写person.name和cat.name是没什么意义的,于是我看了一下*。
有人推荐我写一个类,并给这个类里增加Person和Cat类型的变量,这样就可以在页面里写person.name和cat.name以作区分了。
虽然解决问题,但并不高雅。
于是我找到了另一个方法——给method参数加annotation,使用HandlerMethodArgumentResolver。
那就顺便说说HandlerMethodArgumentResolver。

 

springMVC有这样一个类:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

欢迎加入我的QQ交流群425783133
view sourceprint?01./**02.* An {@link AbstractHandlerMethodAdapter} that supports {@link HandlerMethod}s03.* with the signature -- method argument and return types, defined in04.* {@code @RequestMapping}.05.*06.* <p>Support for custom argument and return value types can be added via07.* {@link #setCustomArgumentResolvers} and {@link #setCustomReturnValueHandlers}.08.* Or alternatively to re-configure all argument and return value types use09.* {@link #setArgumentResolvers} and {@link #setReturnValueHandlers(List)}.10.*11.* @author Rossen Stoyanchev12.* @since 3.113.* @see HandlerMethodArgumentResolver14.* @see HandlerMethodReturnValueHandler15.*/16.public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware,17.InitializingBean

看了说明大致明白,他可以用来定制method参数和返回值。
我这里需要修改的是参数,也就是需要用他的setCustomArgumentResolvers方法。


 

view sourceprint?1./**2.* Provide resolvers for custom argument types. Custom resolvers are ordered3.* after built-in ones. To override the built-in support for argument4.* resolution use {@link #setArgumentResolvers} instead.5.*/6.public void setCustomArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {7.this.customArgumentResolvers = argumentResolvers;8.}

参数List类型的泛型是HandlerMethodArgumentResolver,我需要有一个类去实现他。

 

view sourceprint?01.import java.lang.reflect.Field;02.import java.util.Iterator;03.import org.springframework.beans.BeanUtils;04.import org.springframework.core.MethodParameter;05.import org.springframework.web.bind.support.WebDataBinderFactory;06.import org.springframework.web.context.request.NativeWebRequest;07.import org.springframework.web.method.support.HandlerMethodArgumentResolver;08.import org.springframework.web.method.support.ModelAndViewContainer;09.import pac.ano.FormModel;10.public class MyMethodArgumentsResolver implements HandlerMethodArgumentResolver {11. 12.public boolean supportsParameter(MethodParameter parameter) {13.return parameter.hasParameterAnnotation(FormModel.class);14.}15.public Object resolveArgument(MethodParameter parameter,16.ModelAndViewContainer mavContainer, NativeWebRequest webRequest,17.WebDataBinderFactory binderFactory) throws Exception {18.String objName = parameter.getParameterName() + ".";19.Object o = BeanUtils.instantiate(parameter.getParameterType());20.StringBuffer tmp;21.String[] val;22.Field[] frr = parameter.getParameterType().getDeclaredFields();23.for (Iterator<String> itr = webRequest.getParameterNames(); itr24..hasNext();) {25.tmp = new StringBuffer(itr.next());26.if (tmp.indexOf(objName) < 0)continue;27.for (int i = 0; i < frr.length; i++) {28.frr[i].setAccessible(true);29.if (tmp.toString().equals(objName + frr[i].getName())) {30.val = webRequest.getParameterValues(tmp.toString());31.frr[i].set(o, val[0]);32.}33.}34.}35.return o;36.}37.}

这是一个不完整的版本,但是用来做例子是足够了。
我可以在supportsParameter里判断参数是否满足我的Resolver。
而在resolveArgument里我们可以处理这些参数。

另外,FormModel就是我创建的annotation。


 

view sourceprint?01.import java.lang.annotation.Documented;02.import java.lang.annotation.ElementType;03.import java.lang.annotation.Retention;04.import java.lang.annotation.RetentionPolicy;05.import java.lang.annotation.Target;06.@Target({ ElementType.PARAMETER })07.@Retention(RetentionPolicy.RUNTIME)08.@Documented09.public @interface FormModel {10.String value();11.}

另外,我需要将他配置到spring context中。

 

view sourceprint?1.<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">2.<property name="synchronizeOnSession" value="true" />3.<property name="customArgumentResolvers">4.<list>5.<bean class="pac.ano.interpreter.MyMethodArgumentsResolver" />6.</list>7.</property>8.</bean>


剩下的就是去使用他,controller中:

 

view sourceprint?1.@RequestMapping(value="/index")2.public ModelAndView index(@FormModel("p")Person p){3.ModelAndView tmpMAV = new ModelAndView("index");4.System.out.println(p);5.tmpMAV.addObject("p.name",p.getName());6.return tmpMAV;7.}

页面中:

 

view sourceprint?1.<form action="index" method="post">2.<input type="text" name="p.name" />3.<input type="text" name="name" />4.<input type="text" name="p.age" />5.<input type="text" name="weight" />6.<input type="text" name="p.height" />7.<input type="submit" value="提交"/>8.</form>

使用起来很简单,但是要把我需要的功能完全时间就需要多做写工作了。

欢迎加入我的QQ交流群425783133