在 spring boot 中捕获幂等校验异常,核心做法是定义一个自定义的 idempotentexception 类,并在全局异常处理器 @restcontrolleradvice 中使用 @exceptionhandler 注解拦截该异常。当业务逻辑检测到重复请求时抛出此异常,spring mvc 会自动将其转换为统一的 json 响应(如 http 409 conflict),从而避免重复处理。

如何定义幂等校验异常的基类
首先需要创建一个继承自 RuntimeException 的自定义异常类,用于携带错误码和提示信息。这个类不需要复杂的逻辑,只需提供构造函数即可,它是整个异常处理机制的信号源。
package com.example.exception;
public class IdempotentException extends RuntimeException {
private final String errorCode;
public IdempotentException(String message, String errorCode) {
super(message);
this.errorCode = errorCode;
}
public String getErrorCode() {
return errorCode;
}
}
定义好异常后,在业务层(Service)或拦截器中,当发现请求参数中的唯一标识(如 Token 或 Request ID)已存在时,直接 throw new IdempotentException("重复提交", "IDEMPOTENT_ERROR");。这会将控制流中断并传递给上层处理器。
如何配置全局异常处理器返回统一格式
使用 @RestControllerAdvice 配合 @ExceptionHandler(IdempotentException.class) 来专门处理幂等异常。该方法应返回一个包含状态码、错误信息和时间戳的统一响应对象,确保前端能正确解析。
package com.example.config;
import com.example.exception.IdempotentException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(IdempotentException.class)
public ResponseEntity<map object>> handleIdempotentException(IdempotentException ex) {
Map<string object> body = new HashMap();
body.put("timestamp", LocalDateTime.now());
body.put("status", 409);
body.put("error", "Conflict");
body.put("message", ex.getMessage());
body.put("errorCode", ex.getErrorCode());
return ResponseEntity.status(409).body(body);
}
}</string></map>
当上述代码运行时,如果 Service 抛出了 IdempotentException,客户端将收到如下 JSON 结构:{"timestamp":"2023-10-27T10:00:00.000+08:00","status":409,"error":"Conflict","message":"重复提交","errorCode":"IDEMPOTENT_ERROR"}

如何在 Controller 层触发并验证该异常
为了验证上述机制,我们需要一个简单的 Controller 模拟幂等校验场景。这里假设通过 URL 参数传递 requestId,并使用一个简单的内存集合模拟数据库中的唯一性检查。
package com.example.controller;
import com.example.exception.IdempotentException;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashSet;
import java.util.Set;
@RestController
public class OrderController {
// 模拟存储已处理的 requestId
private static final Set<string> processedRequests = new HashSet();
@PostMapping("/order")
public String createOrder(@RequestParam String requestId) {
if (processedRequests.contains(requestId)) {
throw new IdempotentException("该请求已处理,请勿重复提交", "IDEMPOTENT_ERROR");
}
processedRequests.add(requestId);
return "订单创建成功:" + requestId;
}
}</string>
运行此程序后,第一次调用 POST /order?requestId=123 会返回 "订单创建成功:123"。第二次调用相同参数时,由于 processedRequests 中已存在该 ID,将抛出 IdempotentException,最终由全局处理器返回 409 状态码及错误信息。这种设计确保了无论底层业务多复杂,异常出口都是统一且可控的。












