springMVC拦截器处理订单重复提交

  SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理。比如通过它来进行权限验证,或者是来判断用户是否登陆,或者是像12306 那样子判断当前时间是否是购票时间。

  SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor 来实现的

1,定义一个用于防止重复提交使用的注解 PreventRecoverySubmit

/**
 * 用于防止重复提交使用的注解<br>
 * 暂时只用于APP无状态需要认证的请求下,简单说有TOKEN参数才能生效.
 * @author pgl
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PreventRecoverySubmit {


    /**
     * 设置重复提交的唯一标识,默认为按方法唯一
     * @return
     */
    @AliasFor("key")
    String value() default "";
    
    /**
     * 设置重复提交的唯一标识,默认为按方法唯一
     * @return
     */
    @AliasFor("value")
    String key() default "";
    
    /**
     * 限制多久才能请求一次, 默认为等上次请求成功后就可以立即请求<br>
     * 只能为0以上, 否则为默认效果
     * @return
     */
    int limit() default 0;
    
    /**
     * 配合(limit)限制多久所使用计数的单位,默认为分钟
     * @return
     */
    TimeUnit limitUnit() default TimeUnit.MINUTES;
    
    /**
     * 设置请求超时解除限制时间, 单位为分钟, 默认为1分钟<br>
     * 当请求超过这个时间就会自动解开提交限制<br>
     * 如果设置了限制多久请求一次(limit)配置 则该配置会失效
     * @return
     */
    int timeout() default 1;
}

2,springMVC.XML中配置拦截地址

 <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.XXX.security.core.PreventRecoverySubmitInterceptor">
                <property name="objectMapper" ref="apiObjectMapper"></property>
            </bean>
        </mvc:interceptor>
    </mvc:interceptors>


3,拦截地址写逻辑处理程序

public class PreventRecoverySubmitInterceptor implements HandlerInterceptor, InitializingBean {


    private static final String KEY_PREFIX = "PRS";


    @Autowired
    private CacheService cacheService;


    private ObjectMapper objectMapper;
    
    /**
     * 重写InitializingBean接口中的afterPropertiesSet方法
     * 实例化bean(初始化清空缓存)
     */
    public void afterPropertiesSet() throws Exception {
        cacheService.clearCache(KEY_PREFIX);
    }
    /**
     * 重写HandlerInterceptor接口中的preHandle方法
     * 方法执行之前调用(只限于@RequestMapping springMVC的请求)
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {


        String token = getToken(request);
        PreventRecoverySubmit recoverySubmit = getPreventRecoverySubmit(handler);//获取防重复提交注解对象
        if (recoverySubmit != null && StringUtil.isNotEmpty(token)) {//如果注解对象不为null,并且请求对象不为空
            String key = getKey(recoverySubmit, handler, token);//生成key
            String v = cacheService.get(key);
            if (v != null) {
                JSONUtil.writerHttpMsg(objectMapper, NotDataResult.Failed("您的操作太频繁, 请稍后重试!"), response);
                return false;
            }
            int timeout = recoverySubmit.timeout();
            TimeUnit timeUnit = TimeUnit.MINUTES;//时间单位
            if (recoverySubmit.limit() > 0) {//设置了限制多久才能请求一次
                timeout = recoverySubmit.limit();
                timeUnit = recoverySubmit.limitUnit();
            }
            cacheService.set(key, handler.toString(), timeout, timeUnit);//加入缓存
        }


        return true;
    }
    /**
     *  重写HandlerInterceptor接口中的postHandle方法
     *  方法执行完之后调用,如果方法异常则不会调用
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {


    }


    private String getToken(HttpServletRequest request) {
        String token = request.getHeader("token");
        if (token == null)
            token = request.getParameter("token");
        return token;
    }


    private PreventRecoverySubmit getPreventRecoverySubmit(Object handler) {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            return handlerMethod.getMethodAnnotation(PreventRecoverySubmit.class);
        }
        return null;
    }
    /**
     * 生成key
     * @param recoverySubmit
     * @param handler
     * @param token
     * @return
     */
    private String getKey(PreventRecoverySubmit recoverySubmit, Object handler, String token) {
        String key = recoverySubmit.value();
        if (StringUtil.isEmpty(key)) {
            key = MD5Util.getMD5Id(handler.toString());
        }
        return KEY_PREFIX + ":" + token + ":" + key;
    }
    /**
     * 重写HandlerInterceptor接口中的afterCompletion方法
     * 方法执行完之后调用,不管异常都会调用
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //判断是否设置的请求时间 否则清空缓存
        String token = getToken(request);
        PreventRecoverySubmit recoverySubmit = getPreventRecoverySubmit(handler);
        if (recoverySubmit != null && StringUtil.isNotEmpty(token)) {
            String key = getKey(recoverySubmit, handler, token);
            if (recoverySubmit.limit() < 1) {
                cacheService.del(key);
            }
        }
    }
    
    public void setObjectMapper(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }
}


4,需要防止重复提交的方法上添加注解

 @PreventRecoverySubmit
    @RequestMapping(value = "/applyOrder", method = RequestMethod.POST)
    public @ResponseBody  Boolean abc() {}















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值