优雅成功API接口开关-让你的运行掌控全局 (优雅成功的现代女性)
环境:SpringBoot2.7.12
1.概述
本文将引见如何为API接口灵活减少开关性能。经过这特性能,咱们可以控制API接口的反常访问或显示揭示消息。这有助于在开发和保养环节中更好地治理和控制API接口的行为。经过经常使用开关性能,咱们可以轻松地在不同状况下调整接口的行为,提高系统的灵敏性和可保养性。
为什么要给API接口减少开关性能呢?从以下几方面思考:
2.成功打算
首先,定义一个AOP切面(Aspect),该切面担任控制接口(Controller)的开关行为。
在切面中,咱们可以经常使用SpringAOP的切入点(Pointcut)来指定须要阻拦的方法。一旦方法被阻拦,咱们可以在切面的通知(Advice)中定义相应的自动行为。接上去咱们将一步一步的成功接口开关性能。
@Target({ElementType.TYPE,ElementType.METHOD})public@interfaceApiSwitch{/**接口对应的key,经过可以该key查问接口能否封锁*/Stringkey()default"";/**解析器beanName,经过详细的成功失掉key对应的值*/Stringresolver()default"";/**开启后升级方法名*/Stringfallback()default"";}
publicinterfaceSwitchResolver{booleanresolver(Stringkey);publicvoidconfig(Stringkey,Integeronoff);}
@ComponentpublicclassConcurrentMapResolverimplementsSwitchResolver{privateMap<String,Integer>keys=newConcurrentHashMap<>();@Overridepublicbooleanresolver(Stringkey){Integervalue=keys.get(key);returnvalue==null?false:(value==1);}publicvoidconfig(Stringkey,Integeronoff){keys.put(key,onoff);}}
@ComponentpublicclassRedisResolverimplementsSwitchResolver{privatefinalStringRedisTemplatestringRedisTemplate;publicRedisResolver(StringRedisTemplatestringRedisTemplate){this.stringRedisTemplate=stringRedisTemplate;}@Overridepublicbooleanresolver(Stringkey){Stringvalue=this.stringRedisTemplate.opsForValue().get(key);return!(value==null||"0".equals(value));}@Overridepublicvoidconfig(Stringkey,Integeronoff){this.stringRedisTemplate.opsForValue().set(key,String.valueOf(onoff));}}
这里就提供两种自动的成功。
@Component@AspectpublicclassApiSwitchAspectimplementslicationContextAware{privateApplicationContextcontext;privatefinalSwitchPropertiesswitchProperties;publicstaticfinalMap<String,Class<?extendsSwitchResolver>>MAPPINGS;static{//初始化一切的解析器Map<String,Class<?extendsSwitchResolver>>mappings=newHashMap<>();mappings.put("map",ConcurrentMapResolver.class);mappings.put("redis",RedisResolver.class);MAPPINGS=Collections.unmodifiableMap(mappings);}publicApiSwitchAspect(SwitchPropertiesswitchProperties){this.switchProperties=switchProperties;}@Pointcut("@annotation(apiSwitch)")privatevoidonoff(ApiSwitchapiSwitch){}@Around("onoff(apiSwitch)")publicObjectctl(ProceedingJoinPointpjp,ApiSwitchapiSwitch)throwsThrowable{//对应接口开关的keyStringkey=apiSwitch.key();//解析器bean的称号StringresolverName=apiSwitch.resolver();//升级方法名Stringfallback=apiSwitch.fallback();SwitchResolverresolver=null;//依据指定的beanName失掉详细的解析器;以下都不思考不存在的状况if(StringUtils.hasLength(resolverName)){resolver=this.context.getBean(resolverName,SwitchResolver.class);}else{resolver=this.context.getBean(MAPPINGS.get(this.switchProperties.getResolver()));}//解析器不存在则间接调用指标接口if(resolver==null||!resolver.resolver(key)){returnpjp.proceed();}//调用升级的方法;关于升级的方法便捷点,都必定在以后接口类中,同时还不思考方法参数的状况if(!StringUtils.hasLength(fallback)){//未性能的状况return"接口无法用";}Class<?>clazz=pjp.getSignature().getDeclaringType();MethodfallbackMethod=clazz.getDeclaredMethod(fallback);returnfallbackMethod.invoke(pjp.getTarget());}@OverridepublicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{this.context=applicationContext;}}
@GetMapping("/onoff/{state}")publicObjectonoff(Stringkey,@PathVariable("state")Integerstate){StringresolverType=switchProperties.getResolver();if(!StringUtils.hasLength(resolverType)){SwitchResolverbean=this.context.getBean(ApiSwitchAspect.MAPPINGS.get("map"));if(beaninstanceofConcurrentMapResolverresolver){resolver.config(key,state);}}else{SwitchResolverresolver=this.context.getBean(ApiSwitchAspect.MAPPINGS.get(resolverType));resolver.config(key,state);}return"success";}
经过该接口修正详细哪个接口的开关形态。(留意:这里有小疑问,假设接口上指定了resolver类型且性能文件中指定的类型不分歧,就会产生不失效疑问。这个疑问大家可以自行处置)
@GetMapping("/q1")@ApiSwitch(key="swtich$q1",fallback="q1_fallback",resolver="redisResolver")publicObjectq1(){return"q1";}publicObjectq1_fallback(){return"接口保养中";}
这是完整的性能示例,这里除了key必定外,其它的都可以不填写。
详细测试结果就不贴了,大家可以自行测试基于jvm内存和redis的方式。
总结:经过上述引见,咱们可以看到经常使用SpringAOP成功接口的开关性能是一种十分有效的方法。经过定义AOP切面和切入点,咱们可以准确地阻拦须要控制的方法,并在通知中依据开关形态口头相应的逻辑。这种技术手腕有助于提高代码的可保养性和可裁减性,同时提供更好的灵敏性和控制性来治理接口的行为
瞧瞧人家用SpringBoot写的后端API接口,那叫一个优雅
假设实现一个注册用户的功能,在controller 层,他会先进行校验参数,如下:
以上代码有什么问题嘛? 其实没什么问题,就是校验有点辣眼睛 。正常的添加用户业务还没写,参数校验就一大堆啦。假设后来,又接了一个需求:编辑用户信息。实现编辑用户信息前,也是先校验信息,如下:
我们可以使用注解的方式,来进行参数校验,这样代码更加简洁,也方便统一管理。实际上, spring boot 有个 validation 的组件,我们可以拿来即用。引入这个包即可:
引入包后,参数校验就非常简洁啦,如下:
然后在UserParam 参数对象中,加入 @Validated 注解哈,把错误信息接收到 BindingResult 对象,代码如下:
如果你在你们项目代码中,看到controller 层报文返回结果,有这样的:
也有这样的:
显然,如果接口返回结果不统一,前端处理就不方便,我们代码也不好维护。再比如有的人喜欢用Result 处理结果, 有点人 喜欢用 Response 处理结果,可以想象一下,这些代码有多乱。
所以作为后端开发,我们项目的响应结果,需要 统一标准的返回格式 。一般一个标准的响应报文对象,都有哪些属性呢?
响应状态码一般用枚举表示哈:
因为返回的数据类型不是确定的,我们可以使用泛型,如下:
有了统一的响应体,我们就可以优化一下controller 层的代码啦:
日常开发中,我们一般都是自定义统一的异常类,如下:
在controller 层,很可能会有类似代码:
这块代码,没什么问题哈,但是如果 太多,不是很优雅。
可以借助注解@RestControllerAdvice ,让代码更优雅。 @RestControllerAdvice 是一个应用于 Controller 层的切面注解,它一般配合 @ExceptionHandler 注解一起使用,作为项目的全局异常处理。我们来看下demo代码哈。
还是原来的UserController ,和一个会抛出异常的userService的方法,如下:
我们再定义一个全局异常处理器,用@RestControllerAdvice 注解,如下:
我们有想要拦截的异常类型,比如想拦截BizException 类型,就新增一个方法,使用 @ExceptionHandler 注解修饰,如下:
如何优雅的“编写”api接口文档
一些刚开始写接口文档的服务端同学,很容易按着代码的思路去编写接口文档,这让客户端同学或者是服务对接方技术人员经常吐槽,看不懂接口文档。这篇文章提供一个常规接口文档的编写方法,给大家参考。
推荐使用的是docway写接口文档,方便保存和共享,支持导出PDF MARKDOWN,支持团队项目管理。
一、请求参数
1. 请求方法
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。