java自定义注解,实现幂等
幂等:多次操作和一次操作是一样的结果,例如注册的时候,同一个手机号注册多次,但最终数据库只会保存一个手机号。
实现幂等,可能会有多种手段
1、数据库使用唯一索引;
2、使用java技术:① springAOP的方式;② springboot的拦截器实现;
那我们这里就使用拦截器技术实现。
这里需要使用到redis,前提是已经引入redis的依赖和配置,表示能正常使用
1、自定义注解对象创建;
2、对应拦截器进行业务判断,这里我们不用前端给我们的传递给我们的唯一标识符,因为具有依赖性,我们后台直接使用用户id+入参,再进行MD5加密存储生成的唯一性key的思路,最后配置拦截器,让其生效,然后生成的注解添加到对应注解上,通过对应新增的操作我们需要加上该注解,而且是会加上过期时间。也就是在这个期间范围内,是不允许多次重复发送这样的请求的。
具体代码如下:
1、创建注解类:
/** * 自定义幂等性判断注解 */ @Target(ElementType.METHOD) //作用于方法 @Retention(RetentionPolicy.RUNTIME) // 运行时生效 public @interface IdEmInterface { /** * 幂等性判断时间 * @return */ int time() default 60; // 默认60秒 /** * 单位 * @return */ TimeUnit timeUnit() default TimeUnit.SECONDS; //默认秒 }
2、具体业务实现
@Component public class IdEmInterceptor implements HandlerInterceptor { //实现拦截器接口 @Resource private ObjectMapper objectMapper; @Resource private RedisTemplate redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { IdEmInterface annotation = null; try { Method method = ((HandlerMethod) handler).getMethod(); annotation = method.getAnnotation(IdEmInterface.class); }catch (Exception e){} if (annotation != null) { String id = creatId(request); if (redisTemplate.opsForValue().get(id) != null){ response.getWriter().write("Please do not resubmit~"); return false; }else { redisTemplate.opsForValue().set(id, "true",annotation.time(), annotation.timeUnit()); //这里我们只是使用他的key,所以value不重要 return true; } } return HandlerInterceptor.super.preHandle(request, response, handler); } private String creatId(HttpServletRequest request) throws JsonProcessingException { Long uid = 0L; SecurityUserDetails securityUserDetails = SecurityUserInfoUtil.getSecurityUserDetails(); if (securityUserDetails != null){ uid = securityUserDetails.getUid(); } String requestParam = objectMapper.writeValueAsString(request.getParameterMap()); String id = SecureUtil.md5(uid + requestParam); //使用MD5加密 return id; } }
3、拦截器添加我们定义的拦截规则
@Configuration public class WebConfig implements WebMvcConfigurer { @Resource private IdEmInterceptor idEmInterceptor; @Override public void addInterceptors(org.springframework.web.servlet.config.annotation.InterceptorRegistry registry) { registry.addInterceptor(idEmInterceptor).addPathPatterns("/**"); } /** * 这里讲一下流程 * 1、先去自定义一个注解 * 2、对注解进行一个拦截规则设置 * 3、实现拦截器,拦截规则过滤 * */ }
4、在业务代码中添加注解
@RequestMapping("/add")
@IdEmInterface // 添加响应注解
public ResponseEntity add(@Validated Discuss discuss){
discuss.setUid(SecurityUserInfoUtil.getSecurityUserDetails().getUid());
boolean save = discussService.save(discuss);
if (save){
return ResponseEntity.success(save);
}
return ResponseEntity.error("请求失败!");
}
那么默认60秒内请求多次就会提示请勿重复请求,这样就能在一定程度上控制请求,防止同一个用户的同一个入参在某个时间内多次重复提交。
浙公网安备 33010602011771号