SpringBoot接口传递自定义参数,参数解析器

Hi I’m Shendi



SpringBoot接口传递自定义参数,参数解析器


简介

我的需求:编写了一个日志微服务,使用方式是 创建日志对象 - 日志流程 - 完成日志对象,这样的方式使用时就需要在每个接口都去创建和完成一下,多出了一点代码。

在 SpringBoot 中,我们接收接口的参数都是直接写在函数参数上,例如传递了一个name

@GetMapping("/test")
public String test(String name) {
    
    
	return name;
}

于是就想到能不能像上面这种方式将创建和完成封装起来,就开始寻找解决方案。

之前一直使用的是过滤器,但我的需求过滤器是没有办法实现的,过滤器可以给请求注入字符串,但不能注入对象

例如 User 类,想要的效果如下

@GetMapping("/test")
public String test(User user) {
    
    
	return user.toString();
}

后面学了下拦截器,发现拦截器也不行…


后面发现可以使用addArgumentResolvers来实现接口增加参数,自定义参数解析器



编写实现类

可以继承以下两个接口

  • WebArgumentResolver
  • HandlerMethodArgumentResolver

这两个接口都是用来处理控制器方法参数的接口。不同之处在于:

  1. HandlerMethodArgumentResolver是在Spring 3.1之后引入的,用于处理注解控制器方法参数。它是一个更加灵活、更加强大的解决方案,可以处理更多的操作,例如类型转换、注入依赖、权限验证等等。它可以用于处理@RequestParam、@PathVariable、@RequestBody、@RequestHeader等注解。
  2. WebArgumentResolver是在Spring 3.0和3.1版本中都有,但在3.1版本中已经被HandlerMethodArgumentResolver所取代。它主要用于处理旧版的控制器方法参数,例如Servlet API中的HttpServletRequest和HttpServletResponse对象。但是它缺乏HandlerMethodArgumentResolver的灵活性,不能处理更为复杂的场景。

对于新项目而言,应该优先使用HandlerMethodArgumentResolver,可以获得更加灵活、强大、可扩展的参数处理能力。


本文就使用 HandlerMethodArgumentResolver 来实现给所有接口注入参数


实现HandlerMethodArgumentResolver接口,需要实现两个函数

public class TestResolve implements HandlerMethodArgumentResolver {
    
    

	@Override
	public boolean supportsParameter(MethodParameter parameter) {
    
    
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
    
    
		// TODO Auto-generated method stub
		return null;
	}

}

supportsParameter方法用于判断参数是否符合特定的类型,符合则执行resolveArgument

而resolveArgument方法则用于将从请求中获取的参数值转换为特定的参数类型,从而将其作为参数传递给方法。(返回什么对象那么接口中使用的就是什么对象,所以需要先判断对象类型再做操作,类型不同则报错)


在配置类注册

编写一个类实现 WebMvcConfigurer,这个在使用拦截器时也是用这个配置

WebMvcConfigurer是一个Spring框架中的配置接口,用于配置Spring MVC的默认行为和定制化处理程序。它定义了多个方法,包括添加资源处理器、拦截器和视图控制器等。


import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import shendi.resolve.TestResolve;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    
	
	@Override
	public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
    
    
		resolvers.add(new TestResolve());
	}
	
}


测试使用

给Resolver类改一下,输出类型

public class TestResolve implements HandlerMethodArgumentResolver {
    
    

	@Override
	public boolean supportsParameter(MethodParameter parameter) {
    
    
		System.out.println("supportsParameter:" + parameter.getParameterType());
		return true;
	}

	@Override
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
    
    
		System.out.println(parameter.getParameterType());
		return null;
	}

}

可以看到 supportsParameter 返回 true,那么就会执行 resolveArgument

随便写个接口,函数接收两个参数(类型需要是当前项目的类,不然无效或者报错)

例如测试接口如下

public static class User {
    
    
    public String account;
    public String pwd;
    public String name;
}

@GetMapping("/")
    public String get(String test, User user) {
    
    
    System.out.println("接口执行");
    return "test";
}

函数有两个参数,一个String一个User,运行,请求接口,控制台输出如下

在这里插入图片描述


supportsParameter 返回值改为 false,测试结果如下

在这里插入图片描述

可以很明显的看到区别。



参数注入

根据上面的部分,已经实现了参数的注入了,只不过注入的是null

我们可以在 supportsParameter 判断是否是我们需要注入的类,是则返回 true,否则false

@Override
public boolean supportsParameter(MethodParameter parameter) {
    
    
    // 判断相等可以直接用equals或者==,不过isAssignableFrom是本地(native)函数,可以判断是否有继承关系
    return parameter.getParameterType().isAssignableFrom(User.class);
}

然后在 resolveArgument 创建实例返回

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
    NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
    
    

    // 如果当前有多个类支持的话,就需要用if判断是哪个类,没有则可直接创建对象返回
    if (parameter.getParameterType().isAssignableFrom(User.class)) {
    
    
        User user = new User();
        user.account = "shendi";
        return user;
    }

    return null;
}

这样,可以在接口直接使用 user 对象了

@GetMapping("/")
public String get(String test, User user) {
    
    
    System.out.println("接口执行: " + user.account);
    return "test";
}

在这里插入图片描述



配合过滤器实现我的需求

在这里再说下我的需求

我的需求:编写了一个日志微服务,使用方式是 创建日志对象 - 日志流程 - 完成日志对象,这样的方式使用时就需要在每个接口都去创建和完成一下,多出了一点代码。



根据上面那部分,已经可以给接口注入参数了,因为我的需求是日志使用,在过滤器中也需要使用,所以配合过滤器

我的理解,过滤器 - 接口,接口中解析参数时才用参数解析器,于是直接将对象放入请求的attribute,然后在解析器拿到返回就可以了

代码如下

@Override
protected void doFilter(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) throws IOException, ServletException {
    
    
    OLog olog = null;
    try {
    
    
        String id = ReqUtil.getUserIdStr(req);
        if (id == null) {
    
    
            olog = new OLog("接口", uri);
        } else {
    
    
            olog = new OLog("接口", uri, Integer.parseInt(id));
        }

        req.setAttribute("olog", olog);

        chain.doFilter(req, resp);

        olog.finish();
    } catch (Exception e) {
    
    
        e.printStackTrace();
        if (olog != null) olog.finish(OLog.RESULT_NOOK);
    }
}

public class ArgumentResolve implements HandlerMethodArgumentResolver {
    
    

	@Override
	public boolean supportsParameter(MethodParameter parameter) {
    
    
		return parameter.getParameterType().isAssignableFrom(OLog.class);
	}

	@Override
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
    
    
		
		// 如果当前有多个类支持的话,就需要判断是哪个类
		if (parameter.getParameterType().isAssignableFrom(OLog.class)) {
    
    
			return webRequest.getAttribute("olog", NativeWebRequest.SCOPE_REQUEST);
		}
		
		return null;
	}

}



END

猜你喜欢

转载自blog.csdn.net/qq_41806966/article/details/130324105
今日推荐