前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >参数解析-HandlerMethodArgumentResolver

参数解析-HandlerMethodArgumentResolver

原创
作者头像
Blue_007
修改2023-11-03 21:25:33
2330
修改2023-11-03 21:25:33
举报
文章被收录于专栏:代码生涯代码生涯

🎊 一、背景

今天在做项目时遇到了一个有关参数解析 HandlerMethodArgumentResolver 的使用疑惑。因此去 百度学习了一下,现在记录一下。

🎉 二、参数解析器

想要自定义参数解析器,就要实现HandlerMethodArgumentResolver接口,而它是springMvc下的一个接口,引入spring-web的starter就可见了。

接口内容:

代码语言:java
复制
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;

}

可以看到这个接口有两个方法,分别为supportsParameterresolveArgument

supportsParameter()

它很好理解,返回值是boolean类型,它的作用是判断Controller层中的参数,是否满足条件,满足条件则执行resolveArgument方法,不满足则跳过。

resolveArgument()

它只有在supportsParameter方法返回true的情况下才会被调用。用于处理一些业务,将返回值赋值给Controller层中的对应的参数。

🎃 三、实战

未使用参数解析器时的Controller控制器:

代码语言:java
复制
/**
 * @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()方法有两个参数分别为 cookieTokenparamToken ,再仔细看一下方法体,不难看出,这两个参数和方法体中的代码就是为了,通过cookie或request其中的token这一变量来查询用户user的信息。

但是大家发没发现,这一个方法,就为了简简单单的这一个小功能,就写了这么多代码,是不是有点过分臃肿呢?而且假如还有其他方法会用到用户user这一信息变量呢,难道也写这么多的代码吗?

好的,这个时候我们就可以使用 HandlerMethodArgumentResolver 接口来进行一下小小的优化。


使用 HandlerMethodArgumentResolver 解析器后:

写一个类实现 HandlerMethodArgumentResolver 接口:

代码语言:java
复制
// 自定义参数解析器
@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;
	}
}

把我们编写的这个类,注册到配置文件中去:

代码语言:java
复制
@Configuration
@RequiredArgsConstructor
public class WebConfig extends WebMvcConfigurerAdapter{

    // 构造注入
	private final UserArgumentResolver userArgumentResolver;

	@Override
	public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        // 注册自定义参数解析器
		argumentResolvers.add(userArgumentResolver);
	}

}

最后,我们的控制类就可以这样写了

代码语言:java
复制
@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 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 🎊 一、背景
  • 🎉 二、参数解析器
  • 🎃 三、实战
  • 🎨 四、最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档