写点什么

什么是接口的幂等性,如何实现接口幂等性?,java 微服务架构视频下载

用户头像
极客good
关注
发布于: 刚刚

更新数据时首先和版本号作对比,如果不相等说明已经有其他的请求去更新数据了,提示更新失败。


update tablename set count=count+1,version=version+1 where version=#{version}


悲观锁 乐观锁可以实现的往往用悲观锁也能实现,在获取数据时进行加锁,当同时有多个重复请求时其他请求都无法进行操作


分布式锁 幂等的本质是分布式锁的问题,分布式锁正常可以通过 redis 或 zookeeper 实现;在分布式环境下,锁定全局唯一资源,使请求串行化,实际表现为互斥锁,防止重复,解决幂等。


token 机制 token 机制的核心思想是为每一次操作生成一个唯一性的凭证,也就是 token。一个 token 在操作的每一个阶段只有一次执行权,一旦执行成功则保存执行结果。对重复的请求,返回同一个结果。token 机制的应用十分广泛。


[](


)(三)token 机制的实现


================================================================================


这里展示通过 token 机制实现接口幂等性的案例:github 文末自取 首先引入需要的依赖:


<dependency>


<groupId>org.springframework.boot</groupId>


<artifactId>spring-boot-starter-data-redis</artifactId>


</dependency>


<dependency>


<groupId>org.apache.commons</groupId>


<artifactId>commons-lang3</artifactId>


<version>3.4</version>


</dependency>


<dependency>


<groupId>org.springframework.boot</groupId>


<artifactId>spring-boot-starter-web</artifactId>


</dependency>


[](


)3.1、配置请求的方法体和枚举类




首先配置一下通用的请求返回体


public class Response {


private int status;


private String msg;


private Object data;


//省略 get、set、toString、无参有参构造方法


}


以及返回 code


public enum ResponseCode {


// 通用模块 1xxxx


ILLEGAL_ARGUMENT(10000, "参数不合法"),


REPETITIVE_OPERATION(10001, "请勿重复操作"),


;


ResponseCode(Integer code, String msg) {


this.code = code;


this.msg = msg;


}


private Integer code;


private String msg;


public Integer getCode() {


return code;


}


public void setCode(Integer code) {


this.code = code;


}


public String getMsg() {


return msg;


}


public void setMsg(String msg) {


this.msg = msg;


}


}


[](


)3.2 自定义异常以及配置全局异常类




public class ServiceException extends RuntimeException{


private String code;


private String msg;


//省略 get、set、toString 以及构造方法


}


配置全局异常捕获器


@ControllerAdvice


public class MyControllerAdvice {


@ResponseBody


@ExceptionHandler(ServiceException.class)


public Response serviceExceptionHandler(ServiceException exception){


Response response=new Response(Integer.valueOf(exception.getCode()),exception.getMsg(),null);


return response;


}


}


[](


)3.3 编写创建 Token 和验证 Token 的接口以及实现类




@Service


public interface TokenService {


public Response createToken();


public Response checkToken(HttpServletRequest request);


}


具体实现类,核心的业务逻辑都写在注释中了


@Service


public class TokenServiceImpl implements TokenService {


@Autowired


private RedisTemplate redisTemplate;


@O


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


verride


public Response createToken() {


//生成 uuid 当作 token


String token = UUID.randomUUID().toString().replaceAll("-","");


//将生成的 token 存入 redis 中


redisTemplate.opsForValue().set(token,token);


//返回正确的结果信息


Response response=new Response(0,token.toString(),null);


return response;


}


@Override


public Response checkToken(HttpServletRequest request) {


//从请求头中获取 token


String token=request.getHeader("token");


if (StringUtils.isBlank(token)){


//如果请求头 token 为空就从参数中获取


token=request.getParameter("token");


//如果都为空抛出参数异常的错误


if (StringUtils.isBlank(token)){


throw new ServiceException(ResponseCode.ILLEGAL_ARGUMENT.getCode().toString(),ResponseCode.ILLEGAL_ARGUMENT.getMsg());


}


}


//如果 redis 中不包含该 token,说明 token 已经被删除了,抛出请求重复异常


if (!redisTemplate.hasKey(token)){


throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getCode().toString(),ResponseCode.REPETITIVE_OPERATION.getMsg());


}


//删除 token


Boolean del=redisTemplate.delete(token);


//如果删除不成功(已经被其他请求删除),抛出请求重复异常


if (!del){


throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getCode().toString(),ResponseCode.REPETITIVE_OPERATION.getMsg());


}


return new Response(0,"校验成功",null);


}


}


[](


)3.4 配置自定义注解




这是比较重要的一步,通过自定义注解在需要实现接口幂等性的方法上添加此注解,实现 token 验证


@Target({ElementType.METHOD})


@Retention(RetentionPolicy.RUNTIME)


public @interface ApiIdempotent {


}


接口拦截器


public class ApiIdempotentInterceptor implements HandlerInterceptor {


@Autowired


private TokenService tokenService;


@Override


public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {


if (!(handler instanceof HandlerMethod)) {


return true;


}


HandlerMethod handlerMethod= (HandlerMethod) handler;


Method method=handlerMethod.getMethod();


ApiIdempotent methodAnnotation=method.getAnnotation(ApiIdempotent.class);


if (methodAnnotation != null){

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
什么是接口的幂等性,如何实现接口幂等性?,java微服务架构视频下载