f(x)=f(f(x))
。幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。
在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样的,更复杂的操作幂等保证是利用唯一交易号(流水号)实现.
@Service
public class TokenServiceImpl implements TokenService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public String getToken() {
//获取全局唯一id
long nextId = SnowflakeUtil.nextId();
//存入redis,设置10分钟失效
stringRedisTemplate.opsForValue().set(String.valueOf(nextId), UUID.randomUUID().toString(),10, TimeUnit.MINUTES);
return String.valueOf(nextId);
}
/**
* 删除记录,true表示第一次提交,false重复提交
*/
@Override
public Boolean checkToken(String token) {
return stringRedisTemplate.delete(token);
}
}
/**
* @Description 幂等操作的注解
* @Author CJB
* @Date 2020/3/25 10:19
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeatLimiter {
}
/**
* @Description 获取请求头的信息,具体校验逻辑读者自己实现
* @Author CJB
* @Date 2020/3/25 11:09
*/
@Component
public class HeaderIntercept implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取token
String token = request.getHeader(HeaderConstant.TOKEN);
//校验逻辑
if (!validToken(token))
throw new TokenInvalidException("TOKEN失效");
//获取其他的参数.....
RequestHeader header = RequestHeader.builder()
.token(token)
.build();
//放入request中
request.setAttribute(HeaderConstant.HEADER_INFO,header);
return true;
}
/**
* 校验token,逻辑自己实现
* @param token
* @return
*/
private boolean validToken(String token){
return Boolean.TRUE;
}
}
@Component
public class RepeatIntercept implements HandlerInterceptor {
@Autowired
private TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod){
//获取方法上的参数
RepeatLimiter repeatLimiter = AnnotationUtils.findAnnotation(((HandlerMethod) handler).getMethod(), RepeatLimiter.class);
if (Objects.isNull(repeatLimiter)){
//获取controller类上注解
repeatLimiter=AnnotationUtils.findAnnotation(((HandlerMethod) handler).getBean().getClass(),RepeatLimiter.class);
}
//使用注解,需要拦截验证
if (Objects.nonNull(repeatLimiter)){
//获取全局token,表单提交的唯一id
RequestHeader info = RequestContextUtils.getHeaderInfo();
//没有携带token,抛异常,这里的异常需要全局捕获
if (StringUtils.isEmpty(info.getToken()))
throw new RepeatException();
//校验token
Boolean flag = tokenService.checkToken(info.getToken());
//删除失败,表示
if (Boolean.FALSE.equals(flag))
//抛出重复提交的异常
throw new RepeatException();
}
}
return true;
}
}
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
/**
* 下单
* @param order
* @return
*/
@PostMapping
@RepeatLimiter //幂等性保证
public CommenResult add(@RequestBody Order order){
orderService.save(order);
return new CommenResult("200","下单成功");
}
}
原文:https://www.cnblogs.com/Chenjiabing/p/12574042.html