前后端分离重复提交_java+react前后端分离项目处理重复提交问题

重复提交的问题在web开发中是很常碰到的一个问题,主要分为前端和后端两种途径解决,前端处理一般采用提交事件后,禁止用户再次点击提交按钮,等待服务端结果再重置提交按钮状态。

本文着重介绍,通过java后端处理重复提交问题。开发环境是:spring boot 2.0+react+ant+dva,下图是主要流程思路:

以下是详细步骤代码:

1:客户端登陆,服务端登陆成功后返回初始的表单令牌

packagecom.df.web.manager.security;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.util.UUID;/*** @类名称:

* @类描述:

* @创建人 刘丹

* @创建时间 2018/6/23

* @最后修改人 刘丹.

* @最后修改时间 2018/6/23.

* @版本:1.0*/

public classFormTokenUtil {public staticString refreshFormToken(HttpServletRequest request, HttpServletResponse response) {

String newFormToken=UUID.randomUUID().toString();

response.setHeader("formToken", newFormToken);

request.getSession(true).setAttribute("formToken", newFormToken);returnnewFormToken;

}

}

2:前端获取服务端返回的formToken

sessionStorage.setItem("formToken", resData.result.formToken);

3:在前端统一的request(fetch)的headers中增加表单token项

returnrequest(serviceUrl,

{

method:"POST",

headers: {‘Accept‘: ‘application/json‘,‘Content-Type‘: ‘application/json‘,‘formToken‘: sessionStorage.getItem("formToken")

},

body: data,

credentials:‘include‘});

4:服务端使用aop技术拦截指定注解的Controller请求

packagecom.df.web.manager.aop;importcom.df.web.manager.security.FormTokenUtil;importcom.empiresoft.annotation.FormToken;importcom.empiresoft.pojo.common.ActionResultGenerator;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.stereotype.Component;importorg.springframework.web.context.request.RequestContextHolder;importorg.springframework.web.context.request.ServletRequestAttributes;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;/*** @类名称: 表单重复提交拦截处理

* @类描述:

* @创建人 刘丹

* @创建时间 2018/6/23

* @最后修改人 刘丹.

* @最后修改时间 2018/6/23.

* @版本:1.0*/@Aspect

@Componentpublic classFormTokenAspect {private final Logger logger = LoggerFactory.getLogger(this.getClass());/*** 对formToken注解的Action执行重复提交验证

*

*@paramproceedingJoinPoint

*@paramformToken

*@return

*/@Around("@annotation(formToken)")publicObject execute(ProceedingJoinPoint proceedingJoinPoint, FormToken formToken) {try{

ServletRequestAttributes attributes=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

HttpServletRequest request=attributes.getRequest();

HttpServletResponse response=attributes.getResponse();

String strFormToken= request.getHeader("formToken");if (strFormToken == null) {return ActionResultGenerator.errorResult("表单Token不能为空!");

}

Object sessionFormToken= request.getSession(true).getAttribute("formToken");if (sessionFormToken == null || !sessionFormToken.toString().equals(strFormToken)) {return ActionResultGenerator.errorResult("请勿重复提交数据!");

}//放行

Object o =proceedingJoinPoint.proceed();//重置表单令牌 且写入response 重置前端 表单令牌

FormTokenUtil.refreshFormToken(request, response);returno;

}catch(Throwable e) {

logger.error(e.getMessage());return ActionResultGenerator.errorResult("发生异常!");

}

}

}

5:前端监控Response返回的数据中是否包含表单token项,如果包含则重置前端sessionStorage的表单token。

import fetch from ‘dva/fetch‘;import { message } from ‘antd‘;function parseJSON(response) {if (response.headers.get("formToken")) {

sessionStorage.setItem("formToken", response.headers.get("formToken"))

}returnresponse.json();

}

function checkStatus(response) {if (response.status >= 200 && response.status < 300) {returnresponse;

}

}/*** Requests a URL, returning a promise.

*

*@param{string} url The URL we want to request

*@param{object} [options] The options we want to pass to "fetch"

*@return{object} An object containing either "data" or "err"*/exportdefaultfunction request(url, options) {returnfetch(url, options)

.then(checkStatus)

.then(parseJSON)

.then(data=>({ data }))

.catch((err) =>{

});

}

注解定义:

packagecom.empiresoft.annotation;import java.lang.annotation.*;/*** @类名称:FormToken注解类

* @类描述:使用此注解 则表示需要验证FormToken, 用于处理表单重复提交

* @创建人 刘丹

* @创建时间 2018/6/23

* @最后修改人 刘丹.

* @最后修改时间 2018/6/23.

* @版本:1.0*/@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)public @interfaceFormToken {

}

标记需要重复提交验证

@FormToken

@RequestMapping(value= "/call_service", method =RequestMethod.POST)public ActionResult callServiceByPost(@RequestBody CallService callService) throwsException {returnOauthClientUtil.callUnifiedPlatformService(callService, SecurityUtil.getLoginUser(request), request);

}

注:如需允许用户不同的表单使用不同的表单token,只对同性质表单做重复提交验证,可在前后端对token名称"formToken"的命名做扩展处理。

原文:https://www.cnblogs.com/liudan996/p/9218034.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值