SpringBoot(46) —— 配置扫描接口及开关swagger

    科技2022-08-12  119

    目录

    1.为什么要配置扫描接口2.swagger配置扫描的数据接口1.自定义扫描的接口2.配置是否启动swagger3.需求:根据环境自动开启/关闭swagger功能


    1.为什么要配置扫描接口

    上一篇博客配置的只是一些基本信息,在看swagger页面的时候,我们可以发现它一共有4个板块,这一篇用于配置接口信息 我们可以发现上图中接口信息已经有两个了 一个是basic-error-controller(基本错误控制器,这个controller是我们的springBoot项目自带的,我们每一个出现了4xx和5xx的错误的时候都是走的这个controller,所以swagger将它扫描了出来,这个我们可以不关心);一个是hello-controller(这个控制器就是我们自己在测试项目是否搭建成功的时候自己写的一个controller)@RestController public class HelloController { @RequestMapping("/hello") public String hello(){ return "Hello Swagger"; } } 我们可以点开看一下 可见hello-controller下拉菜单中有多个请求方式,这是因为我们的controller中方法的映射地址写的是@RequestMapping("/hello"),并没有指定使用哪一种请求方式去映射,所以swagger为我们把所有的请求方式都列了出来,如果我们使用@RequestMapping注解的变体,指定了这个方法对应的映射地址的请求方式,就不会有这么多的选项了@GetMapping @PostMapping @PutMapping @DeleteMapping @PatchMapping 所以接下来我们需要学习swagger怎么配置扫描的数据接口/API

    2.swagger配置扫描的数据接口

    在默认情况下,我们可以发现swagger把项目中的所有的数据接口都扫描出来了,但是我们并没有在controller的方法上自定义一些设置,这显然不是我们想要的,我们想要的是swagger扫描的是我们想让它扫描到的数据API,而不是它自己就把所有的数据接口都扫描了展示在swagger页面上

    1.自定义扫描的接口

    要实现自定义扫描,我们需要使用Docket类的select(),要了解这个方法的作用,看源码/** * Initiates a builder for api selection. * * @return api selection builder. To complete building the api selector, the build method of the api selector * needs to be called, this will automatically fall back to building the docket when the build method is called. */ public ApiSelectorBuilder select() { return new ApiSelectorBuilder(this); } 注释大意为:*启动api选择的生成器 *调用select()将返回一个api选择生成器。要完成api选择器的构建,需要调用api选择器的build方法, 它将自动返回帮助构建docket对象 所以我们还需要调用select().build(),我们可以查看build()的源码,从这个方法的返回值我们也可以发现,select()返回值为new ApiSelectorBuilder(),而ApiSelectorBuilder的构造为public class ApiSelectorBuilder { private final Docket parent; public ApiSelectorBuilder(Docket parent) { this.parent = parent; } } 可见,new ApiSelectorBuilder()其实就是返回了一个Docket对象我们可以好好看看ApiSelectorBuilder这个类的定义,这个类很简单 所以在调用build()之前,我们可以调用apis() / paths()来设置build()方法返回的Docket对象的参数,apis()需要传入Predicate< RequestHandler >对象,所以我们需要调用RequestHandlerSelectors.basePackage(“需要被扫描的API接口所在的包”)作为参数传入apis()中@Configuration @EnableSwagger2 //开启Swagger2 public class SwaggerConfig { @Bean public Docket docket(){ return new Docket(DocumentationType.SWAGGER_2) .apiInfo(this.apiInfo()) .select().apis(RequestHandlerSelectors.basePackage("com.thhh.swagger.controller")).build(); } private ApiInfo apiInfo(){ return new ApiInfo( "thhh的SwaggerAPI文档", //标题 "thhh学习Swagger", //描述 "v1.0", //版本 "www.termsOfServiceUrl.com", //服务条款URL new Contact("thhh", "www.thhh.com", "www.thhh@email.com") , //作者信息 "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", new ArrayList() ); } } 测试 原因就是我们在apis()方法中传入的RequestHandlerSelectors.basePackage()指明了swagger要扫描的数据API的包,所以除了这个包里面的数据接口,swagger将不会去扫描其他包中的数据接口,而我们的"com.thhh.swagger.controller"包中又只有我们自己定义的一个"/hello"数据接口,所以swagger页面上只有一个数据接口展示RequestHandlerSelectors除了有方法basePackage()之外,还有其他几个方法可以使用,但是只有basePackage()最常用 any():扫描所有的包中的数据接口none():不扫描任何包中的数据接口withClassAnnotation():扫描类上面的注解,获取数据API,比如@RestControllerwithMethodAnnotation():扫描方法上的注解,获取数据API,比如@GetMapping("") paths()方法用于规定只要哪些路径请求的API比如在HelloController中再定义一个方法test() @RequestMapping("/test") public String test(){ return "Hello Swagger"; } 调用select().paths().select().apis(RequestHandlerSelectors.basePackage("com.thhh.swagger.controller")) .paths(PathSelectors.ant("/test")) 注意:虽然我已经使用apis()指定了要扫描"com.thhh.swagger.controller"下的所有数据API接口,但是由于我又使用了PathSelectors.ant("/test"),此时swagger就只会扫描并加载显示"/test"对应的数据API接口信息 -重启项目测试 去掉paths()的调用再次启动项目

    2.配置是否启动swagger

    对于swagger是否启动就直接在swagger的配置类中使用,我们可以回顾一下在swagger配置类Docket中可以配置的参数public Docket(DocumentationType documentationType) { this.apiInfo = ApiInfo.DEFAULT; this.groupName = "default"; this.enabled = true; this.genericsNamingStrategy = new DefaultGenericTypeNamingStrategy(); this.applyDefaultResponseMessages = true; this.host = ""; this.pathMapping = Optional.absent(); this.apiSelector = ApiSelector.DEFAULT; this.enableUrlTemplating = false; this.vendorExtensions = Lists.newArrayList(); this.documentationType = documentationType; } 我们可以在上面的可以配置的参数中发现一个参数 this.enabled = true,从属性名称就可以知道,这个属性就是用来控制swagger服务是否可用的,我们可以尝试在config中配置该参数为false,再来看看能不能使用swagger服务Docket类中有专门设置enable属性的方法 /** * Hook to externally control auto initialization of this swagger plugin instance. * Typically used if defer initialization. * * @param externallyConfiguredFlag - true to turn it on, false to turn it off * @return this Docket */ public Docket enable(boolean externallyConfiguredFlag) { this.enabled = externallyConfiguredFlag; return this; } 我们可以直接通过链式编程的方式在new Docket后面直接"."使用enable()方法设置enabled参数@Bean public Docket docket(){ return new Docket(DocumentationType.SWAGGER_2) .enable(false) .apiInfo(this.apiInfo()) .select().apis(RequestHandlerSelectors.basePackage("com.thhh.swagger.controller")) .build(); } 测试 所以swagger功能是否开启直接使用Docket.enable()即可设置,true为开启(默认),false为关闭

    3.需求:根据环境自动开启/关闭swagger功能

    要求swagger在生产环境中可以使用,但是在发布的时候不能使用怎么解决? 分析:能不能使用swagger,肯定是要设置上面学习的Docket类的enable,即在生产环境中让enable=true,在发布的时候让enable=false再者,我们的生产环境和发布环境在springBoot项目中怎么区分的?就是通过配置文件区分的,我们配置一套dev环境,再配置一套pro环境,然后在application中选择激活哪一套环境即可最后,在配置swagger的config怎么判断当前的项目环境是生产环境还是发布环境?可以使用springBoot核心包中的一个类Environment,它有一个方法acceptsProfiles(),这个方法专门用来判断当前环境中指定的配置文件是否激活,可以看看源码,主要看注解/** * Return whether one or more of the given profiles is active or, in the case of no * explicit active profiles, whether one or more of the given profiles is included in * the set of default profiles. If a profile begins with '!' the logic is inverted, * i.e. the method will return {@code true} if the given profile is <em>not</em> active. * For example, {@code env.acceptsProfiles("p1", "!p2")} will return {@code true} if * profile 'p1' is active or 'p2' is not active. * @throws IllegalArgumentException if called with zero arguments * or if any profile is {@code null}, empty, or whitespace only * @see #getActiveProfiles * @see #getDefaultProfiles * @see #acceptsProfiles(Profiles) * @deprecated as of 5.1 in favor of {@link #acceptsProfiles(Profiles)} */ boolean acceptsProfiles(Profiles profiles); 注解大意为:*返回一个或多个给定配置文件是否处于活动状态,或者在没有显式配置活动配置文件的情况下, 判断是否将一个或多个指定的配置文件包含在默认配置文件集中。如果配置文件名称以“!”开头,则判断逻辑反转/颠倒, 也就是说,如果给定的配置文件没有被激活,那么该方法将返回 true *例如,env.acceptsProfiles("p1", "!p2")},则当环境中p1配置文件被激活,p2配置文件没有激活 的情况下这个方法返回为true 动手解决

    创建两套环境的配置文件,一个配置文件为application-dev.properties,端口配置为8081;一个配置文件为application-pro.properties,端口配置为8082

    在swagger的config类中调用Environment .acceptsProfiles()

    @Bean public Docket docket(Environment environment){ Profiles profile = Profiles.of("dev","test");//如果当前的配置文件是dev/test,就返回一个实例 boolean flag = environment.acceptsProfiles(profile);//如果这个Profiles实例/参数代表的配置文件被激活了,就返回true,否则返回false return new Docket(DocumentationType.SWAGGER_2) .enable(flag) .apiInfo(this.apiInfo()) .select().apis(RequestHandlerSelectors.basePackage("com.thhh.swagger.controller")) .build(); }

    去application中激活配置文件dev

    spring.profiles.active=dev

    启动项目测试

    去application中切换当前项目配置文件

    spring.profiles.active=pro

    测试 测试成功!

    Processed: 0.009, SQL: 8