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就是通過參數解調器實現的。
以上