spring开发文档(spring开发工具)

神器 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.

*/@ConfigurationpublicclassSpringDocConfig{@BeanpublicOpenAPImallTinyOpenAPI(){returnnewOpenAPI()                .info(newInfo().title("Mall-Tiny API")                        .description("SpringDoc API 演示")                        .version("v1.0.0")                        .license(newLicense().name("Apache 2.0").url("")))                .externalDocs(newExternalDocumentation()                        .description("SpringBoot实战电商项目mall(50K+Star)全套文档")                        .url(""));    }@BeanpublicGroupedOpenApipublicApi(){returnGroupedOpenApi.builder()                .group("brand")                .pathsToMatch("/brand/**")                .build();    }@BeanpublicGroupedOpenApiadminApi(){returnGroupedOpenApi.builder()                .group("admin")                .pathsToMatch("/admin/**")                .build();    }}

结合SpringSecurity使用

由于我们的项目集成了SpringSecurity,需要通过JWT认证头进行访问,我们还需配置好SpringDoc的白名单路径,主要是Swagger的资源路径;

/**

* SpringSecurity的配置

* Created by macro on 2018/4/26.

*/@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled = true)public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity httpSecurity) throws Exception {httpSecurity.csrf()// 由于使用的是JWT,我们这里不需要csrf.disable().sessionManagement()// 基于token,所以不需要session.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers(HttpMethod.GET,// Swagger的资源路径需要允许访问"/","/swagger-ui.html","/swagger-ui/","/*.html","/favicon.ico","/**/*.html","/**/*.css","/**/*.js","/swagger-resources/**","/v3/api-docs/**").permitAll().antMatchers("/admin/login")// 对登录注册要允许匿名访问.permitAll().antMatchers(HttpMethod.OPTIONS)//跨域请求会先进行一次options请求.permitAll().anyRequest()// 除上面外的所有请求全部需要鉴权认证.authenticated();            }}

然后在OpenAPI对象中通过addSecurityItem方法和SecurityScheme对象,启用基于JWT的认证功能。

/**

* SpringDoc API文档相关配置

* Created by macro on 2022/3/4.

*/@ConfigurationpublicclassSpringDocConfig{privatestaticfinalString SECURITY_SCHEME_NAME ="BearerAuth";@BeanpublicOpenAPImallTinyOpenAPI(){returnnewOpenAPI()                .info(newInfo().title("Mall-Tiny API")                        .description("SpringDoc API 演示")                        .version("v1.0.0")                        .license(newLicense().name("Apache 2.0").url("")))                .externalDocs(newExternalDocumentation()                        .description("SpringBoot实战电商项目mall(50K+Star)全套文档")                        .url(""))                .addSecurityItem(newSecurityRequirement().addList(SECURITY_SCHEME_NAME))                .components(newComponents()                                .addSecuritySchemes(SECURITY_SCHEME_NAME,newSecurityScheme()                                                .name(SECURITY_SCHEME_NAME)                                                .type(SecurityScheme.Type.HTTP)                                                .scheme("bearer")                                                .bearerFormat("JWT")));    }}

测试

接下来启动项目就可以访问Swagger界面了,访问地址:

我们先通过登录接口进行登录,可以发现这个版本的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有点卡手的朋友可以迁移到它试试!

参考资料

项目地址:

官方文档:

项目源码地址

Spring Data Elasticsearch

Spring Data Elasticsearch项目将核心Spring概念应用于使用Elasticsearch搜索引擎开发解决方案。为我们提供了一个“模板”作为高级抽象,用于存储、查询、排序和面对文档.

要使用Spring Data Elasticsearch为我们设计好的模板,只需继承ElasticsearchRepositoryT, ID接口

如:

ElasticsearchRepositoryT, ID的类图谱:

可以看到ElasticsearchRepository实现了CrudRepository这个接口

Spring Data repository抽象中的中心接口是Repository。它将领域类和领域类的ID类型作为类型参数来管理。此接口主要用作标记接口,以捕获要使用的类型,并帮助您发现扩展此接口的接口。CrudRepository为所管理的实体类提供了复杂的CRUD功能。

CrudRepository:

在CrudRepository之上,有一个PagingAndSortingRepository抽象,它添加了额外的方法来简化对实体的分页访问:

如:

上面的方法名将被转换为下面的Elasticsearch json查询:

还可以使用@Query注释在方法中声明查询。

详细的文档说明:

以下为对针对自定义实体类Blog基本操作的测试:

Blog

继承ElasticsearchRepository接口:

Service:

测试

Spring Properties整理

spring 配置及配置文件,是学习spring的基础知识,那么,这篇文档我们先了解下spring 的配置写法,以及如何加载配置的。

以key: value来表示,value前必须带一个空格。

第一种写法

第二种写法

大括号的方式,还有逗号

数组用 “-”表示。

当然,还有一种,冒号不要丢失

Spring 的配置通过配置文件进行映射。分为两种方式,一种是 @ConfigurationProperties 读取属性,一种是 @Value 这种读取单个的值。

类文件为

这是一种通过路径 monapi 映射方式。

这里如果

支持对 通过类加载的方式,对配置的值进行映射。

映射完成后,我们还得让Spring 能扫描的到。 那么又可以用到两种方式。

让 Spring 知道我们的 @ConfigurationProperties 类存在,以便将其加载到应用程序上下文中。

第一种,就是让自定义的类,注册成为一个启动类的配置,然后的加载方式。@EnableConfigurationProperties({MonitorApiproperties.class})

可以在启动类了,就是主入口类,加载配置

第二种,可以直接在 ConfigurationProperties @ComponentScan 注解参数。

还可以通过bean 生成配置。 也可以直接用了,当然如果是bean 加载的话,就不用在

MonitorApiproperties 注释 @Component 了。

调用,一般都是在 Configuration 去取参数,就可以直接用了。

这就比较简单了,直接获取值就行了,只能一个值一个值的获取。

@Component

public class PrometheusRepostitoryImpl implements PrometheusRepostitory {

}

配置文件加载位置和顺序,springboot启动会扫描一下位置的配置文件作为springboot的默认配置文件。

SpringBoot也可以从以下位置加载配置;优先级从高到低,高优先级的配置覆盖低优先级的配置,所有配置形成互补配置。

有时候需要配置多个配置文件,一个主配置文件,application.yml和开发配置文件,和生产环境配置。

application.yml

application-dev.yml

application-prod.yml

我们通过在主配置文件用

配置命名

而在 application-dev.yml 和 application-prod.yml ,为了能找到 dev(prod) 的标签,我们通过 ,配置名称方式,来读取。

可以使用spring.profile.active来进行切换。

也可以通过命令行指定配置文件

spring开发文档(spring开发工具)  第1张

Spring系列(一)Spring MVC bean 解析、注册、实例化流程源码剖析

最近在使用Spring MVC过程中遇到了一些问题,网上搜索不少帖子后虽然找到了答案和解决方法,但这些答案大部分都只是给了结论,并没有说明具体原因,感觉总是有点不太满意。

更重要的是这些所谓的结论大多是抄来抄去,基本源自一家,真实性也有待考证。

那作为程序员怎么能知其所以然呢?

此处请大家内心默读三遍。

用过Spring 的人都知道其核心就是IOC和AOP,因此要想了解Spring机制就得先从这两点入手,本文主要通过对IOC部分的机制进行介绍。

在开始阅读之前,先准备好以下实验材料。

IDEA 是一个优秀的开发工具,如果还在用Eclipse的建议切换到此工具进行。

IDEA有很多的快捷键,在分析过程中建议大家多用Ctrl+Alt+B快捷键,可以快速定位到实现函数。

Spring bean的加载主要分为以下6步:

查看源码第一步是找到程序入口,再以入口为突破口,一步步进行源码跟踪。

Java Web应用中的入口就是web.xml。

在web.xml找到ContextLoaderListener ,此Listener负责初始化Spring IOC。

contextConfigLocation参数设置了bean定义文件地址。

下面是ContextLoaderListener的官方定义:

翻译过来ContextLoaderListener作用就是负责启动和关闭Spring root WebApplicationContext。

具体WebApplicationContext是什么?开始看源码。

从源码看出此Listener主要有两个函数,一个负责初始化WebApplicationContext,一个负责销毁。

继续看initWebApplicationContext函数。

在上面的代码中主要有两个功能:

进入CreateWebAPPlicationContext函数

进入determineContextClass函数。

进入configureAndReFreshWebApplicaitonContext函数。

WebApplication Context有很多实现类。 但从上面determineContextClass得知此处wac实际上是XmlWebApplicationContext类,因此进入XmlWebApplication类查看其继承的refresh()方法。

沿方法调用栈一层层看下去。

获取beanFactory。

beanFactory初始化。

加载bean。

读取XML配置文件。

XmlBeanDefinitionReader读取XML文件中的bean定义。

继续查看loadBeanDefinitons函数调用栈,进入到XmlBeanDefinitioReader类的loadBeanDefinitions方法。

最终将XML文件解析成Document文档对象。

上一步完成了XML文件的解析工作,接下来将XML中定义的bean注册到webApplicationContext,继续跟踪函数。

用BeanDefinitionDocumentReader对象来注册bean。

解析XML文档。

循环解析XML文档中的每个元素。

下面是默认命名空间的解析逻辑。

不明白Spring的命名空间的可以网上查一下,其实类似于package,用来区分变量来源,防止变量重名。

这里我们就不一一跟踪,以解析bean元素为例继续展开。

解析bean元素,最后把每个bean解析为一个包含bean所有信息的BeanDefinitionHolder对象。

接下来将解析到的bean注册到webApplicationContext中。接下继续跟踪registerBeanDefinition函数。

跟踪registerBeanDefinition函数,此函数将bean信息保存到到webApplicationContext的beanDefinitionMap变量中,该变量为map类型,保存Spring 容器中所有的bean定义。

Spring 实例化bean的时机有两个。

一个是容器启动时候,另一个是真正调用的时候。

相信用过Spring的同学们都知道以上概念,但是为什么呢?

继续从源码角度进行分析,回到之前XmlWebApplication的refresh()方法。

可以看到获得beanFactory后调用了 finishBeanFactoryInitialization()方法,继续跟踪此方法。

预先实例化单例类逻辑。

获取bean。

doGetBean中处理的逻辑很多,为了减少干扰,下面只显示了创建bean的函数调用栈。

创建bean。

判断哪种动态代理方式实例化bean。

不管哪种方式最终都是通过反射的形式完成了bean的实例化。

我们继续回到doGetBean函数,分析获取bean的逻辑。

上面方法中首先调用getSingleton(beanName)方法来获取单例bean,如果获取到则直接返回该bean。方法调用栈如下:

getSingleton方法先从singletonObjects属性中获取bean 对象,如果不为空则返回该对象,否则返回null。

那 singletonObjects保存的是什么?什么时候保存的呢?

回到doGetBean()函数继续分析。如果singletonObjects没有该bean的对象,进入到创建bean的逻辑。处理逻辑如下:

下面是判断容器中有没有注册bean的逻辑,此处beanDefinitionMap相信大家都不陌生,在注册bean的流程里已经说过所有的bean信息都会保存到该变量中。

如果该容器中已经注册过bean,继续往下走。先获取该bean的依赖bean,如果镩子依赖bean,则先递归获取相应的依赖bean。

依赖bean创建完成后,接下来就是创建自身bean实例了。

获取bean实例的处理逻辑有三种,即Singleton、Prototype、其它(request、session、global session),下面一一说明。

如果bean是单例模式,执行此逻辑。

获取单例bean,如果已经有该bean的对象直接返回。如果没有则创建单例bean对象,并添加到容器的singletonObjects Map中,以后直接从singletonObjects直接获取bean。

把新生成的单例bean加入到类型为MAP 的singletonObjects属性中,这也就是前面singletonObjects()方法中获取单例bean时从此Map中获取的原因。

Prototype是每次获取该bean时候都新建一个bean,因此逻辑比较简单,直接创建一个bean后返回。

从相应scope获取对象实例。

判断scope,获取实例函数逻辑。

在相应scope中设置实例函数逻辑。

以上就是Spring bean从无到有的整个逻辑。

从源码角度分析 bean的实例化流程到此基本接近尾声了。

回到开头的问题,ContextLoaderListener中初始化的WebApplicationContext到底是什么呢?

通过源码的分析我们知道WebApplicationContext负责了bean的创建、保存、获取。其实也就是我们平时所说的IOC容器,只不过名字表述不同而已。

本文主要是讲解了XML配置文件中bean的解析、注册、实例化。对于其它命名空间的解析还没有讲到,后续的文章中会一一介绍。

希望通过本文让大家在以后使用Spring的过程中有“一切尽在掌控之中”的感觉,而不仅仅是稀里糊涂的使用。

spring boot 官方文档怎么学习

如果我说,从开头开始学,然后丢一堆链接,不知道会不会被打?然而我内心的OS是:打打不到啊达不到!这个Spring Boot系列算是我看见的比较完整的,通俗易懂的一个系列了,推荐给你们吧!Spring Boot系列(九):定时任务Spring Boot系列(八):RabbitMQ详解Spring Boot系列(七):springboot+mybatis多数据源最简解决方案Spring Boot系列(六):如何优雅的使用mybatisSpring Boot系列(五):spring data jpa的使用Spring Boot系列(四):thymeleaf使用详解Spring Boot系列(三):Spring Boot中Redis的使用Spring Boot系列(二):web综合开发Spring Boot系列(一):Spring Boot 入门篇然后送上一个番外篇: springboot实战:我们的第一款开源软件 也欢迎关注我的专栏:极乐科技 - 知乎专栏专栏里面很多讲Spring Boot使用技巧的文章

以上内容为新媒号(sinv.com.cn)为大家提供!新媒号,坚持更新大家所需的互联网后端知识。希望您喜欢!

版权申明:新媒号所有作品(图文、音视频)均由用户自行上传分享,仅供网友学习交流,不声明或保证其内容的正确性,如发现本站有涉嫌抄袭侵权/违法违规的内容。请发送邮件至 k2#88.com(替换@) 举报,一经查实,本站将立刻删除。

(0)
上一篇 2023-09-23
下一篇 2023-09-23

相关推荐

发表回复

登录后才能评论