SpringMVC拦截所有Controller请求,实现自定义参数
1.自定义参数分解器
重写addArgumentResolvers方法生产参数分解器
需要实现HandlerMethodArgumentResolver接口,
supportsParameter方法返回的是当前方法实例
resolveArgument方法返回时对象类型
上代码:
// An highlighted block
@Service
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
@Autowired
private MiaoShaUserService userService;
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
Class<?> clazz = methodParameter.getParameterType() ;
return clazz == MiaoshaUser.class ;
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest webRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
/**
* threadlocal 线程安全
*/
return UserContext.getUser();
}
}
2.重写拦截器方法
需要继承HandlerInterceptorAdapter
需要注意的是三个方法: preHandle postHandle afterCompletion
perHandle:执行controller方法之前调用,通常做登录之前的处理,共同方法,可以获取方法的注解response,request之类
postHandle:执行controller后,返回modelAndView方法,但未进行页面渲染的时候调用。
afterCompletion:服务器端已经执行完毕,页面渲染完毕后执行
上代码:
// An highlighted block
@Service
public class AccessInterceptor extends HandlerInterceptorAdapter{
private static Logger logger = LoggerFactory.getLogger(AccessInterceptor.class);
@Autowired
MiaoShaUserService userService;
@Autowired
RedisService redisService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
/**
* 获取调用 获取主要方法
*/
if(handler instanceof HandlerMethod) {
logger.info("打印拦截方法handler :{} ",handler);
HandlerMethod hm = (HandlerMethod)handler;
MiaoshaUser user = getUser(request, response);
UserContext.setUser(user);
AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
if(accessLimit == null) {
return true;
}
int seconds = accessLimit.seconds();
int maxCount = accessLimit.maxCount();
boolean needLogin = accessLimit.needLogin();
String key = request.getRequestURI();
if(needLogin) {
if(user == null) {
render(response, SESSION_ERROR);
return false;
}
key += "_" + user.getNickname();
}else {
}
AccessKey ak = AccessKey.withExpire(seconds);
Integer count = redisService.get(ak, key, Integer.class);
if(count == null) {
redisService.set(ak, key, 1);
}else if(count < maxCount) {
redisService.incr(ak, key);
}else {
render(response, ACCESS_LIMIT_REACHED);
return false;
}
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
super.afterCompletion(request, response, handler, ex);
UserContext.removeUser();
}
private void render(HttpServletResponse response, ResultStatus cm)throws Exception {
response.setContentType("application/json;charset=UTF-8");
OutputStream out = response.getOutputStream();
String str = JSON.toJSONString(ResultObject.error(cm));
out.write(str.getBytes("UTF-8"));
out.flush();
out.close();
}
private MiaoshaUser getUser(HttpServletRequest request, HttpServletResponse response) {
String paramToken = request.getParameter(MiaoShaUserService.COOKIE_NAME_TOKEN);
String cookieToken = getCookieValue(request, MiaoShaUserService.COOKIE_NAME_TOKEN);
if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {
return null;
}
String token = StringUtils.isEmpty(paramToken)?cookieToken:paramToken;
return userService.getByToken(response, token);
}
private String getCookieValue(HttpServletRequest request, String cookiName) {
Cookie[] cookies = request.getCookies();
if(cookies == null || cookies.length <= 0){
return null;
}
for(Cookie cookie : cookies) {
if(cookie.getName().equals(cookiName)) {
return cookie.getValue();
}
}
return null;
}
2.实现WebMvcConfigurer
需要实现两个方法
addinterceptors:添加拦截器方法
addArgumentResolvers:添加参数解调器
上代码:
// An highlighted block
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
UserArgumentResolver resolver;
@Autowired
private AccessInterceptor interceptor;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(resolver);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor);
}
然后就可以在controllor方法里写参数调用,例如这样:
// An highlighted block
@AccessLimit(seconds = 5, maxCount = 5, needLogin = true)
@RequestMapping(value="/{path}/do_miaosha", method= RequestMethod.POST)
@ResponseBody
public ResultObject<Integer> miaosha(Model model, MiaoshaUser user, @PathVariable("path") String path,
@RequestParam("goodsId") long goodsId) {
miaoshaUser就是通过参数解调器实现的。
以上