• JSD-2204-Knife4j框架-处理响应结果-Day07


    1.Knife4j框架

    Knife4j框架是一款基于Swagger 2框架的、能够基于项目中的控制器的代码来生成在线API文档的框架,另外,此框架还有调试功能,可以向服务器端发送请求,并获取响应结果。

    关于此框架,要使之能够使用,需要:

    • 添加依赖
    • 添加配置类
    • application.properties中添加1条配置

    关于依赖的代码:

    1. <dependency>
    2. <groupId>com.github.xiaoymingroupId>
    3. <artifactId>knife4j-spring-boot-starterartifactId>
    4. <version>2.0.9version>
    5. dependency>

    关于配置类:

    1. import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
    2. import lombok.extern.slf4j.Slf4j;
    3. import org.springframework.beans.factory.annotation.Autowired;
    4. import org.springframework.context.annotation.Bean;
    5. import org.springframework.context.annotation.Configuration;
    6. import springfox.documentation.builders.ApiInfoBuilder;
    7. import springfox.documentation.builders.PathSelectors;
    8. import springfox.documentation.builders.RequestHandlerSelectors;
    9. import springfox.documentation.service.ApiInfo;
    10. import springfox.documentation.service.Contact;
    11. import springfox.documentation.spi.DocumentationType;
    12. import springfox.documentation.spring.web.plugins.Docket;
    13. import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
    14. /**
    15. * Knife4j配置类
    16. *
    17. * @author java@tedu.cn
    18. * @version 0.0.1
    19. */
    20. @Slf4j
    21. @Configuration
    22. @EnableSwagger2WebMvc
    23. public class Knife4jConfiguration {
    24. /**
    25. * 【重要】指定Controller包路径
    26. */
    27. private String basePackage = "cn.tedu.csmall.product.controller";
    28. /**
    29. * 分组名称
    30. */
    31. private String groupName = "product";
    32. /**
    33. * 主机名
    34. */
    35. private String host = "http://java.tedu.cn";
    36. /**
    37. * 标题
    38. */
    39. private String title = "酷鲨商城在线API文档--商品管理";
    40. /**
    41. * 简介
    42. */
    43. private String description = "酷鲨商城在线API文档--商品管理";
    44. /**
    45. * 服务条款URL
    46. */
    47. private String termsOfServiceUrl = "http://www.apache.org/licenses/LICENSE-2.0";
    48. /**
    49. * 联系人
    50. */
    51. private String contactName = "Java教学研发部";
    52. /**
    53. * 联系网址
    54. */
    55. private String contactUrl = "http://java.tedu.cn";
    56. /**
    57. * 联系邮箱
    58. */
    59. private String contactEmail = "java@tedu.cn";
    60. /**
    61. * 版本号
    62. */
    63. private String version = "1.0.0";
    64. @Autowired
    65. private OpenApiExtensionResolver openApiExtensionResolver;
    66. public Knife4jConfiguration() {
    67. log.debug("加载配置类:Knife4jConfiguration");
    68. }
    69. @Bean
    70. public Docket docket() {
    71. String groupName = "1.0.0";
    72. Docket docket = new Docket(DocumentationType.SWAGGER_2)
    73. .host(host)
    74. .apiInfo(apiInfo())
    75. .groupName(groupName)
    76. .select()
    77. .apis(RequestHandlerSelectors.basePackage(basePackage))
    78. .paths(PathSelectors.any())
    79. .build()
    80. .extensions(openApiExtensionResolver.buildExtensions(groupName));
    81. return docket;
    82. }
    83. private ApiInfo apiInfo() {
    84. return new ApiInfoBuilder()
    85. .title(title)
    86. .description(description)
    87. .termsOfServiceUrl(termsOfServiceUrl)
    88. .contact(new Contact(contactName, contactUrl, contactEmail))
    89. .version(version)
    90. .build();
    91. }
    92. }

    关于application.properties中的配置:

    1. # 开启Knife4j框架的增强模式
    2. knife4j.enable=true

    注意:

    • 当前项目的Spring Boot版本必须是2.6以下的版本(2.6不可用)
      • 如果要使用更高版本的Spring Boot,必须使用更高版本的Knife4j
    • 在配置类中的basePackage必须是控制器类所在的包,记得需要修改

    完成后,启动项目,通过 /doc.html 即可访问在线API文档。

    在开发实践中,还应该对在线API文档进行细化,需要在控制器及相关类中进行一些配置:

    • 在控制器类上添加@Api注解,配置tags属性,此属性是String类型的
    • 在控制器类中处理请求的方法上添加@ApiOperation注解,配置value属性,此属性是String类型的
    • 在控制器类中处理请求的方法上添加@ApiOperationSupport注解,配置order属性,此属性是int类型的
      • 此属性用于排序,数据越小越靠前,不建议使用1位的数字
    • 在控制器类中处理请求的方法上,不要再使用没有限制请求方式的@RequestMapping,建议使用@GetMapping@PostMapping
    • 如果处理请求的方法中,如果参数是封装的数据类型,应该在此类型的各属性上添加@ApiModelProperty注解,以配置对参数的说明
    • 如果处理请求的方法中,如果参数并没有封装,则需要使用@ApiImplicitParams@ApiImplicitParam这2个注解组合来配置
      • 注意:一旦配置了@ApiImplicitParam,原本的提示的值会被覆盖,应该完整的配置各属性

    完整的配置示例--AlbumController

    1. @Api(tags = "04. 相册管理模块")
    2. @Slf4j
    3. @RestController
    4. @RequestMapping("/albums")
    5. public class AlbumController {
    6. @Autowired
    7. private IAlbumService albumService;
    8. public AlbumController() {
    9. log.info("创建控制器:AlbumController");
    10. }
    11. // 添加相册
    12. // http://localhost:9080/albums/add-new?name=XiaoMi&description=TestDescription&sort=69
    13. @ApiOperation("添加相册")
    14. @ApiOperationSupport(order = 100)
    15. @PostMapping("/add-new")
    16. public String addNew(@Validated AlbumAddNewDTO albumAddNewDTO) {
    17. log.debug("开始处理【添加相册】的请求:{}", albumAddNewDTO);
    18. albumService.addNew(albumAddNewDTO);
    19. return "添加相册成功!";
    20. }
    21. // http://localhost:9080/albums/9527/delete
    22. @ApiOperation("根据id删除相册")
    23. @ApiOperationSupport(order = 200)
    24. @ApiImplicitParams({
    25. @ApiImplicitParam(name = "id", value = "相册id", dataType = "long", required = true)
    26. })
    27. @PostMapping("/{id:[0-9]+}/delete")
    28. public String delete(@PathVariable Long id) {
    29. log.debug("开始处理【删除相册】的请求:id={}", id);
    30. albumService.deleteById(id);
    31. return "删除相册成功!";
    32. }
    33. }

    完整的配置示例--AlbumAddNewDTO

    1. @Data
    2. public class AlbumAddNewDTO implements Serializable {
    3. /**
    4. * 相册名称
    5. */
    6. @ApiModelProperty(value = "相册名称", example = "小米80的相册", required = true)
    7. @NotNull(message = "必须提交相册名称!")
    8. private String name;
    9. /**
    10. * 相册简介
    11. */
    12. @ApiModelProperty(value = "相册简介", example = "小米80的相册的简介", required = true)
    13. @NotNull(message = "必须提交相册简介!")
    14. private String description;
    15. /**
    16. * 自定义排序序号
    17. */
    18. @ApiModelProperty(value = "自定义排序序号", example = "88", required = true)
    19. @NotNull(message = "必须提交自定义排序序号!")
    20. @Range(max = 99, message = "自定义排序序号必须是0~99之间的值!")
    21. private Integer sort;
    22. }

    2.关于响应结果

    当服务器端向客户端响应数据时,除了必要的提示文本以外,还应该响应“业务状态码”到客户端,以便于客户端程序能够便捷且准确的判断当前请求的执行结果!

    另外,某些操作是需要向客户端响应数据的

    所以,向客户端的响应数据至少需要包含以下部分:

    • 业务状态码:本质上是一个数值,由服务器端和客户端共同约定每个数值的意义
    • 业务执行出错时的描述文本
    • 数据:当处理请求成功时,可能需要响应某些数据到客户端(通常是客户端发起GET请求,当然,某些POST请求可能也需要响应数据)

    以上做法应该是针对所有请求都是如此响应的,通常,会自定义某个类型,用于封装以上3种数据,作为处理请求的方法的返回值类型,当响应时,Spring MVC框架会将返回值转换成JSON格式的字符串!

    提示:Spring MVC能够将处理请求的方法的返回值转换成JSON格式的字符串,需要:

    • 此方法是响应正文的
    • 此项目中需要添加jackson-databind依赖
      • 在Spring Boot中,spring-boot-starter-web中包含了此依赖
    • 此方法的返回值类型在Spring MVC中没有默认的Converter(转换器),会自动调用jackson-databind中的Converter,而jackson-databind的处理方法就是将返回值转换成JSON格式的字符串
      • 只要是自定义的数据类型,在Spring MVC中都没有默认的Converter

    例如,在项目的根包下创建web.JsonResult类:

    1. @Data
    2. public class JsonResult implements Serializable {
    3. private Integer state;
    4. private String message;
    5. private Object data;
    6. }

    以上类型,将作为项目中每个处理请求的方法、每个处理异常的方法的返回值类型!

    如果在Service层始终抛出ServiceException,由于使用了统一处理异常的机制,会导致所有异常的业务状态码都是相同的!为了解决此问题,可以:

    • 创建多种异常类型,针对不同的错误,在Service层抛出不同的异常
    • 在Service层每次抛出异常时,向异常对象中封装业务状态码

    如果采取以上第2种做法,则需要将ServiceException调整为:

    1. @Getter
    2. public class ServiceException extends RuntimeException {
    3. private Integer state;
    4. public ServiceException(Integer state, String message) {
    5. super(message);
    6. this.state = state;
    7. }
    8. }

    然后,另外自定义一个接口,用于声明各业务状态码的常量:

    1. public interface ServiceCode {
    2. Integer ERR_CONFLICT = 2;
    3. Integer ERR_NOT_FOUND = 6;
    4. Integer ERR_INSERT = 3;
    5. Integer ERR_UPDATE = 4;
    6. Integer ERR_DELETE = 5;
    7. }

    并且,在抛出异常时,向异常对象中封装以上业务状态码,例如:

    1. String message = "添加相册失败!相册名称【" + name + "】已存在!";
    2. log.warn(message);
    3. throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
    1. this.axios.post(url, data).then(() => {
    2. let data = response.data;
    3. if (data.state == 1) {
    4. // 成功
    5. } else if (data.state == 2) {
    6. // 显示 data.message
    7. }
    8. });
  • 相关阅读:
    SD卡笔记
    微信小程序--》数据绑定和事件绑定
    课程表系列
    16. 如何修改 SAP ABAP OData 模型,使其支持 $expand 操作
    Java知识梳理 第五章 程序控制结构
    SecretFlow学习指南(2)学习路径
    linux c++调试 CMakeLists编写
    【Mysql进阶优化篇02】索引失效的10种情况及原理
    【VSCode】自动生成Jupyter(ipynb)文件的目录
    Git版本控制管理——合并
  • 原文地址:https://blog.csdn.net/TheNewSystrm/article/details/126107976