java实现防止重复提交

2025-03-26ASPCMS社区 - fjmyhfvclm
概念

防止重复提交是一种常见的安全措施,用于防止用户在短时间内多次提交相同的请求。通过使用注解,我们可以在代码层面实现这种防护机制,以提高系统的安全性和稳定性。

场景

防止重复提交的机制在许多Web应用程序中都是必需的,特别是在涉及到敏感操作或需要保证数据一致性的情况下。以下是一些常见的场景:

  1. 提交表单:防止用户多次提交表单,避免重复插入或修改数据。
  2. 支付请求:防止用户多次点击支付按钮,避免重复扣款。
  3. 并发操作:防止多个线程同时执行相同的操作,避免数据冲突。
其他方式

除了使用注解,还有其他一些方式可以实现防止重复提交的机制,例如:

  1. Token验证:在每个请求中生成一个唯一的令牌,并将其存储在会话或隐藏表单字段中。服务器在处理请求时验证令牌的唯一性,如果重复提交相同的令牌,则拒绝处理。
  2. 重定向:在处理请求后,将用户重定向到一个结果页面,而不是直接返回结果。这样,用户无法通过刷新页面或再次提交相同的请求。
  3. 前端验证:在前端使用JavaScript等技术验证用户输入,避免重复提交无效的请求。
步骤

下面是使用注解实现防止重复提交的一般步骤:

  1. 定义注解:创建一个自定义注解,用于标记需要进行重复提交检查的方法或接口。

  1. 实现拦截器或切面:创建一个拦截器或切面,用于在方法执行前进行重复提交检查。如下是实现一个拦截器

展开全文

/**

* 验证是否重复提交

* @param request

* @return

* @throws Exception

*/

️public ️abstract ️boolean ️isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation);

定义一个实现类,继承拦截器这个类,实现其方法具体的验证方法也在其中

类中的具体方法如下

️@Override

️public ️boolean ️isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation)

{

String nowParams = "";

️if (request ️instanceof RepeatedlyRequestWrapper)

{

RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;

nowParams = HttpHelper.getBodyString(repeatedlyRequest);

}

// body参数为空,获取Parameter的数据

️if (StringUtils.isEmpty(nowParams))

{

nowParams = JSONObject.toJSONString(request.getParameterMap());

}

Map<String, Object> nowDataMap = ️new HashMap<String, Object>();

nowDataMap.put(REPEAT_PARAMS, nowParams);

nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());

// 请求地址(作为存放cache的key值)

String url = request.getRequestURI();

// 唯一值(没有消息头则使用请求地址)

String submitKey = StringUtils.trimToEmpty(request.getHeader(header));

// 唯一标识(指定key + url + 消息头)

String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + url + submitKey;

Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);

️if (sessionObj != ️null)

{

Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;

️if (sessionMap.containsKey(url))

{

Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);

️if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval()))

{

️return ️true;

}

}

}

Map<String, Object> cacheMap = ️new HashMap<String, Object>();

cacheMap.put(url, nowDataMap);

redisCache.setCacheObject(cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS);

️return ️false;

}

其中compareParams是判断参数是否相同方法,compareTime判断两次间隔时间

  1. 使用注解:在需要进行重复提交检查的方法或接口上添加自定义注解。

️@RestController

️public ️class ️TestController {

️@RepeatSubmit

️@PostMapping("/test")

️public ️void ️test(@RequestBody User user) {

// 处理逻辑

}

}

在上述示例中,我们定义了一个AvoidDuplicateSubmit注解,并在UserController的createUser方法上使用了该注解。然后,我们通过AvoidDuplicateSubmitAspect切面类,在方法执行前进行重复提交检查。

总结

通过使用注解,我们可以在代码层面实现防止重复提交的机制。通过定义自定义注解、实现拦截器或切面以及在需要进行重复提交检查的方法上使用注解,我们可以有效地防止用户在短时间内多次提交相同的请求,提高系统的安全性和稳定性。

全部评论