SpringBoot实现自定义控制器参数注解

Eave 2020.08.16 22:07

有这样一个场景,在某个控制器中的参数中,需要从Request的Header中取到Authorization请求头,其中Authorization是Jwt的身份Token,我们需要取到Token中的uid字段,以用来判断当前的用户身份,在没有使用任何的权限身份管理框架的前提下,那么我们只能在Controller层进行一步步的调取,如果是有多个控制器的话,这样会增加很多的冗余代码,于是我们可以考虑使用自定义注解来实现类似于SpringBoot的参数注入。


一、自定义注解

package com.qianyan.annotation;

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)
public @interface JsonBody
{
    String name() default "";
}

二、实现HandlerMethodArgumentResolver解析器接口

SpringBoot中已经为我们提供了相关的处理解析器HandlerMethodArgumentResolver,我们只需要实现接口完成业务逻辑处理即可。

package com.qianyan.resolver;

import java.io.BufferedReader;
import java.io.InputStreamReader;

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;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.qianyan.annotation.JsonBody;
import com.qianyan.util.Common;

/**
 * 获取POST请求的JSON数据
 * @author 路遥
 */
public class JsonBodyResolver implements HandlerMethodArgumentResolver
{
    @Override
    public boolean supportsParameter(MethodParameter parameter)
    {
        return parameter.hasParameterAnnotation(JsonBody.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception
    {
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        String body = getBody(request);
        if(Common.isEmpty(body))
        {
            throw new Exception("Body数据为空");
        }

        JSONObject object = JSON.parseObject(body);
        if(object == null)
        {
            throw new Exception("Json格式错误");
        }

        JsonBody josnBody = parameter.getMethodAnnotation(JsonBody.class);
        // 参数类型
        Class clazz = parameter.getParameterType();
        // 参数名称
        String name = Common.isEmpty(josnBody.name()) ? parameter.getParameterName() : josnBody.name();
        if(clazz == JSONArray.class)
        {
            return object.getJSONArray(name);
        }
        return object.getJSONObject(name);
    }

    private String getBody(HttpServletRequest request) throws Exception
    {
        StringBuffer buffer = new StringBuffer("");
        InputStreamReader input = new InputStreamReader(request.getInputStream(), "utf-8");
        BufferedReader reader = new BufferedReader(input);

        String temp = null;
        while((temp = reader.readLine()) != null)
        {
            buffer.append(temp);
        }
        reader.close();

        return buffer.toString();
    }
}

supportsParameter接口是用于判断是否需要对该参数进行解析,如果该接口的返回值为true,则会继续执行;

resolveArgument接口是处理参数的分解,只有supportsParametertrue时才会调用此方法;


三、将Resolver注入到SpringMVC的ArgumentResolvers中

package com.qianyan.configurer;

import java.util.List;

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

import com.qianyan.resolver.JsonBodyResolver;

/**
 * WebMvc配置类
 * @author 路遥
 */
@Configuration
public class WebConfigurer implements WebMvcConfigurer
{
    /**
     * 添加控制器参数注入注解
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers)
    {
        resolvers.add(new JsonBodyResolver());
    }
}