spring boot api接口开发(springboot聚合项目如何对外暴露api)
本文目录
- springboot聚合项目如何对外暴露api
- springboot框架开发的rest api工程,异步请求方法同步调用执行,怎么做
- 神器 SpringDoc 横空出世!最适合 SpringBoot 的API文档工具来了
- 瞧瞧人家用SpringBoot写的后端API接口,那叫一个优雅
- SpringBoot 规范接口开发流程
- springboot实现动态加载远程配置文件
- Spring Boot - 自动生成接口文档
- SpringBoot的RestApi接口的单元测试
springboot聚合项目如何对外暴露api
springboot如何暴露接口1.在对应的service层编写提供别人使用的方法service2.再指定的地方 提供对应的接口给别人使用(映射的url是在web层对应的url)提供接口3.在web层创建个文件夹编写调用接口的实现类 可以等同看作编写controller层(controller层是对前端暴露接口
springboot框架开发的rest api工程,异步请求方法同步调用执行,怎么做
1、controller本身就是单例的,非线程安全,多线程会共用对象2、controller不要涉及业务层,从其属性来看,控制层来连接请求触发服务3、根据需求,两种方法都可行,只要不在controller层处理业务;4、如果三个方法都是需要返回数据的,建议各自写各自的controller层,清晰明白;其实,如果三个方法业务性质一样,也可以封装起来,通过参数判断具体执行那部分代码
神器 SpringDoc 横空出世!最适合 SpringBoot 的API文档工具来了
之前在SpringBoot项目中一直使用的是SpringFox提供的Swagger库,上了下官网发现已经有接近两年没出新版本了!前几天升级了SpringBoot 2.6.x 版本,发现这个库的兼容性也越来越不好了,有的常用注解属性被废弃了居然都没提供替代!无意中发现了另一款Swagger库SpringDoc,试用了一下非常不错,推荐给大家! SpringDoc简介 SpringDoc是一款可以结合SpringBoot使用的API文档生成工具,基于OpenAPI 3,目前在Github上已有1.7K+Star,更新发版还是挺勤快的,是一款更好用的Swagger库!值得一提的是SpringDoc不仅支持Spring WebMvc项目,还可以支持Spring WebFlux项目,甚至Spring Rest和Spring Native项目,总之非常强大,下面是一张SpringDoc的架构图。 使用 接下来我们介绍下SpringDoc的使用,使用的是之前集成SpringFox的mall-tiny-swagger项目,我将把它改造成使用SpringDoc。 集成 首先我们得集成SpringDoc,在pom.xml中添加它的依赖即可,开箱即用,无需任何配置。 《!--springdoc 官方Starter--》org.springdocspringdoc-openapi-ui1.6.6 从SpringFox迁移 我们先来看下经常使用的Swagger注解,看看SpringFox的和SpringDoc的有啥区别,毕竟对比已学过的技术能该快掌握新技术; 接下来我们对之前Controller中使用的注解进行改造,对照上表即可,之前在@Api注解中被废弃了好久又没有替代的description属性终于被支持了! /** * 品牌管理Controller * Created by macro on 2019/4/19. */@Tag(name ="PmsBrandController", description ="商品品牌管理")@Controller@RequestMapping("/brand")publicclassPmsBrandController{@AutowiredprivatePmsBrandService brandService;privatestaticfinalLogger LOGGER = LoggerFactory.getLogger(PmsBrandController.class);@Operation(summary ="获取所有品牌列表",description ="需要登录后访问")@RequestMapping(value ="listAll", method = RequestMethod.GET)@ResponseBodypublicCommonResult》 getBrandList() {returnCommonResult.success(brandService.listAllBrand()); }@Operation(summary ="添加品牌")@RequestMapping(value ="/create", method = RequestMethod.POST)@ResponseBody@PreAuthorize("hasRole(’ADMIN’)")publicCommonResult createBrand(@RequestBodyPmsBrand pmsBrand) { CommonResult commonResult; int count = brandService.createBrand(pmsBrand);if(count ==1) { commonResult = CommonResult.success(pmsBrand); LOGGER.debug("createBrand success:{}", pmsBrand); }else{ commonResult = CommonResult.failed("操作失败"); LOGGER.debug("createBrand failed:{}", pmsBrand); }returncommonResult; }@Operation(summary ="更新指定id品牌信息")@RequestMapping(value ="/update/{id}", method = RequestMethod.POST)@ResponseBody@PreAuthorize("hasRole(’ADMIN’)")publicCommonResult updateBrand(@PathVariable("id")Longid,@RequestBodyPmsBrand pmsBrandDto, BindingResult result) { CommonResult commonResult; int count = brandService.updateBrand(id, pmsBrandDto);if(count ==1) { commonResult = CommonResult.success(pmsBrandDto); LOGGER.debug("updateBrand success:{}", pmsBrandDto); }else{ commonResult = CommonResult.failed("操作失败"); LOGGER.debug("updateBrand failed:{}", pmsBrandDto); }returncommonResult; }@Operation(summary ="删除指定id的品牌")@RequestMapping(value ="/delete/{id}", method = RequestMethod.GET)@ResponseBody@PreAuthorize("hasRole(’ADMIN’)")publicCommonResult deleteBrand(@PathVariable("id")Longid) { int count = brandService.deleteBrand(id);if(count ==1) { LOGGER.debug("deleteBrand success :id={}", id);returnCommonResult.success(null); }else{ LOGGER.debug("deleteBrand failed :id={}", id);returnCommonResult.failed("操作失败"); } }@Operation(summary ="分页查询品牌列表")@RequestMapping(value ="/list", method = RequestMethod.GET)@ResponseBody@PreAuthorize("hasRole(’ADMIN’)")publicCommonResult》 listBrand(@RequestParam(value ="pageNum", defaultValue ="1")@Parameter(description ="页码")Integer pageNum,@RequestParam(value ="pageSize", defaultValue ="3")@Parameter(description ="每页数量")Integer pageSize) { List brandList = brandService.listBrand(pageNum, pageSize);returnCommonResult.success(CommonPage.restPage(brandList)); }@Operation(summary ="获取指定id的品牌详情")@RequestMapping(value ="/{id}", method = RequestMethod.GET)@ResponseBody@PreAuthorize("hasRole(’ADMIN’)")publicCommonResult brand(@PathVariable("id")Longid) {returnCommonResult.success(brandService.getBrand(id)); }} 接下来进行SpringDoc的配置,使用OpenAPI来配置基础的文档信息,通过GroupedOpenApi配置分组的API文档,SpringDoc支持直接使用接口路径进行配置。 /** * SpringDoc API文档相关配置 * Created by macro on 2022/3/4. ***隐藏网址*** 结合SpringSecurity使用 由于我们的项目集成了SpringSecurity,需要通过JWT认证头进行访问,我们还需配置好SpringDoc的白名单路径,主要是Swagger的资源路径; /** * SpringSecurity的配置 * Created by macro on 2018/4/26. ***隐藏网址*** 然后在OpenAPI对象中通过addSecurityItem方法和SecurityScheme对象,启用基于JWT的认证功能。 /** * SpringDoc API文档相关配置 * Created by macro on 2022/3/4. ***隐藏网址*** 测试 ***隐藏网址*** 我们先通过登录接口进行登录,可以发现这个版本的Swagger返回结果是支持高亮显示的,版本明显比SpringFox来的新; 然后通过认证按钮输入获取到的认证头信息,注意这里不用加bearer前缀; 之后我们就可以愉快地访问需要登录认证的接口了; 看一眼请求参数的文档说明,还是熟悉的Swagger样式! 常用配置 SpringDoc还有一些常用的配置可以了解下,更多配置可以参考官方文档。 springdoc:swagger-ui:# 修改Swagger UI路径path:/swagger-ui.html# 开启Swagger UI界面enabled:trueapi-docs:# 修改api-docs路径path:/v3/api-docs# 开启api-docsenabled:true# 配置需要生成接口文档的扫描包packages-to-scan:com.macro.mall.tiny.controller# 配置需要生成接口文档的接口路径paths-to-match:/brand/**,/admin/** 总结 在SpringFox的Swagger库好久不出新版的情况下,迁移到SpringDoc确实是一个更好的选择。今天体验了一把SpringDoc,确实很好用,和之前熟悉的用法差不多,学习成本极低。而且SpringDoc能支持WebFlux之类的项目,功能也更加强大,使用SpringFox有点卡手的朋友可以迁移到它试试! 参考资料 ***隐藏网址*** ***隐藏网址*** 项目源码地址 ***隐藏网址*** ***隐藏网址***
瞧瞧人家用SpringBoot写的后端API接口,那叫一个优雅
假设实现一个注册用户的功能,在controller 层,他会先进行校验参数,如下:
以上代码有什么问题嘛? 其实没什么问题,就是校验有点辣眼睛 。正常的添加用户业务还没写,参数校验就一大堆啦。假设后来,又接了一个需求:用户信息。实现用户信息前,也是先校验信息,如下:
我们可以使用注解的方式,来进行参数校验,这样代码更加简洁,也方便统一管理。实际上, spring boot 有个 validation 的组件,我们可以拿来即用。引入这个包即可:
引入包后,参数校验就非常简洁啦,如下:
然后在 UserParam 参数对象中,加入 @Validated 注解哈,把错误信息接收到 BindingResult 对象,代码如下:
如果你在你们项目代码中,看到controller 层报文返回结果,有这样的:
也有这样的:
显然,如果接口返回结果不统一,前端处理就不方便,我们代码也不好维护。再比如有的人喜欢用 Result 处理结果, 有点人 喜欢用 Response 处理结果,可以想象一下,这些代码有多乱。
所以作为后端开发,我们项目的响应结果,需要 统一标准的返回格式 。一般一个标准的响应报文对象,都有哪些属性呢?
响应状态码一般用枚举表示哈:
因为返回的数据类型不是确定的,我们可以使用泛型,如下:
有了统一的响应体,我们就可以优化一下controller 层的代码啦:
日常开发中,我们一般都是自定义统一的异常类,如下:
在controller 层,很可能会有类似代码:
这块代码,没什么问题哈,但是如果 try...catch 太多,不是很优雅。
可以借助注解 @RestControllerAdvice ,让代码更优雅。 @RestControllerAdvice 是一个应用于 Controller 层的切面注解,它一般配合 @ExceptionHandler 注解一起使用,作为项目的全局异常处理。我们来看下demo代码哈。
还是原来的 UserController ,和一个会抛出异常的userService的方法,如下:
我们再定义一个全局异常处理器,用 @RestControllerAdvice 注解,如下:
我们有想要拦截的异常类型,比如想拦截 BizException 类型,就新增一个方法,使用 @ExceptionHandler 注解修饰,如下:
SpringBoot 规范接口开发流程
UserService
这种写法每次都要在controller层传入BindingResult,很不方便,接下来用自动抛出异常的方式去进一步优化
这时候后端已经引发了 MethodArgumentNotValidException 异常,并且前端收到的数据如下
后端直接将整个错误对象相关信息都响应给前端了,这是因为虽然引发了异常,但是我们没有去对其进行处理,所以走了SpringBoot默认的异常处理流程,现在开始进行全局异常处理
自定义异常的好处
还能在全局异常处理中处理Exception异常,这样无论遇到什么Exception都能够统一返回给前端,不过这种一般建议是在项目上线之前才这样做,开发的时候为了方便调试还是不太建议这样做
写一个新的api,返回的类型不再是ResultVo,而是直接返回实体类对象,这样就会走beforeBodyWrite方法去包装,然后真正返回给前端的还是ResultVO,这样做的目的就是可以省去我们自己手动封装数据到ResultVO的过程
效果
上面实体类中,id字段没有加上自定义注解,所以会走统一的VALIDATE_FAILED封装的响应体,而其他字段都加上了自定义注解,所以遇到字段校验出错时就会用自定义注解中的errcode和errmsg去封装返回
springboot实现动态加载远程配置文件
有个独立的API项目,该项目主要是对外部各个系统提供API接口,为了保证调用的安全,需要对请求进行校验,主要校验包括调用频率,访问IP,是否跨域和Token,其中IP和是否跨域的配置会根据接入方进行相应的修改,为了避免每次有新的接入方就得去修改一次配置文件并重启项目,所以打算使用动态配置的方式。 初级实现方案:API服务每隔5分钟向管理端请求一次数据,管理端添加IP和域白名单的管理,这个实现方案,简单好用,但是弊端也明显,管理端每次修改完配置后,客户端需要等待下次请求后才会加载对应的配置,同时,还需要自己管理获取到的配置文件 更新方案:在springboot启动时,先从远端获取配置文件,并将其加载进Environment对象中,其余的,就都交给Spring了。同时配合spring-cloud-context实现远程配置变更后,本地重新拉取配置并更新点进去之后,springboot会在这里初始化ConfigurableEnvironment对象 这里是给ConfigurableEnvironment做一些初始化工作,我们先不管了,重点在这里,listeners.environmentPrepared(environment);,Springboot通过事件,将Environment的加载分发出去 到此为止,我们就能像使用本地配置文件一样使用服务器上的配置文件了,但是这里还只实现了加载远程配置文件,我们还需要在远程配置文件变更时,实现配置文件的热更新
Spring Boot - 自动生成接口文档
在目前主流的前后端分离项目中,桥接前后端的就是接口,因此,一份简洁易懂的接口文档就显得非常重要了。幸运的是,我们不必手动去编写这些接口文档,市面上已有许多成熟的第三方库可以自动为项目生成接口文档,在 Spring Boot 中,最常使用的接口文档自动生成库就是 Swagger。
本篇博文主要介绍在 Spring Boot 中集成 Swagger 3 的方法。
更多详细信息,请参考官网: Specification
简单来说, OpenAPI 就是定义描述 REST API 的规范,而 Swagger 就是对 OpenAPI 规范的实现。
在 Spring Boot 中集成 Swagger 3,步骤如下:
可以看到,Swagger 3 的使用还是非常简单的。
如果需要更细致的自定义配置,我们可以自定义一个配置类,然后注入一个 Docket 数据实例,自定义配置 Swagger。
以下列举几种常见的配置示例:
Swagger 更多配置选项,请参考官方文档: springfox
Swagger 在使用过程中,有一些事项可以注意一下,避免出现问题。比如:
SpringBoot的RestApi接口的单元测试
记录一下SpringBoot的RestApi接口的单元测试
1.使用的junit单元测试框架,所以需要加入依赖。
2.如果是jar项目,就在单元测试的类上标注下面两个注解。
3.如果是web项目,则还需要添加下面这个注解。
4.因为测试的是rest接口,所以,需要引入下面的请求发送工具(其他的也可以)。
5.因为是针对本项目,所以通常还会添加一个属性,和一个方法。
6.这样的话,当需要编写单元测试的时候,只要直接继承该类即可。
本文相关文章:
spring boot api接口开发(SpringBoot的RestApi接口的单元测试)
2024年7月3日 21:16
spring boot api接口开发(springboot框架开发的rest api工程,异步请求方法同步调用执行,怎么做)
2024年6月27日 10:18
更多文章:
芭乐app下载网址进入18在线观看站长统计(有哪些的实用网站推荐)
2023年11月14日 08:40
dreamweaver cs3(dreamweaver cs3的设计和拆分按钮是灰色的,这是什么情况)
2024年7月21日 16:14
实况世界足球胜利十一人2022什么时候发布?胜利十一人的介绍
2024年6月4日 21:32
iso系统下载?哪里可以找到windows ISO镜像来下载
2024年5月17日 23:47