现在的技术发展还是很迅猛,子曰:“志于道,据于德,依于仁,游于艺”,既然当年弃工程力学转向软件这个行业,就需要“游”于各种技术之中,虽然年长了,但还是应该熟悉这些新兴的技术,“自古美女如良将,不许人家到白头”,技术人员及时走到管理岗位又怎么样,庞统一天治理一个县城,那是基本功,这些基本功怎么能因为你到了管理岗位就可以不学呢?
当年从北京回武汉,在公司接触了CMMI5,明白应该按照规范的流程做事情,因为那个是最佳实践的沉淀,接口文档用word写的很清楚,通讯协议、入参、出参、加密方式、签名方式、调用时序图都要写的很清楚,如果有改动怎添加修订记录,做的不好的情况,就是接口文档可能会比较滞后,不过那个时候还是ssm框架,不是前后端分离,冲突还不是那么明显,只有对外接口采用postman等调试一下,接口想对较少。
现在前端采用vue、react,后端采用springboot,前后端分离,开发工程师也分工了,这个时候矛盾就出来,这个时候yapi、metersphere等工具诞生了,不过这些还不够,还希望通过swagger在代码中就把接口文档写好,这样不是更好吗,再往后发展又诞生了springfox,就这个环节又简化了。
<springfox.version>3.0.0</springfox.version>
<spring-plugin.version>2.0.0.RELEASE</spring-plugin.version>
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-metadata</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-metadata</artifactId>
</exclusion>
</exclusions>
</dependency>
springfox-boot-starter
默认引用的是1.2.0.RELEASE
,启动的时候会提示下面的错误,故而需要调整为2.0.0.RELEASE
Caused by: java.lang.NoSuchMethodError: org.springframework.plugin.core.PluginRegistry.getPluginFor(Ljava/lang/Object;)Ljava/util/Optional;
at springfox.documentation.schema.plugins.SchemaPluginsManager.viewProvider(SchemaPluginsManager.java:95)
at springfox.documentation.spring.web.readers.operation.OperationModelsProvider.viewForReturn(OperationModelsProvider.java:116)
at springfox.documentation.spring.web.readers.operation.OperationModelsProvider.collectFromReturnType(OperationModelsProvider.java:85)
at springfox.documentation.spring.web.readers.operation.OperationModelsProvider.apply(OperationModelsProvider.java:58)
at springfox.documentation.spring.web.plugins.DocumentationPluginsManager.modelContexts(DocumentationPluginsManager.java:160)
at springfox.documentation.spring.web.scanners.ApiModelReader.read(ApiModelReader.java:87)
at springfox.documentation.spring.web.scanners.ApiListingScanner.scan(ApiListingScanner.java:154)
at springfox.documentation.spring.web.scanners.ApiDocumentationScanner.scan(ApiDocumentationScanner.java:67)
at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.scanDocumentation(AbstractDocumentationPluginsBootstrapper.java:96)
at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.bootstrapDocumentationPlugins(AbstractDocumentationPluginsBootstrapper.java:82)
at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:100)
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181)
... 19 common frames omitted
启动工程中,这里的使用@EnableOpenApi
,它就找到对应的controller了。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.ArrayList;
@Configuration
@EnableOpenApi
public class SwaggerConfig {
@Bean
public Docket docket(){
return new Docket(DocumentationType.OAS_30);
}
private ApiInfo apiInfo(){
// 作者信息
Contact contact = new Contact("dzm","","test@qq.com");
return new ApiInfo("青丘的接口文档",
"项目描述",
"1.0",
"",
contact,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList());
}
}
这里还可以通过构造器模式创建信息。
private ApiInfo apiInfo(){
// 作者信息
Contact contact = new Contact("dzm","","test@qq.com");
return new ApiInfoBuilder().title("青丘接口文档")
.description("青丘项目")
.contact(contact)
.version("1.0.0")
.build();
}
打开页面http://localhost:8188/swagger-ui/index.html,这个端口8188
是根据系统的启动端口而定,你的可能是8080
上面的只要带@RestController
或者@Controller
,它都会把接口帮我们整理出来
controller的参数说明
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>3.0.0</version>
</dependency>
这里@Api
类名、@ApiOperation
方法名、@ApiParam
参数说明 对controller进行描述
@Api("强弱管理")
@RequestMapping("api/qiangruo")
@RestController
public class QiangRuoController {
private static Logger log = LoggerFactory.getLogger(QiangRuoController.class);
@Autowired
private QiangRuoService qiangRuoService;
@ApiOperation("获取孙海义八字旺衰对象")
@PostMapping("getShyDto")
public ShyGenYinDto getShyDto(@ApiParam("八字") @RequestParam("bz") String bz){
String[] zhus = bz.split(" ");
BaZi bazi = new BaZi.Builder()
.setYear(zhus[0]).setMonth(zhus[1]).setDay(zhus[2]).setHour(zhus[3])
.build();
return qiangRuoService.getShyDto(bazi);
}
返回参数,这里有两个注解@ApiModel
实体类、@ApiModelProperty
实体类属性
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel("孙海义根印")
public class ShyGenYinDto {
/**
* 年支
*/
@ApiModelProperty("年支")
private String yz;
接着就可以看到中文的注释了。
生产环境不想让别人看到接口文档,于是增加相应的配置
springfox:
documentation:
swagger-ui:
enabled: false
这些还不够,可以通过设置账号、密码,这样还可以查看当前系统的接口版本。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
springboot1和springboot2是不一样的,因为我接触的时候已经是springboot2,哪些过去时学习也没啥意义了。
参考springboot + spring security + swagger 整合
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 静态资源配置
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) throws Exception {
//swagger2所需要用到的静态资源,允许访问
web.ignoring().antMatchers("/v3/api-docs",
"/swagger-resources/configuration/ui",
"/swagger-resources",
"/swagger-resources/configuration/security",
"/swagger-ui.html");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//允许根路径url的访问
.antMatchers("/").permitAll()
//允许swagger-ui.html访问
.antMatchers("/swagger-ui.html").permitAll()
.anyRequest().authenticated()
.and()
.logout().permitAll()
.and()
.formLogin().permitAll();
}
}
启动的时候,打印日志Using generated security password: 71c3ad59-a36c-46e0-be57-1445fb41dff8
,这个是密码,用户名为user
。
swagger-ui不友好,这里调整一下使用swagger-bootstrap-ui
看看,依赖的是springfox-swagger2
的2.9.2
,并不是3.0.0
,还是有兼容性问题
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'swaggerBootstrapUiResourceExtController' defined in URL [jar:file:/D:/repository/com/github/xiaoymin/swagger-bootstrap-ui/1.9.6/swagger-bootstrap-ui-1.9.6.jar!/com/github/xiaoymin/swaggerbootstrapui/web/SwaggerBootstrapUiResourceExtController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'swaggerResourcesExtProvider' defined in URL [jar:file:/D:/repository/com/github/xiaoymin/swagger-bootstrap-ui/1.9.6/swagger-bootstrap-ui-1.9.6.jar!/com/github/xiaoymin/swaggerbootstrapui/service/SwaggerResourcesExtProvider.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.github.xiaoymin.swaggerbootstrapui.service.SwaggerResourcesExtProvider]: Constructor threw exception; nested exception is java.lang.NoSuchMethodError: springfox.documentation.schema.ClassSupport.classByName(Ljava/lang/String;)Lcom/google/common/base/Optional;
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:729)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:192)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1270)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:541)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:501)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
at org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$144/146403516.getObject(Unknown Source)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:760)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:869)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759)
后面作者改版了, knife4j,
添加,单体springboot引入下面这个就可以
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
这个时候输入http://localhost:8188/doc.html
,即可,这种模式就好多了
这里再做一下测验,看swagger还能做什么
@ApiOperation("测试")
@ApiImplicitParams({
@ApiImplicitParam(name = "day", value = "日柱",required=true)
})
@PostMapping("test")
@ResponseBody
public ResponseResult<ShyGenYinDto> test(BaZi bazi){
ResponseResult<ShyGenYinDto> resp = new ResponseResult<ShyGenYinDto>(true);
return resp;
}
入参为列表的
import org.springframework.web.bind.annotation.RequestBody
@ApiOperation("批量新增期初明细")
@PostMapping("addBatch")
public ResponseResult addBatch(@ApiParam(name = "req",value = "期初明细") @RequestBody List<AccInitialSubjectReq> req){
return null;
}
升级到springboot2.7.6,与swagger3.0.0产生冲突,这个是需要增加下面的配置,即可
spring:
# autoconfigure:
# exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
mvc:
pathmatch:
matching-strategy: ant_path_matcher