今天在做项目时遇到了一个有关参数解析 HandlerMethodArgumentResolver
的使用疑惑。因此去 百度学习了一下,现在记录一下。
想要自定义参数解析器,就要实现HandlerMethodArgumentResolver
接口,而它是springMvc
下的一个接口,引入spring-web的starter就可见了。
接口内容:
package org.springframework.web.method.support;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
/**
* Strategy interface for resolving method parameters into argument values in
* the context of a given request.
*
* @author Arjen Poutsma
* @since 3.1
* @see HandlerMethodReturnValueHandler
*/
public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter parameter);
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
可以看到这个接口有两个方法,分别为supportsParameter
和resolveArgument
。
supportsParameter()
它很好理解,返回值是boolean类型,它的作用是判断Controller层中的参数,是否满足条件,满足条件则执行resolveArgument方法,不满足则跳过。
resolveArgument()
它只有在supportsParameter方法返回true的情况下才会被调用。用于处理一些业务,将返回值赋值给Controller层中的对应的参数。
未使用参数解析器时的Controller控制器:
/**
* @author Blue 2113438464@qq.com
* @ClassName TestController
* @Description 测试
* @date 2022/7/14 19:23
* @Version 1.0
*/
@Slf4j
@Controller
@RequestMapping("/test")
@RequiredArgsConstructor
public class TestController {
// 构造注入
private final UserService userService;
/**
* 根据用户id获取 内外销,供应商编号
* @param Model 模型
* @param response 响应
* @param cookieToken Token
* @param paramToken Token
* @return 页面路径
*/
@RequestMapping("/toList")
public String toList(Model model,HttpServletResponse response,
@CookieValue(value = UserService.TOKEN,required = false)String cookieToken,
@RequestParam(value = UserService.TOKEN,required = false) String paramToken) {
// 参数安全比较,是否存在Token
if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)){
return "login";
}
// 拿取token
String token = StringUtils.isEmpty(cookieToken) ? paramToken : cookieToken;
// 业务
User user = userService.getByToken(response,token);
// 日志
log.info(user.toString());
// 将数据添加到模型对象中
model.addAttribute("user",user);
// 返回
return "goodsList";
}
}
上面类的toList()方法有两个参数分别为 cookieToken
和 paramToken
,再仔细看一下方法体,不难看出,这两个参数和方法体中的代码就是为了,通过cookie或request其中的token这一变量来查询用户user的信息。
但是大家发没发现,这一个方法,就为了简简单单的这一个小功能,就写了这么多代码,是不是有点过分臃肿呢?而且假如还有其他方法会用到用户user这一信息变量呢,难道也写这么多的代码吗?
好的,这个时候我们就可以使用
HandlerMethodArgumentResolver
接口来进行一下小小的优化。
使用 HandlerMethodArgumentResolver 解析器后:
写一个类实现 HandlerMethodArgumentResolver
接口:
// 自定义参数解析器
@Component
@RequiredArgsConstructor
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
// 构造注入
private final MiaoshaUserService userService;
// 满足条件则执行resolveArgument方法,不满足则跳过
public boolean supportsParameter(MethodParameter parameter) {
// MethodParameter类是专门用来获取方法参数、参数名等功能的类
Class<?> clazz = parameter.getParameterType();
// 判断参数类型
return clazz == MiaoshaUser.class;
}
// 处理Controller层中的对应的参数
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
// 请求
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
// 响应
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
// 获取参数
String paramToken = request.getParameter(MiaoshaUserService.COOKI_NAME_TOKEN);
// MiaoshaUserService.COOKI_NAME_TOKEN为我自定义的常量,就是token名
String cookieToken = getCookieValue(request, MiaoshaUserService.COOKI_NAME_TOKEN);
// 参数安全比较,是否存在Token
if (StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {
return null;
}
// 拿取token
String token = StringUtils.isEmpty(paramToken) ? cookieToken : paramToken;
// 返回User对象
return userService.getByToken(response, token);
}
// 获取Cookie
private String getCookieValue(HttpServletRequest request, String cookiName) {
// 拿到所有Cookie信息
Cookie[] cookies = request.getCookies();
// 循环比较
for(Cookie cookie : cookies) {
if(cookie.getName().equals(cookiName)) {
// 有就返回
return cookie.getValue();
}
}
// 返回为空
return null;
}
}
把我们编写的这个类,注册到配置文件中去:
@Configuration
@RequiredArgsConstructor
public class WebConfig extends WebMvcConfigurerAdapter{
// 构造注入
private final UserArgumentResolver userArgumentResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
// 注册自定义参数解析器
argumentResolvers.add(userArgumentResolver);
}
}
最后,我们的控制类就可以这样写了
@RequestMapping("/toList")
public String toList(Model model,MiaoshaUser user) {
// 直接拿User对象
model.addAttribute("user", user);
// 查询商品列表
List<GoodsVo> goodsList = goodsService.listGoodsVo();
// 添加
model.addAttribute("goodsList", goodsList);
// 返回
return "goodsList";
}
以此类推,可以做很多有用的代码优化。
如果您对本文有任何疑问或需要帮助,请在评论区留言,我会尽力解答。如果本文对您有帮助,请给个赞以示支持,非常感谢!💗
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。