spring boot使用自定义参数解析器
需求:在用户已经登录后请求别的接口时注入用户对象
1、自定义需要拦截的参数注解和用户实体对象
package io.xiongdi.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 登录用户注解
* @author wujiaxing
* @date 2019-06-30
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUser {
}
package io.xiongdi.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 用户实体类
* @author wujiaxing
*/
@Data
@Builder
@TableName("tb_user")
public class UserEntity implements Serializable {
private static final long serialVersionUID = 1315432620351507739L;
public UserEntity(){}
public UserEntity(long userId, String username, String mobile, String password, LocalDateTime createTime) {
this.userId = userId;
this.username = username;
this.mobile = mobile;
this.password = password;
this.createTime = createTime;
}
/**
* 用户ID
*/
@TableId
private long userId;
/**
* 用户名
*/
private String username;
/**
* 电话号码
*/
private String mobile;
/**
* 密码
*/
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String password;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime createTime;
}
2、自定义参数解析器类,实现 HandlerMethodArgumentResolver 接口,并实现其方法
package io.xiongdi.resolver;
import io.xiongdi.annotation.LoginUser;
import io.xiongdi.entity.UserEntity;
import io.xiongdi.interceptor.AuthorizationInterceptor;
import io.xiongdi.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
* 方法参数解析器接口,这个接口是SpringMVC参数解析绑定的核心接口。
* 不同的参数类型绑定都是通过实现这个接口来实现。
* 也可以通过实现这个接口来自定义参数解析器
* @author wujiaxing
* @date 2019-06-30
*/
@Component
public class LoginUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Autowired
private UserService userService;
/**
* 该解析器是否支持parameter参数的解析
* @param parameter 拦截到的参数
* @return 是否符合我们的拦截规则
* <p>
* isAssignableFrom方法作用是判断参数类型是否为UserEntity类或是父类或是父接口
* </p>
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().isAssignableFrom(UserEntity.class) && parameter.hasParameterAnnotation(LoginUser.class);
}
/**
* <p>
* 将方法参数从给定请求(webRequest)解析为参数值并返回
* 请求顺序:
* 1.进入拦截器,拦截有token请求头的用户,说明是验证过的
* 2.进入自定义参数解析器supportsParameter方法,解析带有LoginUser注解并且类UserEntity或父类的参数
* 3.进入自定义参数解析器resolveArgument方法,将存在作用域里的userid拿出来查询到user用户信息,赋给UserEntity参数
* </p>
* @param parameter
* @param mavContainer
* @param webRequest
* @param binderFactory
* @return
* @throws Exception
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
// 从请求作用域中获取userid
Object o = webRequest.getAttribute(AuthorizationInterceptor.USER_KEY, RequestAttributes.SCOPE_REQUEST);
if (o == null) {
return null;
}
UserEntity userEntity = userService.getById((long) o);
return userEntity;
}
}
3、将自定义的参数解析器添加到 spring boot
package io.xiongdi.config;
import io.xiongdi.interceptor.AuthorizationInterceptor;
import io.xiongdi.resolver.LoginUserHandlerMethodArgumentResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* @author wujiaxing
* <p>
* 此配置类可配置拦截器、参数解析器、返回值解析器、跨域支持等等
* </p>
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private AuthorizationInterceptor authorizationInterceptor;
@Autowired
private LoginUserHandlerMethodArgumentResolver loginUserHandlerMethodArgumentResolver;
/**
* 拦截器配置
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authorizationInterceptor).addPathPatterns("/api/**");
}
/**
* 跨域支持配置
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowCredentials(true).allowedOrigins("*").allowedMethods("GET", "PUT", "DELETE", "POST", "OPTIONS").maxAge(3600);
}
/**
* 参数解析配置
* @param resolvers
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(loginUserHandlerMethodArgumentResolver);
}
}
4、配置已经好了,可以写一个接口测试一下了
package io.xiongdi.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.xiongdi.annotation.Login;
import io.xiongdi.annotation.LoginUser;
import io.xiongdi.common.utils.R;
import io.xiongdi.entity.UserEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author wujiaxing
* @date 2019-07-07
*/
@Api(tags = "测试接口")
@RestController
@RequestMapping("/api")
public class ApiTestController {
// 测试用这个方法就行,下面两个方法是别的功能的,@Login 注解也是自定义的,测试时可以去掉09:11:38
@Login
@ApiOperation(value = "获取用户对象", response = UserEntity.class)
@GetMapping("userInfo")
public R userInfo(@LoginUser UserEntity userEntity) {
return R.ok().put("user", userEntity);
}
@Login
@ApiOperation("获取用户ID")
@GetMapping("userId")
public R userId(@RequestAttribute("userId") long userId) {
return R.ok().put("userId", userId);
}
@ApiOperation("忽略token测试")
@GetMapping("notToken")
public R notToken() {
return R.ok().put("msg", "无需token也能正常登录");
}
}
只要你不觉得尴尬,那尴尬的就是别人