TA的每日心情 | 开心 2021-12-13 21:45 |
---|
签到天数: 15 天 [LV.4]偶尔看看III
|
看到公司有个部门提出了这个问题,补个粗略的解决方案。。。
1.编写拦截器
- /**
- * Description: 防止重复提交
- *
- * @Author liam
- * @Create Date: 2018/3/9 9:22
- */
- public class AvoidReSubmitIntercepter extends HandlerInterceptorAdapter {
- private static final String SPLIT_FLAG = "_";
- private static final String AVOID_RE_SUBMIT_TOKEN_KEY = "identifier_token";
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
- if (checkAvoidReSubmitTokenOn(handler,AvoidReSubmitBehavior.Check)) {
- //验证是否重复
- if (checkIsRepeatSubmit(request)) {
- //重复提交
- return false;
- }
- }
- return super.preHandle(request, response, handler);
- }
- @Override
- public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
- if (checkAvoidReSubmitTokenOn(handler,AvoidReSubmitBehavior.Create)) {
- Random random = new Random();
- String uuid = UUID.randomUUID().toString().replace(SPLIT_FLAG, String.valueOf(random.nextInt(100000)));
- String tokenValue = String.valueOf(System.currentTimeMillis());
- String transferToken = uuid + SPLIT_FLAG + tokenValue;
- request.setAttribute(AVOID_RE_SUBMIT_TOKEN_KEY, transferToken);
- request.getSession(true).setAttribute(uuid, tokenValue);
- }
- super.postHandle(request, response, handler, modelAndView);
- }
- /**
- * Description: 是否开启防重规则
- *
- * @Author liam
- * @Create Date: 2018/3/9 10:33
- */
- private boolean checkAvoidReSubmitTokenOn(Object handler,AvoidReSubmitBehavior behavior) {
- HandlerMethod handlerMethod = (HandlerMethod) handler;
- Method invokeMethod = handlerMethod.getMethod();
- AvoidReSubmitToken avoidReSubmitToken = invokeMethod.getAnnotation(AvoidReSubmitToken.class);
- if (avoidReSubmitToken != null && avoidReSubmitToken.behavior().equals(behavior)) {
- return true;
- }
- return false;
- }
- private boolean checkIsRepeatSubmit(HttpServletRequest request) {
- String clientToken = request.getParameter(AVOID_RE_SUBMIT_TOKEN_KEY);
- if (StringUtils.isEmpty(clientToken)) {
- clientToken = request.getParameter(AVOID_RE_SUBMIT_TOKEN_KEY);
- if (StringUtils.isEmpty(clientToken)) {
- return true;
- }
- }
- String[] clientTokensDetail = StringUtils.split(clientToken, SPLIT_FLAG);
- if (clientTokensDetail.length == 2) {
- String uuid = clientTokensDetail[0];
- String token = clientTokensDetail[1];
- //此处存在并发风险...阔以加锁处理
- String serverToken = (String) request.getSession(true).getAttribute(uuid);
- if (StringUtils.isNotEmpty(serverToken) && token.equals(serverToken)) {
- request.getSession(true).removeAttribute(uuid);
- return false;
- }
- }
- return true;
- }
- }
复制代码
提供开启规则的注解:
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.METHOD)
- public @interface AvoidReSubmitToken {
- AvoidReSubmitBehavior behavior();
- }
复制代码
定义两种行为:
- public enum AvoidReSubmitBehavior {
- Create,
- Check;
- }
复制代码
拦截器的配置:
- <!-- 拦截器配置 -->
- <mvc:interceptors>
- <!-- 配置Token拦截器,防止用户重复提交数据 -->
- <mvc:interceptor>
- <mvc:mapping path="/**"/>
- <bean class="liam.AvoidReSubmitIntercepter"/>
- </mvc:interceptor>
- </mvc:interceptors>
复制代码
java代码使用;
- @AvoidReSubmitToken(behavior = AvoidReSubmitBehavior.Create)
- @RequestMapping("test")
- public String testPage() {
- return "form/page";
- }
- @AvoidReSubmitToken(behavior = AvoidReSubmitBehavior.Check)
- @RequestMapping("potHandler")
- public String postHandler(){
- return "ok";
- }
复制代码
页面代码:
- <form id="" class="form-horizontal" action="${ctx}/postHandler" method="post">
- ......
- <input type="hidden" name="token" value="${identifier_token}"/>
- <!-- 注:name必须是identifier_token -->
- ......
- </form>
复制代码
其实该方案也可以验证提交数据是否有效,当然通常是把token放到只读的缓存了。。
伪代码。。没测试呢。。。
|
|