介绍
前面几节我们介绍了Spring MVC的几种常见的数据绑定的方法,可以灵活地获取用户请求中的参数,例如@PathVariable,@ModelAttribute,@RequestParam等这些数据绑定注解,有了这些注解,我们可以很方便的去获取参数,但是偶尔我们需要自定义的去进行数据绑定,Spring一直遵循开闭原则,可以让使用者自定义去做自己的事情,今天我们一起浅析一下HandlerMethodArgumentResolver
认识HandlerMethodArgumentResolver,我们可以看下HandlerMethodArgumentResolver的继承关系图
我们可以很清楚的看到我们常见的几个数据绑定的annotation的具体实现都是实现了HandlerMethodArgumentResolver这个接口,我们可以先尝试一下写一个demo,自定义annotation绑定一个数据
首先我们新建一个annotation-----CurrentUser 默认只能注解参数,且运行时有效:
package org.study.lyncc.web.resolver.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;
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CurrentUser {
String value() default "";
}
我们按照他的定义,自定义一个CurrentUserHandlerMethodArgumentResolver实现HandlerMethodArgumentResolver:
package org.study.lyncc.web.resolver;
import org.springframework.core.MethodParameter;
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 org.study.lyncc.web.entity.User;
import org.study.lyncc.web.resolver.annotation.CurrentUser;
public class CurrentUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver{
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(CurrentUser.class);
}
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return new User(1,"lyncc");
}
}
这边只是一个简单的demo,默认返回一个user,这样,我们写个controller来测试一下
package org.study.lyncc.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.study.lyncc.web.entity.User;
import org.study.lyncc.web.resolver.annotation.CurrentUser;
@Controller
@RequestMapping(value="/data/binding")
public class CostomDataBindingController {
@RequestMapping(value="/test")
public ModelAndView costomData(@CurrentUser User u){
System.out.println(u.getUsername());
ModelAndView mav = new ModelAndView("session");
return mav;
}
}
我们写了一个测试方法,costomData中间的入参是User,前面加了我们自定义的注解@CurrentUser,这样此处的User应该就是我们在CurrentUserHandlerMethodArgumentResolver中resolveArgument方法返回的对象了
不过我们还需要让spring容器加载我们自定义的数据绑定的类CurrentUserHandlerMethodArgumentResolver,我们修改一下我们spring mvc的配置文件spring-servlet.xml
在启动spring mvc 浏览器中输入:http://localhost:8080/spring-mvc/data/binding/test,发现在控制台中正常打印了
好了,我们再举一个例子,加入我们的url是http://localhost:8080/spring-mvc/data/binding/custom?names=lyncc,fly,ted&ids=1,2,3,我们想要在后台直接获取一个List
也就说我们可以提前转化
同样我们定义一个annotation
package org.study.lyncc.web.resolver.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;
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ManyUser {
String value() default "";
}
ManyUserHandlerMethodArgumentResolver
package org.study.lyncc.web.resolver;
import java.util.ArrayList;
import java.util.List;
import org.springframework.core.MethodParameter;
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 org.study.lyncc.web.entity.User;
import org.study.lyncc.web.resolver.annotation.ManyUser;
public class ManyUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver{
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(ManyUser.class);
}
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
List users = new ArrayList();
String names = (String)webRequest.getParameter("names");
String ids = (String)webRequest.getParameter("ids");
if(null != names && null != ids){
String[] nameStrs = names.trim().split(",");
String[] idStrs = ids.trim().split(",");
for(int i = 0;i
package org.study.lyncc.web.controller;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.study.lyncc.web.entity.User;
import org.study.lyncc.web.resolver.annotation.CurrentUser;
import org.study.lyncc.web.resolver.annotation.ManyUser;
@Controller
@RequestMapping(value="/data/binding")
public class CostomDataBindingController {
@RequestMapping(value="/test")
public ModelAndView costomData(@CurrentUser User u){
System.out.println(u.getUsername());
ModelAndView mav = new ModelAndView("session");
return mav;
}
@RequestMapping(value="/custom")
public ModelAndView customData1(@ManyUser List users){
if(null != users && !users.isEmpty()){
for(User u : users){
System.out.println(u);
}
}
ModelAndView mav = new ModelAndView("session");
return mav;
}
}
别忘记修改spring-servlet.xml
启动项目,输入http://localhost:8080/spring-mvc/data/binding/custom?names=lyncc,fly,ted&ids=1,2,3