写点什么

什么是接口的幂等性,如何实现接口幂等性?,mongodb 实战第二版下载

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

@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;


@Override


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){


// 校验通过放行,校验不通过全局异常捕获后输出返回结果


tokenService.checkToken(request);


}


return true;


}


@Override


public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {


}


@Override


public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {


}


}


3.5 配置拦截器以及 redis




配置 webConfig,添加拦截器


@Configuration


public class WebConfig implements WebMvcConfigurer {


@Override


public void addInterceptors(InterceptorRegistry registry) {


registry.addInterceptor(apiIdempotentInterceptor());


}


@Bean


public ApiIdempotentInterceptor apiIdempotentInterceptor() {


return new ApiIdempotentInterceptor();


}


}


配置 redis,使得中文可以正常传输


@Configuration


public class RedisConfig {


//自定义的 redistemplate


@Bean(name = "redisTemplate")


public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){


//创建一个 RedisTemplate 对象,为了方便返回 key 为 string,value 为 Object


RedisTemplate<String,Object> template = new RedisTemplate<>();


template.setConnectionFactory(factory);


//设置 json 序列化配置


Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=new


Jackson2JsonRedisSerializer(Object.class);


ObjectMapper objectMapper=new ObjectMapper();


objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);


objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance);


//string 的序列化


StringRedisSerializer stringRedisSerializer=new StringRedisSerializer();


//key 采用 string 的序列化方式


template.setKeySerializer(stringRedisSerializer);


//value 采用 jackson 的序列化方式


template.setValueSerializer(jackson2JsonRedisSerializer);


//hashkey 采用 string 的序列化方式


template.setHashKeySerializer(stringRedisSerializer);


//hashvalue 采用 jackson 的序列化方式


template.setHashValueSerializer(jackson2JsonRedisSerializer);


template.afterPropertiesSet();


return template;


}


}


最后是 controller


@RestController


@RequestMapping("/token")


public class TokenController {


@Autowired


private TokenService tokenService;


@GetMapping


public Response token(){


return tokenService.createToken();


}


@PostMapping("checktoken")


public Response checktoken(HttpServletRequest request){


return tokenService.checkToken(request);


}


}

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
什么是接口的幂等性,如何实现接口幂等性?,mongodb实战第二版下载