一、Javadoc
源代码注释必须是非常规范的,否则在生成时会出现错误。具体会有错误原因提示。
如果项目中包含中文注释,必须在命令行中配置UTF-8编码参数。
-
打开IDEA,在顶部菜单中选择
Tools(工具)
选项卡。 -
在下拉菜单中选择
Generate JavaDoc
(生成JavaDoc)。 -
在弹出的对话框中,选择生成文档的范围。如果只针对单个源文件生成文档,可以直接选择该文件。
-
设置输出目录。可以新建一个文件夹来存放生成的文档。
-
选择区域设置来决定文档的语言。例如,简体中文是 zh_CN。
-
在其他命令行参数中输入
-encoding UTF-8 -charset UTF-8
,这样可以避免中文字符不会出现乱码。
-
完成设置后点击OK,IDEA将开始生成JavaDoc文档。
-
打开输出目录,找到index.html文件(JavaDoc的入口文件)打开查看即可。
二、Swagger
作用:
- 将项目中所有的接口呈现在页面上,不需要专门编写接口文档。
- 接口更新之后,只需要修改swagger文档中的描述就可以生成新的接口文档,避免接口文档老旧问题。
- 通过swagger页面可以直接进行接口调用,降低接口调试成本。
使用
-
引入POM依赖
<!-- swagger3:swagger是openAPI的规范技术。springfox是swagger的具体实现 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>3.0.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>3.0.0</version> </dependency>
-
在
SpringBoot
启动类添加@EnableOpenApi
注解。开启swagger支持@SpringBootApplication @EnableOpenApi public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
-
报错:提示。原因:SpringBoot版本在2.6.0之后出现swagger版本不兼容。SpringBoot处理映射匹配默认策略发生变化。
-
2.6.0之前
-
2.6.0之后
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181) ~[spring-context-5.3.23.jar:5.3.23] at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) ~[spring-context-5.3.23.jar:5.3.23] at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) ~[spring-context-5.3.23.jar:5.3.23] at java.lang.Iterable.forEach(Iterable.java:75) ~[na:1.8.0_131] at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155) ~[spring-context-5.3.23.jar:5.3.23] at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123) ~[spring-context-5.3.23.jar:5.3.23] at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935) ~[spring-context-5.3.23.jar:5.3.23] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) ~[spring-context-5.3.23.jar:5.3.23] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.6.13.jar:2.6.13] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:745) [spring-boot-2.6.13.jar:2.6.13] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:420) [spring-boot-2.6.13.jar:2.6.13] at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-2.6.13.jar:2.6.13] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1317) [spring-boot-2.6.13.jar:2.6.13] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) [spring-boot-2.6.13.jar:2.6.13] at com.example.demo.DemoApplication.main(DemoApplication.java:12) [classes/:na] Caused by: java.lang.NullPointerException: null at springfox.documentation.spring.web.WebMvcPatternsRequestConditionWrapper.getPatterns(WebMvcPatternsRequestConditionWrapper.java:56) ~[springfox-spring-webmvc-3.0.0.jar:3.0.0] at springfox.documentation.RequestHandler.sortedPaths(RequestHandler.java:113) ~[springfox-core-3.0.0.jar:3.0.0] at springfox.documentation.spi.service.contexts.Orderings.lambda$byPatternsCondition$3(Orderings.java:89) ~[springfox-spi-3.0.0.jar:3.0.0] at java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469) ~[na:1.8.0_131] at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355) ~[na:1.8.0_131] at java.util.TimSort.sort(TimSort.java:220) ~[na:1.8.0_131] at java.util.Arrays.sort(Arrays.java:1512) ~[na:1.8.0_131] at java.util.ArrayList.sort(ArrayList.java:1454) ~[na:1.8.0_131] at java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:387) ~[na:1.8.0_131] at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_131] at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_131] at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_131] at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_131] at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482) ~[na:1.8.0_131] at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_131] at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[na:1.8.0_131] at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_131] at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[na:1.8.0_131] at springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider.requestHandlers(WebMvcRequestHandlerProvider.java:81) ~[springfox-spring-webmvc-3.0.0.jar:3.0.0] at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[na:1.8.0_131] at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374) ~[na:1.8.0_131] at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[na:1.8.0_131] at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_131] at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[na:1.8.0_131] at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_131] at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[na:1.8.0_131] at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.withDefaults(AbstractDocumentationPluginsBootstrapper.java:107) ~[springfox-spring-web-3.0.0.jar:3.0.0] at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.buildContext(AbstractDocumentationPluginsBootstrapper.java:91) ~[springfox-spring-web-3.0.0.jar:3.0.0] at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.bootstrapDocumentationPlugins(AbstractDocumentationPluginsBootstrapper.java:82) ~[springfox-spring-web-3.0.0.jar:3.0.0] at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:100) ~[springfox-spring-web-3.0.0.jar:3.0.0] at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178) ~[spring-context-5.3.23.jar:5.3.23] ... 14 common frames omitted
-
-
报错解决
-
在启动类或配置类添加注解
@EnableWebMvc
@SpringBootApplication @EnableOpenApi @EnableWebMvc public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
-
在application.properties配置文件添加
properties spring.mvc.pathmatch.matching-strategy=ant_path_matcher
server.port=8080 spring.mvc.pathmatch.matching-strategy=ant_path_matcher
-
-
启动并访问swagger页面:
http://localhost:8080/swagger-ui/index.html
常用注解
-
@Api
:用在所请求的类上,表示对类的说明tags =
“说明该类的作用,可以在UI界面上看到的注解”
-
@ApiOperation
:用在请求的方法上,说明方法的用途、作用value =
“说明方法的用途、作用”notes =
“方法的备注说明”
-
@ApiImplicitParams
:用在请求的方法上,表示一组参数说明@ApiImplicitParam
:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面name
:参数名value
:参数的说明required
:参数是否必须传paramType
:参数位置@RequestHeader
:从请求头中获取参数信息@RequestParam
:从query中获取参数信息@PathVariable
:从URL中获取占位符参数并绑定到控制器处理方法的入参中
-
@ApiResponses
:用在请求的方法上,表示一组响应@ApiResponse
:用在@ApiResponses中,一般用于表达一个错误的响应信息code
:数字message
:信息response
:抛出异常的类
-
@ApiModel
:用于响应类上,表示一个返回响应数据的信息 -
@ApiModelProperty
:用在属性上,描述响应类的属性
@Api(tags = "这是一个测试类")
@RestController
public class TestController {
@ApiOperation(value = "测试学生", notes = "测试一下")
@GetMapping("student")
@ApiImplicitParams({
@ApiImplicitParam(name = "name", value = "姓名", required = true, paramType = "query"),
@ApiImplicitParam(name = "age", value = "年龄", required = false, dataType = "Integer"),
})
public Student sayStudent( String name, Integer age) {
Student student = new Student();
student.setName(name);
student.setAge(age);
return student;
}
}
@ApiModel("学生测试类")
@Data
public class Student {
@ApiModelProperty("姓名")
private String name;
@ApiModelProperty("年龄")
private int age;
}
修改信息配置
标识文档介绍说明,例如什么项目,负责人信息等
新建一个SwaggerConfig类,重写ApiInfo,以及重写Docker实现并且重置ApiInfo。
@Configuration
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.OAS_30) // 指定swagger文档是3.0
.apiInfo(createRestApiInfo());
}
@Bean
public ApiInfo createRestApiInfo() {
return new ApiInfo("这是一个专门用于测试的接口文档","项目于2024年12月26日开始","1.0","www.baidu.com","wh","apache 2.0", "www.baidu.com");
}
}
开启或关闭
在swaggerconfig中设置enable开启(true)或关闭(false)即可
@Configuration
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.OAS_30) // 指定swagger文档是3.0
.enable(true) // 开启(true)或关闭(false)
.apiInfo(createRestApiInfo());
}
@Bean
public ApiInfo createRestApiInfo() {
return new ApiInfo("这是一个专门用于测试的接口文档","项目于2024年12月26日开始","1.0","www.baidu.com","wh","apache 2.0", "www.baidu.com");
}
}
设置过滤
可以指定包路径下的类生成API或者根据当前用户请求的路径过滤。
- 使用过滤,必须先调用select方法。
- 通过apis方法,basePackage可以根据包路径来生成特定类的API。
- any方法是默认所有都有效,none方法默认无效。
- withClassAnnotation根据类注解生成。
- withMethodAnnotation根据方法注解生成。
@Configuration
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.OAS_30) // 指定swagger文档是3.0
.enable(true) // 开启(true)或关闭(false)
.select().apis(RequestHandlerSelectors.basePackage("com.example.demo.demos.web")) // 指定扫描注解的包
.build()
.apiInfo(createRestApiInfo());
}
@Bean
public ApiInfo createRestApiInfo() {
return new ApiInfo("这是一个专门用于测试的接口文档","项目于2024年12月26日开始","1.0","www.baidu.com","wh","apache 2.0", "www.baidu.com");
}
}
三、Knife4j
Knife4j是一个基于Swagger UI的增强版UI框架。主要解决SwaggerUI界面不美观问题。
-
引入POM依赖
<dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-openapi2-spring-boot-starter</artifactId> <version>4.0.0</version> </dependency>
-
创建配置类:新建Fnif4jConfig.java,也可以是其他名字
package com.example.demo.demos.web; import io.swagger.annotations.Api; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc; @Configuration @EnableSwagger2WebMvc public class Knife4jConfig { @Bean public Docket api() { // 使用swagger2语法 Docket docket = new Docket(DocumentationType.SWAGGER_2).apiInfo(new ApiInfoBuilder() .title("Demo测试") // 网站标题 .description("这是一个测试的Demo") // 描述 .termsOfServiceUrl("") // 服务条款URL .contact(new Contact("小王吧", "www.baidu.com", "112@126.com")) .license("www.baidu.com") // 许可证 .licenseUrl("www.baidu.com") //许可证URL .version("1.0.0") // 版本 .build()) .groupName("demo") // 组名 .select() .apis(RequestHandlerSelectors.basePackage("com.example")) .paths(PathSelectors.any()) .build(); return docket; } }
-
实体类
@ApiModel("学生类") @Data public class Student { @ApiModelProperty("学号") private String no; @ApiModelProperty("姓名") private String name; @ApiModelProperty("年龄") private int age; }
-
调用测试
package com.example.demo.demos.web; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @Api(tags = "这是一个测试类") @RestController public class TestController { @ApiOperation(value = "测试学生", notes = "测试一下") @GetMapping("student") @ApiImplicitParams({ @ApiImplicitParam(name = "name", value = "姓名", required = true, paramType = "query"), @ApiImplicitParam(name = "age", value = "年龄", required = false, dataType = "Integer"), }) public String sayStudent( String name, Integer age) { return "你好," + name + ",年龄是" + age; } @ApiOperation(value = "测试学生实体", notes = "测试一下实体类") @GetMapping("studentDto") public Student sayStudent(Student student) { student.setNo("No:123456"); return student; } }
-
访问:localhost:8080/doc.html(根据具体情况配置,一般是IP + 端口号 + 项目名 + /doc.html)
四、ApiFox
-
下载Apifox,并注册一个账号
-
IDEA中引入Apifox Helper插件
-
账号设置一个令牌
-
将令牌信息及项目配置到IDEA中
-
修改日志编码
-
更新接口文档到Apifox
-
更新文档成功
-
请求绑定token
-
调用登录接口,获取token。通过添加后置操作来把获取到的token放到变量里。
-
请求其他接口时,将token值从变量取出使用即可。