Java 阶段三 Day13 RESTful、Lombok基础组件及Knife4j
一、RESTful -Representational State Transfer
RESTful(Representational State Transfer)是一种用于设计网络应用程序的架构风格。它基于一组原则和约束,以便创建具有高性能、可扩展性、简单性和可维护性的分布式系统。RESTful风格通常与HTTP协议一起使用,因此在Web开发中非常常见。
原则和概念
-
资源(Resource):在RESTful中,资源是系统中的任何对象或数据,可以通过URL唯一标识(直接通过URI访问)。资源可以是实际对象(如用户、产品)或虚拟概念(如订单、会话)。
-
表现层(Representation):资源的表现层是资源的具体表示方式,通常以XML、JSON或HTML等格式呈现。客户端与服务器之间通过这些表现层进行通信。
-
状态无关性(Statelessness):RESTful架构是状态无关的,每个请求都包含了足够的信息,使服务器能够理解并处理请求,而不需要维护客户端的状态。这有助于系统的可伸缩性和可靠性。
-
统一接口(Uniform Interface):RESTful架构使用统一的接口来访问资源,这包括一组明确定义的HTTP方法(如GET、POST、PUT、DELETE)和标准的URL结构。这使得客户端和服务器之间的通信更加一致和可预测。
-
无层次约束(Layered System):RESTful允许在架构中引入层次结构,例如代理服务器、负载均衡器等,以提高性能和安全性。
-
可缓存性(Caching):RESTful支持缓存,客户端可以缓存资源的表现层,以减少服务器负载和提高性能。
-
按需状态(On-Demand State):RESTful要求客户端包含所有必需的信息,而不依赖于服务器的状态。这使得客户端更加独立,并减少了服务器端的复杂性。
-
自描述性(Self-Descriptive Messages):RESTful的表现层应该包含足够的信息,以便客户端能够理解如何处理资源。这降低了客户端与服务器之间的耦合度。
-
无需会话管理(No Session Management):RESTful不依赖于会话管理机制,客户端可以在每个请求中包含所有必要的信息。
-
HTTP方法:RESTful使用标准的HTTP方法来执行操作。最常用的HTTP方法包括GET(获取资源)、POST(创建资源)、PUT(更新资源)和DELETE(删除资源)。这些方法对应于常见的CRUD操作(创建、读取、更新、删除)。
RESTful架构常用于构建Web服务、API和分布式系统,它提供了一种简单、直观和高效的方式来进行网络通信。许多现代Web应用程序和移动应用程序都使用RESTful API来与服务器进行通信。RESTful的设计原则使得开发人员能够构建易于理解和扩展的系统。
RESTful的特征
-
每一个URI代表一种资源
-
客户端和服务器端之前传递着资源的某种表现
-
客户端通过HTTP的几个动作 对 资源进行操作 - 状态转化
状态转化:访问一个URI即发生了一次 客户端和服务端的交互;此次交互将会涉及到数据和状态得变化。
设计符合RESTful 特征的API
详细要求:
-
资源的命名:
- 使用名词来表示资源,而不是动词。例如,使用
/users
表示用户资源,而不是/getUsers
。 - 使用复数名词形式来表示集合资源,使用单数名词形式来表示单一资源。例如,
/users
表示用户集合,/user/123
表示单个用户。
- 使用名词来表示资源,而不是动词。例如,使用
-
使用HTTP方法:
- 使用HTTP方法来执行操作。最常用的HTTP方法包括GET(获取资源)、POST(创建资源)、PUT(更新资源)和DELETE(删除资源)。
- 遵循HTTP方法的语义。例如,使用GET来获取资源,而不是用于创建或更新资源。
-
统一接口:
- 使用一组明确定义的URI模板来表示资源。这有助于客户端理解如何构建和解析URL。
- 使用HTTP状态码来表示操作结果。常见状态码包括200 OK、201 Created、204 No Content、400 Bad Request、404 Not Found、500 Internal Server Error等。
-
资源的表现层:
- 支持多种数据格式,例如JSON、XML等,以满足不同客户端的需求。客户端可以通过设置
Accept
头来请求特定的数据格式。 - 使用恰当的媒体类型来标识表现层,例如
application/json
或application/xml
。
- 支持多种数据格式,例如JSON、XML等,以满足不同客户端的需求。客户端可以通过设置
-
无状态性:
- 避免在服务器端保存客户端的状态信息。每个请求应该包含所有必要的信息,以便服务器能够理解和处理请求。
-
关联资源:
- 使用超链接来关联资源,使得客户端可以轻松地导航到相关资源。超链接可以嵌入到资源的表现层中,或者通过
Link
头部来提供。
- 使用超链接来关联资源,使得客户端可以轻松地导航到相关资源。超链接可以嵌入到资源的表现层中,或者通过
-
版本控制:
- 使用版本控制来处理API的演进。在URI中包含版本号(例如
/v1/resource
)或者使用自定义头部来指定版本。
- 使用版本控制来处理API的演进。在URI中包含版本号(例如
-
安全性:
- 使用HTTPS来保护数据的传输,特别是在涉及敏感信息的情况下。
- 使用身份验证和授权机制来保护API,确保只有合法用户可以访问资源。
-
错误处理:
- 提供有意义的错误消息,以帮助客户端识别和处理错误。错误消息应该包括HTTP状态码、错误代码和错误描述。
- 使用标准的HTTP状态码来表示错误类型,避免自定义错误码。
-
文档和元数据:
- 提供详细的文档,描述API的使用方法、资源、端点、参数等信息。常见的方式包括Swagger、OpenAPI规范等。
- 使用HATEOAS(Hypertext As The Engine Of Application State)来提供API的自描述性,使得客户端能够动态探索API。
-
测试和监控:
- 进行全面的单元测试和集成测试,以确保API的稳定性和正确性。
- 实施监控机制来跟踪API的性能和可用性,及时发现并解决问题。
设计RESTful API需要权衡许多因素,包括资源的命名、URI结构、HTTP方法的选择、错误处理等。遵循上述最佳实践有助于确保API的一致性、可读性和可维护性,同时提供良好的开发者体验。此外,与团队成员和其他开发者进行讨论和审查也是设计API的重要步骤,以确保满足实际需求。
具体介绍
-
协议 - http/https
-
域名
域名中体现出api字样,如
https://api.example.com
或者
https://example.org/api/ -
版本:
https://api.example.com/v1/ -
路径:
路径中避免使用动词,资源用名词表示,案例如下https://api.example.com/v1/users https://api.example.com/v1/animals
-
HTTP动词语义
请求动词 说明 GET(SELECT) 从服务器取出资源(一项或多项) POST(CREATE) 在服务器新建一个资源 PUT(UPDATE) 在服务器更新资源 DELETE(DELETE) 从服务器删除资源 案例:
请求动作 请求资源 说明 GET /zoos 列出所有动物园 POST /zoos 新建一个动物园 GET /zoos/ID 获取某个指定动物园的信息 PUT /zoos/ID 更新某个指定动物园的信息 DELETE /zoos/ID 删除某个动物园 GET /zoos/ID/animals 列出某个指定动物园的所有动物 DELETE /zoos/ID/animals/ID 删除某个指定动物园的指定动物 -
巧用查询字符串
?type_id=1:指定筛选条件 ?limit=10:指定返回记录的数量 ?offset=10:指定返回记录的开始位置。 ?page=2&per_page=100:指定第几页,以及每页的记录数。
-
状态码
用HTTP响应码表达 此次请求结果,例如
响应码 说明 200 OK - [GET] 服务器成功返回用户请求的数据 404 NOT FOUND 用户发出的请求针对的是不存在的记录,服务器没有进行操作 500 INTERNAL SERVER ERROR 服务器发生错误
二、整合 Lombok 基础组件
2.1 Lombok 介绍
Lombok(发音为"LOM-bok",意为"Less Code, More Fun")是一个用于Java编程语言的开源项目,它旨在减少Java代码中的样板代码(boilerplate code)编写,以提高代码的可读性和可维护性。Lombok通过使用注解来自动生成常见的Java代码,例如getter和setter方法、构造函数、equals和hashCode方法等,从而简化了Java类的编写过程。
以下是Lombok的一些主要功能和用途:
-
自动生成Getter和Setter:通过在类字段上添加
@Getter
和@Setter
注解,Lombok会自动生成相应的getter和setter方法,减少了冗长的getter和setter代码的编写。 -
自动生成构造函数:Lombok支持自动生成各种类型的构造函数,包括无参构造函数、全参构造函数、带有指定字段的构造函数等。
-
自动生成
toString
方法:通过在类上添加@ToString
注解,Lombok可以自动生成toString
方法,用于方便地打印对象的字符串表示。 -
自动生成
equals
和hashCode
方法:通过在类上添加@EqualsAndHashCode
注解,Lombok可以自动生成equals
和hashCode
方法,用于对象的比较和哈希计算。 -
自动生成
@NoArgsConstructor
和@AllArgsConstructor
:这些注解用于生成无参构造函数和全参构造函数,可减少构造函数的编写。 -
自动生成
@Data
注解:@Data
注解包含了@Getter
、@Setter
、@ToString
、@EqualsAndHashCode
等功能,可一次性自动生成所有这些方法。 -
自动生成
@Builder
注解:@Builder
注解用于生成建造者模式的构建器方法,用于创建对象的复杂实例。 -
自动生成
@Slf4j
和其他日志注解:Lombok支持生成与不同日志框架(如SLF4J、Log4j、Logback)兼容的日志注解,以便快速添加日志记录功能。 -
自动生成
@Value
注解:@Value
注解用于创建不可变(immutable)的JavaBean,它生成final字段和无参构造函数。
Lombok的主要目标是减少样板代码的编写,使Java代码更加简洁和易读。开发人员可以通过添加Lombok注解来自动生成常见的代码,而无需手动编写。这有助于提高开发效率并降低错误的可能性。但需要注意的是,使用Lombok的代码可能会对阅读代码的开发者造成一些困惑,因为生成的代码在源代码中是看不到的,因此文档和注释的编写变得尤为重要。
要使用Lombok,需要将Lombok库添加到项目的依赖中,并在IDE中安装Lombok插件,以便在开发过程中正确显示生成的代码,每个IDE和构建工具都有自己的配置方式。
2.2 安装和配置 Lombok
-
添加Lombok依赖:首先,在项目的构建工具中(例如Maven、Gradle)添加Lombok依赖。具体添加方式取决于你的构建工具。
-
如果使用Maven,可以在项目的
pom.xml
文件中添加以下依赖:<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.22</version> <!-- 根据当前最新版本更新 --> <scope>provided</scope> </dependency>
-
如果使用Gradle,可以在项目的
build.gradle
文件中添加以下依赖:compileOnly 'org.projectlombok:lombok:1.18.22' // 根据当前最新版本更新 annotationProcessor 'org.projectlombok:lombok:1.18.22'
注意:Lombok的
compileOnly
依赖用于编译时,annotationProcessor
依赖用于处理Lombok注解。 -
-
安装Lombok插件:为了在IDE中正确显示和处理Lombok注解,你需要安装适用于你的IDE的Lombok插件。Lombok支持的IDE包括Eclipse、IntelliJ IDEA、NetBeans等。
-
对于IntelliJ IDEA,你可以在IDE内使用插件市场(Plugin Marketplace)搜索"Lombok"并安装它。
-
对于Eclipse,你可以在Eclipse Marketplace搜索"Lombok"并安装它。
-
对于其他IDE,也可以查找适用于Lombok的插件或集成工具。
-
-
配置IDE:安装Lombok插件后,你可能需要进行一些IDE的配置以确保Lombok正常工作。
-
对于IntelliJ IDEA,打开IDE设置(File -> Settings or IntelliJ IDEA -> Preferences),然后在"Build, Execution, Deployment"下找到"Lombok"。启用"Lombok"支持并重启IDE。
-
对于Eclipse,通常无需额外配置。
-
-
使用Lombok注解:在项目中使用Lombok注解,例如
@Getter
、@Setter
、@Data
等,以减少样板代码的编写。在你的Java类中添加这些注解,它们会自动生成相应的代码。 -
构建项目:重新构建项目以应用Lombok的功能。在IDE中,通常无需手动构建,因为Lombok插件会自动处理。
2.3 Lombok 注解及其用法
2.3.1 @Getter 和 @Setter
用来生成 getter 和 setter 方法
@Getter
@Setter
public class Student {
private String name;
private int age;
}
这将自动生成 getName(), setName(), getAge(), setAge() 方法
2.3.2 @ToString
@ToString
public class Student {
private String name;
private int age;
}
这将自动生成 toString() 方法。
2.3.3 @AllArgsConstructor 和 @NoArgsConstructor
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private String name;
private int age;
}
这将自动生成一个有参构造函数和一个无参构造函数。
2.3.4 @Data
是一个组合的注解,它等价于同时使用了 @Getter、@Setter、@NoArgsConstructor、@AllArgsConstructor 和 @ToString 注解。
@Data
public class Student {
private String name;
private int age;
}
这将自动生成 getName(), setName(), getAge(), setAge(),有参构造函数、无参构造函数,以及 toString() 方法。
三、Knife4j
Knife4j 是一款开源的基于 Swagger 的 API 文档生成工具,旨在为 Java 开发者提供方便的 API 文档管理和在线测试功能。它是 Swagger-UI 的增强版,提供了更多的功能和自定义选项,以改善 API 文档的呈现和交互性。
以下是 Knife4j 的一些主要特点和功能:
-
自动生成 API 文档:Knife4j 可以自动解析项目中的 Swagger 注解(例如
@ApiOperation
、@ApiParam
)并生成 API 文档。这使得创建和维护 API 文档变得更加轻松。 -
在线测试:Knife4j 具有强大的在线 API 测试功能,允许开发人员在浏览器中执行 API 请求并查看响应。这有助于快速验证 API 的功能和正确性。
-
美观的界面:Knife4j 的界面与 Swagger-UI 相比更加美观和用户友好。它提供了更多的交互功能,如折叠和展开操作、参数验证和示例值的显示等。
-
权限控制:Knife4j 支持对 API 文档的访问权限控制,你可以配置谁可以查看和使用 API 文档。
-
多种主题:Knife4j 支持多种主题,你可以根据项目的需求选择合适的主题样式。
-
导出功能:你可以将 Knife4j 生成的 API 文档导出为静态 HTML 文件,以便在没有 Knife4j 运行时也能访问文档。
-
Spring Boot 集成:Knife4j 针对 Spring Boot 提供了集成支持,使得在 Spring Boot 项目中使用 Knife4j 更加简便。
-
参数校验:Knife4j 提供了参数校验功能,可以在在线测试时验证输入参数的合法性。
-
全局配置:你可以根据项目需求进行全局配置,包括文档标题、描述、联系信息等。
3.1 Knife4j快速上手
3.1.1 添加依赖
要快速上手使用 Knife4j 生成 API 文档,你需要按照以下步骤进行配置和使用:
如果你使用 Maven,可以在项目的 pom.xml
文件中添加以下依赖:
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.2</version> <!-- 根据最新版本更新 -->
</dependency>
如果你使用 Gradle,可以在项目的 build.gradle
文件中添加以下依赖:
implementation 'com.github.xiaoymin:knife4j-spring-boot-starter:3.0.2' // 根据最新版本更新
3.1.2 配置Swagger的相关信息
工程目录下创建config.Knife4jConfig
@Configuration
@EnableSwagger2
public class Knife4jConfig {
//配置Swagger2的Docket的Bean实例
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
// apiInfo():配置 API 的一些基本信息,比如:文档标题title,文档描述description,文档版本号version
.apiInfo(apiInfo())
// select():生成 API 文档的选择器,用于指定要生成哪些 API 文档
.select()
// apis():指定要生成哪个包下的 API 文档
.apis(RequestHandlerSelectors.basePackage("com.example.egmvc2.controller"))
// paths():指定要生成哪个 URL 匹配模式下的 API 文档。这里使用 PathSelectors.any(),表示生成所有的 API 文档。
.paths(PathSelectors.any())
.build();
}
//文档信息配置
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
// 文档标题
.title("地址存储")
// 文档描述信息
.description("地址存储在线API文档")
// 文档版本号
.version("1.0")
.build();
}
}
pom.xml添加配置
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.19</version>
</dependency>
application.properties添加
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
3.1.3 查看生成的接口文档
在 SpringBoot 项目启动后,访问 http://localhost:8080/doc.html 地址即可查看生成的Knife4j接口文档。
左侧的address-controller及放在controller中的AddressController文件
3.2 常用注解应用分析
-
@Api注解
添加在控制器类上的注解,通过此注解的tags属性可以修改原本显示控制器类名称的位置的文本,通常,建议在配置的tags属性值上添加序号,例如:“01. 用户模块”、“02. 微博模块”,则框架会根据值进行排序。-
参数说明
- tags:配置模块名称
-
代码示例
// 1. AddressController @Api(tags = "地址管理模块") public class AddressController { ...}
-
文档效果(重启工程并刷新页面:http://localhost:8080/doc.html#/home)
-
-
@ApiOperation注解
添加在控制器类中处理请求的方法上的注解,用于配置此方法处理的请求在API文档中显示的文本。-
参数说明
value:配置业务名称 -
代码示例
此处以添加地址功能为例,其他所有方法请添加说明@RequestMapping("insert") @ApiOperation("添加地址数据") public String insert(Address address) { return addressMapper.insert(address) == 1 ? "添加成功" : "添加失败"; }
-
-
@ApiModelProperty注解
是添加在POJO类的属性上的注解,用于对请求参数或响应结果中的某个属性进行说明,主要通过其value属性配置描述文本,并可通过example属性配置示例值。-
参数说明
- value属性:配置参数名称
- required属性:配置是否必须提交此请求参数
- example属性:配置示例值
注意:如果配置了 required=true,只是一种显示效果,Knife4j框架并不具备检查功能
-
代码示例
以添加AddressDTO为例@Data public class AddressDTO { @ApiModelProperty(value = "收件人", required = true, example = "左大凯") private String receiver; @ApiModelProperty(value = "收件地址", required = true) private String address; @ApiModelProperty(value = "邮箱", required = true) private String email; @ApiModelProperty(value = "手机号码", required = true) private String mobile; @ApiModelProperty(value = "已收件", required = true) private String tag; }
-
-
@ApiImplicitParam注解
添加在控制器类中处理请求的方法上的注解,主要用于配置非封装的参数
- 参数说明
- name:指定参数名称(参数变量名)
- value:配置参数名称
- dataType:配置数据类型
- required:配置是否必须提交此请求参数
- example:配置参数的示例值
注意:一旦使用此注解,各个参数的数据类型默认都会显示String,可以通过dataType指定数据类型
- 代码示例
此处以根据ID搜索地址功能为例@RequestMapping("selectById") @ApiOperation("根据ID进行搜索") @ApiImplicitParam(name = "id", value = "邮箱", required = true, dataType = "int", example = "0") public AddressDTO selectById(int id) { return addressMapper.selectById(id); }
- 文档效果(重启工程并刷新页面:http://localhost:8080/doc.html#/home)
- 参数说明
-
@ApiImplicitParams注解
添加在控制器类中处理请求的方法上的注解,当方法有多个非封装的参数时,在方法上添加此注解,并在注解内部通过@ApiImplicitParam数组配置多个参数。-
代码示例
此处以根据收件人和收货地址搜索功能为例(并无实际价值)@GetMapping("selectByNameAndAddress") @ApiOperation("根据用户名和地址进行搜索") @ApiImplicitParams(value = { @ApiImplicitParam(name = "receiver", value = "收件人", required = true), @ApiImplicitParam(name = "address", value = "地址", required = true) }) public List<AddressDTO> selectByNameAndAddress(String receiver, String address) { return addressMapper.selectByNameAndAddress(receiver, address); }
-
文档效果(重启工程并刷新页面:http://localhost:8080/doc.html#/home)
-
-
@ApiIgnore注解
添加在处理请求的方法的参数上,用于表示API文档框架应该忽略此参数
此处还以根据收件人和收货地址搜索功能为例(并无实际价值)
将address的required删除,在address前添加@ApiIgnore- 代码示例
@GetMapping("selectByNameAndAddress") @ApiOperation("根据用户名和地址进行搜索") @ApiImplicitParams(value = { @ApiImplicitParam(name = "receiver", value = "收件人", required = true), @ApiImplicitParam(name = "address", value = "地址") }) public List<AddressDTO> selectByNameAndAddress(String receiver,@ApiIgnore String address) { return addressMapper.selectByNameAndAddress(receiver, address); }
- 文档效果(重启工程并刷新页面:http://localhost:8080/doc.html#/home)
对比上图,可以发现请求类型和是否必读均发生变化。
- 代码示例
3.4 限制请求方式
API文档中默认每个功能会展示7种请求方式,遵循RESTful规则将 @RequestMapping 注解修改为对应请求方法的注解,比如:@GetMapping @PostMapping @PutMapping @DeleteMapping 注解,重启工程后刷新测试。
3.5 导出离线API文档
- 文档管理 - 离线文档 中存在多种格式的导出格式
- 选择合适的文档格式,导出即可到本地磁盘