自定义注解+HandlerInterceptor拦截 实现 防止表单重复提交

开发环境:SpringBoot + JDK8
1. 自定义 @NoRepeatForm 注解
/**
 * 说明:
 * 1.RetentionPolicy.RUNTIME 运行时生效
 * 2.ElementType.METHOD 作用在方法级别
 * 3.请求未完成时,默认2秒内不可重复提交
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface NoRepeatForm {

    long timeout() default 2000;    //超时时间
}
2. 实现HandlerInterceptor,自定义拦截器
@Component  //注入Spring进行管理
public class FormInterceptor implements HandlerInterceptor {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private static final Logger LOGGER = LoggerFactory.getLogger(FormInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        Method method = ((HandlerMethod) handler).getMethod();
        NoRepeatForm noRepeatForm = method.getAnnotation(NoRepeatForm.class);
        if (noRepeatForm == null) { //如果该方法未标记注解,不作任何处理
            return true;
        }
        String key=getKey(request,method);  //获取唯一Key
        Object obj = stringRedisTemplate.opsForValue().get(key);
        if (obj != null) {  //如果不是第一次提交,返回“请勿重复提交”提示
            response.setContentType("application/json;charset=utf-8");
            try {
                response.getWriter().write(JSON.toJSONString(InvokeResult.fail("请勿重复提交")));
            } catch (IOException e) {
                e.printStackTrace();
            }
            return false;
        }
        long timeout = noRepeatForm.timeout();
        if (timeout < 0) {	//如果自定义超时时间设置有误,设置为默认值
            timeout = 2000;
        }
        //表单第一次提交过,存入Key
        LOGGER.info("存入key:"+key);
        stringRedisTemplate.opsForValue().set(key, String.valueOf(IDTool.getId()), timeout, TimeUnit.MILLISECONDS);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        if (!(handler instanceof HandlerMethod)) {
            return;
        }
        Method method = ((HandlerMethod) handler).getMethod();
        NoRepeatForm noRepeatForm = method.getAnnotation(NoRepeatForm.class);
        if (noRepeatForm == null) {
            return;
        }
        //请求完成,删除Key
        method = ((HandlerMethod) handler).getMethod();
        String key=getKey(request,method);
        stringRedisTemplate.delete(key);
        LOGGER.info("删除key:"+key);
    }

    /**
     * 根据请求地址和方法获取唯一Key
     * @param request 获取IP
     * @param method 定位 className -> methodName
     * @return key
     */
    private String getKey(HttpServletRequest request, Method method){
        String ip = IPUtils.getIpAddr(request);
        String ipKey = String.format("%s#%s", method.getDeclaringClass().getName(), method.getName());
        String key=String.format("%s_%d", ip, Math.abs(ipKey.hashCode()));
        LOGGER.info("key:"+key);
        return key ;
    }
}
3. 在自定义WebMvcConfig配置中,添加拦截器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private FormInterceptor formInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(formInterceptor);
    }
	//    @Bean
	//    FormInterceptor formInterceptor(){
	//        return new FormInterceptor();
	//    }
}
4. 遇到的问题以及解决办法
问题:在进行拦截处理时,获取的stringRedisTemplate对象为null,导致存入数据时异常
原因:自定义拦截器没有注入成功
解决方式:1)使用@Bean注解;2)使用@Component注解
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值