java后端 防重复提交_后台防止表单重复提交

具体的做法:

1、获取用户填写用户名和密码的页面时向后台发送一次请求,这时后台会生成唯一的随机标识号,专业术语称为Token(令牌)。

2、将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端。

3、服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。

看具体的范例:

1.创建FormServlet,用于生成Token(令牌)和跳转到form.jsp页面

importjava.io.IOException;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;public class FormServlet extendsHttpServlet {private static final long serialVersionUID = -884689940866074733L;public voiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {

String token= UUID.randomUUID().toString() ;//创建令牌

System.out.println("在FormServlet中生成的token:"+token);

request.getSession().setAttribute("token", token); //在服务器使用session保存token(令牌)

request.getRequestDispatcher("/form.jsp").forward(request, response);//跳转到form.jsp页面

}public voiddoPost(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {

doGet(request, response);

}

}

2.在form.jsp中使用隐藏域来存储Token(令牌)

form表单

">

--%>

用户名:

3.DoFormServlet处理表单提交

importjava.io.IOException;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;public class DoFormServlet extendsHttpServlet {public voiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {boolean b = isRepeatSubmit(request);//判断用户是否是重复提交

if(b==true){

System.out.println("请不要重复提交");return;

}

request.getSession().removeAttribute("token");//移除session中的token

System.out.println("处理用户提交请求!!");

}/*** 判断客户端提交上来的令牌和服务器端生成的令牌是否一致

*@paramrequest

*@return* true 用户重复提交了表单

* false 用户没有重复提交表单*/

private booleanisRepeatSubmit(HttpServletRequest request) {

String client_token= request.getParameter("token");//1、如果用户提交的表单数据中没有token,则用户是重复提交了表单

if(client_token==null){return true;

}//取出存储在Session中的token

String server_token = (String) request.getSession().getAttribute("token");//2、如果当前用户的Session中不存在Token(令牌),则用户是重复提交了表单

if(server_token==null){return true;

}//3、存储在Session中的Token(令牌)与表单提交的Token(令牌)不同,则用户是重复提交了表单

if(!client_token.equals(server_token)){return true;

}return false;

}public voiddoPost(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {

doGet(request, response);

}

}

方案二:判断请求url和数据是否和上一次相同

推荐,非常简单,页面不需要任何传入,只需要在验证的controller方法上写上自定义注解即可

写好自定义注解

importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;/*** 一个用户 相同url 同时提交 相同数据 验证

*@authorAdministrator

**/@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)public @interfaceSameUrlData {

}

写好拦截器

importjava.lang.reflect.Method;importjava.util.HashMap;importjava.util.Map;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importorg.springframework.web.method.HandlerMethod;importorg.springframework.web.servlet.handler.HandlerInterceptorAdapter;importcom.thinkgem.jeesite.common.mapper.JsonMapper;/*** 一个用户 相同url 同时提交 相同数据 验证

* 主要通过 session中保存到的url 和 请求参数。如果和上次相同,则是重复提交表单

*@authorAdministrator

**/

public class SameUrlDataInterceptor extendsHandlerInterceptorAdapter{

@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throwsException {if (handler instanceofHandlerMethod) {

HandlerMethod handlerMethod=(HandlerMethod) handler;

Method method=handlerMethod.getMethod();

SameUrlData annotation= method.getAnnotation(SameUrlData.class);if (annotation != null) {if(repeatDataValidator(request))//如果重复相同数据

return false;else

return true;

}return true;

}else{return super.preHandle(request, response, handler);

}

}/*** 验证同一个url数据是否相同提交 ,相同返回true

*@paramhttpServletRequest

*@return

*/

public booleanrepeatDataValidator(HttpServletRequest httpServletRequest)

{

String params=JsonMapper.toJsonString(httpServletRequest.getParameterMap());

String url=httpServletRequest.getRequestURI();

Map map=new HashMap();

map.put(url, params);

String nowUrlParams=map.toString();//

Object preUrlParams=httpServletRequest.getSession().getAttribute("repeatData");if(preUrlParams==null)//如果上一个数据为null,表示还没有访问页面

{

httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);return false;

}else//否则,已经访问过页面

{if(preUrlParams.toString().equals(nowUrlParams))//如果上次url+数据和本次url+数据相同,则表示城府添加数据

{return true;

}else//如果上次 url+数据 和本次url加数据不同,则不是重复提交

{

httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);return false;

}

}

}

}

