HandlerMethodArgumentResolver简介
HandlerMethodArgumentResolver接口有以下两个方法
参考:https://blog.youkuaiyun.com/qq_36285124/article/details/64438245
//是否支持要转换的参数类型
boolean supportsParameter(MethodParameter parameter);
//如果支持的话进行转换
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
自定义当前用户注解
/**
* 当前用户注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = ElementType.PARAMETER)
public @interface CurrentUser {
}
自定义参数解析
/**
* 当前用户MethodArgumentResolver
*/
public class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Inject
private UserService userService;
/**
* 是否支持参数
*/
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
//判断方法参数是否带有@CurrentUser注解且参数类型为User或其子类
return methodParameter.hasParameterAnnotation(CurrentUser.class) && User.class.isAssignableFrom(methodParameter.getParameterType());
}
/**
* 解析变量
*/
@SuppressWarnings("unchecked")
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
//获取当前用户
return userService.getCurrent();
}
}
传统项目注册自定义解析器
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="xx.xx.xx.currentUserMethodArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
使用@CurrentUser注解获取当前用户
@Controller
@RequestMapping("/test")
public class TestController {
@GetMapping("/currentUser")
public String test(@CurrentUser User currentUser) {
......
}
}
问题场景
场景一:平时controller层想要接收多个实体对象时,只能通过@RequestBody的形式,后台接口还需要建立大量的VO,很不方便,能否通过HandlerMethodArgumentResolver自定义解析器,让接口参数接口更方便呢?
项目经理说:可通过拦截的形式,解析参数,封装到对应的实体中。
老A说:在前端时间看spring源码时,发现HandlerMethodArgumentResolver就可以实现。
自定义参数解析demo:
EntityResolve.java类
@Documented
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface EntityResolve {
String value();
}
EntityResolveHandler.java核心解析类
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
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;
public class EntityResolveHandler implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(final MethodParameter parameter) {
return parameter.hasParameterAnnotation(EntityResolve.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
throws Exception {
// 获取http参数值
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
Map<String, String[]> parameterMap = request.getParameterMap();
EntityResolve entityResolve = parameter.getParameterAnnotation(EntityResolve.class);
String paramName = entityResolve.value();
Class<?> parameterType = parameter.getParameterType();
Type parameterizedType = parameter.getParameter().getParameterizedType();
if (parameterizedType instanceof ParameterizedType) {
Type[] types = ((ParameterizedType) parameterizedType).getActualTypeArguments();// 泛型类型列表
List<Object> list = new ArrayList<Object>();
for (Type type : types) {
for (String s : parameterMap.keySet()) {
if (s.startsWith(paramName)) {
for (String paramValue : parameterMap.get(s)) {
Class clazz = (Class) type;
Object object = clazz.newInstance();
String[] split = s.split("\\.");
String p = split[1];
String methodName = getMethodName(p);
Method method = clazz.getMethod(methodName, String.class);
method.invoke(object, paramValue);
list.add(object);
}
}
}
}
return list;
} else {
Object object = parameterType.newInstance();
// 从request中能拿到参数值
for (String s : parameterMap.keySet()) {
if (s.startsWith(paramName)) {
String paramValue = parameterMap.get(s)[0];
String[] split = s.split("\\.");
String p = split[1];
String methodName = getMethodName(p);
Method method = parameterType.getMethod(methodName, String.class);
method.invoke(object, paramValue);
}
}
return object;
}
}
public Object resolveArgument1(final MethodParameter parameter, final ModelAndViewContainer mavContainer,
final NativeWebRequest webRequest, final WebDataBinderFactory binderFactory) throws Exception {
// 获取http参数值
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
Map<String, String[]> parameterMap = request.getParameterMap();
EntityResolve entityResolve = parameter.getParameterAnnotation(EntityResolve.class);
String paramName = entityResolve.value();
Class<?> parameterType = parameter.getParameterType();
Type parameterizedType = parameter.getParameter().getParameterizedType();
if (parameterizedType instanceof ParameterizedType) {
Type[] types = ((ParameterizedType) parameterizedType).getActualTypeArguments();// 泛型类型列表
List<Object> list = new ArrayList<Object>();
for (Type type : types) {
for (String s : parameterMap.keySet()) {
if (s.startsWith(paramName)) {
for (String paramValue : parameterMap.get(s)) {
Class clazz = (Class) type;
Object object = clazz.newInstance();
String[] split = s.split("\\.");
String p = split[1];
String methodName = getMethodName(p);
Method method = clazz.getMethod(methodName, String.class);
method.invoke(object, paramValue);
list.add(object);
}
}
}
}
return list;
} else {
Object object = parameterType.newInstance();
// 从request中能拿到参数值
for (String s : parameterMap.keySet()) {
if (s.startsWith(paramName)) {
String paramValue = parameterMap.get(s)[0];
String[] split = s.split("\\.");
String p = split[1];
String methodName = getMethodName(p);
Method method = parameterType.getMethod(methodName, String.class);
method.invoke(object, paramValue);
}
}
return object;
}
}
String getMethodName(final String paramName) {
StringBuffer sb = new StringBuffer();
sb.append("set");
sb.append(paramName.substring(0, 1).toUpperCase());
sb.append(paramName.substring(1));
return sb.toString();
}
public boolean isListParam(final Class<?> clazz) {
if (List.class.isAssignableFrom(clazz)) {
return true;
}
return false;
}
}
controller层
@RestController
@RequestMapping("/user")
public class SpringTestController {
private static final Logger LOGGER = LoggerFactory.getLogger(SpringTestController.class);
@PostMapping("/test")
public void getUserInfo(HttpServletRequest request, @FormModel("user")User userInfo, @FormModel("dept") Dept dept) {
System.out.println(userInfo.getUsername());
System.out.println(userInfo.toString());
System.out.println(dept.toString());
}
}