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

时间:2022-07-10 09:47:27

转载自:http://blog.csdn.net/truong/article/details/30971317

平时工作用是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


01. /**
02. * An {@link AbstractHandlerMethodAdapter} that supports {@link HandlerMethod}s
03. * with the signature -- method argument and return types, defined in
04. * {@code @RequestMapping}.
05. *
06. * <p>Support for custom argument and return value types can be added via
07. * {@link #setCustomArgumentResolvers} and {@link #setCustomReturnValueHandlers}.
08. * Or alternatively to re-configure all argument and return value types use
09. * {@link #setArgumentResolvers} and {@link #setReturnValueHandlers(List)}.
10. *
11. * @author Rossen Stoyanchev
12. * @since 3.1
13. * @see HandlerMethodArgumentResolver
14. * @see HandlerMethodReturnValueHandler
15. */
16. public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware,
17. InitializingBean

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


 

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

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

 

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(); itr
24. .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。


 

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. @Documented
09. public @interface FormModel {
10. String value();
11. }

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

 

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中:

 

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. }

页面中:

 

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>

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