前言
这几天开发一个项目,为了方便,前台将当前登陆人的ID和名称放在每个请求的Header中(这里不考虑安全性之类的),这样后台只要需要用到,就直接从Header中get出来就可以了。
后台实现方法
后台写了一个manage类,需要获取登陆人名称或ID的地方注入此类,然后执行里面的方法即可,manage类代码如下:
/**
* @author jiangkd
* @date 2022/4/12 10:17
*/
@Slf4j
@Component
public class HeaderManage {
@Resource
HttpServletRequest httpServletRequest;
/**
* 从header中获取当前登录人, name
*
* @return 登录人
*/
public String getUsername() {
//
final String username = httpServletRequest.getHeader(HeaderConsts.KEY_NAME);
try {
// 解码
return URLDecoder.decode(username, "UTF-8");
} catch (Exception e) {
// 解码异常了
log.error("从header中获取name并进行URL解码异常", e);
return null;
}
}
/**
* 从header中获取当前登录人的用户ID
*
* @return 用户ID
*/
public String getUid() {
//
return httpServletRequest.getHeader(HeaderConsts.KEY_UID);
}
}
实际使用这么的确是没有问题的,但是这几天突然发现,如果自定义一个注解,不就可以直接从Header中获取需要的参数值了,不用每次都要如注入一个HeaderManage类执行方法了,而是Controller的方法入口中,使用一个自定义注解标识的参数接收即可。
怎么实现呢 。。。
自定义注解方式
关于自定义注解的原理和说明,这里不做解释,不懂得伙伴百度一下吧,也不难。
首先我们创建一个注解类 HeaderValue,代码如下:
/**
* 自定义注解, 从Header中获取指定key的值
*
* @author jiangkd
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HeaderValue {
String value() default "";
}
我们这里只是实现我们一开始的需求,不做复杂的注解,所以这里只定义一个value()方法,默认值是“”。
下一步我们需要实现这个注解的请求解析处理,也就是实现一个HandlerMethodArgumentResolver类。
实现HandlerMethodArgumentResolver,代码如下:
/**
* 自定义注解HeaderValue解析器, 获取Header中指定key的值
*
* @author jiangkd
* @date 2022/11/1 9:49:48
*/
public class HeaderValueMethodArgumentResolver implements HandlerMethodArgumentResolver {
/**
* 判断Controller层方法中的参数, 是否满足条件, 满足条件则执行resolveArgument方法,不满足则跳过;
*
* @param parameter 要解析的方法参数对象,可以从对象获取参数的属性(如参数的类型,所修饰的注解等)
* @return 满足条件返回true;否则false
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
// 方法中的参数是否使用了注解@HeaderValue
return parameter.hasParameterAnnotation(HeaderValue.class);
}
/**
* 只有在supportsParameter方法返回true的情况下才会被调用, 用于处理一些业务, 将返回值赋值给Controller层中的这个参数
*
* @param parameter 要解析的方法参数对象,可以从对象获取参数的属性(如参数的类型,所修饰的注解等)
* @param mavContainer 当前请求的 ModelAndViewContainer 容器
* @param webRequest 当前的请求实体
* @param binderFactory 实例创建工厂
* @return 参数具体解析后封装的对象
* @throws Exception e
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
// 注解@HeaderValue
final HeaderValue parameterAnnotation = parameter.getParameterAnnotation(HeaderValue.class);
if (null != parameterAnnotation) {
// 获取注解中的值, 也就是获取value的值
String annotationValue = parameterAnnotation.value();
if (StrUtil.isEmpty(annotationValue)) {
// 不指定注解的value, 默认使用被标记的参数的名称
annotationValue = parameter.getParameterName();
}
// HttpServletRequest
final HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
// 从header中获取指定key的参数值
final String headerValue = request.getHeader(annotationValue);
// URL解码
return URLDecoder.decode(headerValue, "utf-8");
}
return null;
}
}
测试@HeaderValue
controller测试代码如下:
/**
* 测试注解@HeaderValue
*
* @author jiangkd
* @date 2022/11/1 9:53:42
*/
@RestController
@RequestMapping("/header/value")
public class HeaderValueController {
@GetMapping("/test")
public String test(@HeaderValue("uid") String uid, @HeaderValue() String name) {
//
return "uid:" + uid + ", name:" + name;
}
}
测试方法中,参数uid的注解中定义了value的值,name的没有定义,所以上面的解析器中key就使用参数的名称,也就是name。
发送请求测试。。。
从结果可以看出,controller中的uid和name成功的获取到了header中的对应的参数值。