方案三:利用Spring AOP和redis的锁来实现防止表单重复提交

主要是利用了redis的分布式锁机制

1、注解:

importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;/*** 防止重复提交注解

*@authorzzp 2018.03.11

*@version1.0*/@Retention(RetentionPolicy.RUNTIME)//在运行时可以获取

@Target(value = {ElementType.METHOD, ElementType.TYPE})  //作用到类,方法,接口上等

public @interfacePreventRepetitionAnnotation {

}

2、AOP代码

importjava.lang.reflect.Method;importjava.util.UUID;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpSession;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.reflect.MethodSignature;importorg.com.rlid.utils.json.JsonBuilder;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.EnableAspectJAutoProxy;importorg.springframework.stereotype.Component;importdemo.zzp.app.aop.annotation.OperaterAnnotation;importdemo.zzp.app.redis.JedisUtils;/*** 防止重复提交操作AOP类

*@authorzzp 2018.03.10

*@version1.0*/@Aspect

@Component

@EnableAspectJAutoProxy(proxyTargetClass=true)public classPreventRepetitionAspect {

@AutowiredprivateJedisUtils jedisUtils;private static final String PARAM_TOKEN = "token";private static final String PARAM_TOKEN_FLAG =  "tokenFlag";/*** around

*@throwsThrowable*/@Around(value=  "@annotation(demo.zzp.app.aop.annotation.PreventRepetitionAnnotation)")public Object excute(ProceedingJoinPoint  joinPoint) throwsThrowable{try{

Object result= null;

Object[] args=joinPoint.getArgs();for(int i = 0;i < args.length;i++){if(args[i] != null && args[i]  instanceofHttpServletRequest){

HttpServletRequest request=  (HttpServletRequest) args[i];//被调用的方法需要加上HttpServletRequest request这个参数

HttpSession session =request.getSession();if(request.getMethod().equalsIgnoreCase("get")){//方法为get

result =generate(joinPoint, request, session,  PARAM_TOKEN_FLAG);

}else{//方法为post

result =validation(joinPoint, request, session,  PARAM_TOKEN_FLAG);

}

}

}returnresult;

}catch(Exception e) {

e.printStackTrace();return JsonBuilder.toJson(false, "操作失败!", "执行防止重复提交功能AOP失败,原因:" +e.getMessage());

}

}public Object generate(ProceedingJoinPoint  joinPoint, HttpServletRequest request, HttpSession  session,String tokenFlag) throwsThrowable {

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

request.setAttribute(PARAM_TOKEN, uuid);returnjoinPoint.proceed();

}public Object validation(ProceedingJoinPoint  joinPoint, HttpServletRequest request, HttpSession  session,String tokenFlag) throwsThrowable {

String requestFlag=request.getParameter(PARAM_TOKEN);//redis加锁

boolean lock =  jedisUtils.tryGetDistributedLock(tokenFlag +  requestFlag, requestFlag, 60000);if(lock){//加锁成功//执行方法

Object funcResult =joinPoint.proceed();//方法执行完之后进行解锁

jedisUtils.releaseDistributedLock(tokenFlag +requestFlag, requestFlag);returnfuncResult;

}else{//锁已存在

return JsonBuilder.toJson(false, "不能重复提交!",  null);

}

}

}

3、Controller代码

@RequestMapping(value = "/index",method =RequestMethod.GET)

@PreventRepetitionAnnotationpublic String toIndex(HttpServletRequest  request,Mapmap){return "form";

}

@RequestMapping(value= "/add",method =RequestMethod.POST)

@ResponseBody

@PreventRepetitionAnnotationpublicString add(HttpServletRequest request){try{

Thread.sleep(5000);

}catch(InterruptedException e) {

e.printStackTrace();

}return JsonBuilder.toJson(true, "保存成功!",null);

}

第一次点击提交表单,判断到当前的token还没有上锁,即给该token上锁。如果连续点击提交,则提示不能重复提交,当上锁的那次操作执行完,redis释放了锁之后才能继续提交。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值