Swagger使用————接口参数注解的使用缺陷

问题描述

在使用springboot开发web项目时,用到了swagger框架,来生成web api文档。但是其中有一项是举例说明参数的结构,如下图:


但是,这个功能真的是非常方便,因为可以让前端开发人员第一时间得知参数的内部结构是什么样的,这尤其适用于那些json体结构的参数。网上的例子都是这样的:


但是,我无论如何都弄不出来这个样子,前前后后研究了有好几个小时。

终于找出了问题。

问题原因

网上的api接口中,几乎全是传入一个完整的Java Bean对象,而不是传JsonObject对象。

我的代码是这样:

    @ApiOperation(value = "添加景区下的特价门票", notes = "{\"scenicIdArr\" : [53361,53356]}")@PostMapping(value = "/special_price/add")public JSONObject addSpecialPrice(@RequestBody JSONObject scenicIdArr) {return sprSvc.addSpecialPrice(scenicIdArr);}

别人的代码是这样:

    @ApiOperation("更改用户信息")@PostMapping("/updateUserInfo")public int updateUserInfo(@RequestBody @ApiParam(name="用户对象",value="传入json格式",required=true) User user){int num = userService.updateUserInfo(user);return num;}

经过比较,很容易就发现了问题,我的接口中的参数是无法得知内部数据结构的JSONObject类型,而别人的参数是一个已知其内部数据结构的User对象。

既然知道了原因,那我也将接口进行了一些修改:

创建一个符合我业务要求的数据结构实体类,然后将这个实体类作为参数传入接口中:

    @ApiOperation(value = "添加景区下的特价门票", notes = "{\"scenicIdArr\" : [53361,53356]}")@PostMapping(value = "/special_price/add")public JSONObject addSpecialPrice(@RequestBody ScenicIdArr scenicIdArr) {return null;}@ApiModelclass ScenicIdArr {@ApiModelProperty(value = "景区id数组")int[] scenicIdArr;}

上述代码中,我定义了一个成员内部类,并将实体类以@ApiModel进行注解。效果如下:


呵呵,没有一丁点效果!我陷入了沉思... ...

于是我大胆的猜想:swagger框架可能是自动调用了get或set方法,并完成页面渲染。

于是我又修改了代码:

@ApiOperation(value = "添加景区下的特价门票", notes = "{\"scenicIdArr\" : [53361,53356]}")@PostMapping(value = "/special_price/add")public JSONObject addSpecialPrice(@RequestBody ScenicIdArr scenicIdArr) {return null;}@ApiModelclass ScenicIdArr {@ApiModelProperty(value = "景区id数组")int[] scenicIdArr;public int[] getScenicIdArr() {return scenicIdArr;}}

我加了一个get方法,来获取实体类中的属性,看一下效果:


上图中可以看到,不论是整体的实体类结构,还是字段上的注释“景区id数组”都很好的显示了出来。这样,我们在页面点击小黄框的时候,就可以将数据自动的加载到参数填写的白框内。


这样,我们省去了手动书写结构和key值的过程,而只需要我们输入具体的value值即可。

由于本篇博客并不是教你如何使用spring-boot-starter-swagger自动依赖配置模块中的各种注解如何使用,因此,此处只是简单解析了一下接口参数的模板生成方式。

但是,题目中既然提到了这个功能的缺陷,就不得不回过头来吐槽一下这个破JB玩意儿!

吐槽一下

这个在小黄框显示对外接口参数结构的功能真的应该说是非常实用的一个功能,我并不知道这个功能具体的名称是什么,暂且就称它为“参数样例功能”。

为什么说这个功能非常实用?

首先,书写简便。REST接口风格的参数多以json结构体传输数据,而这样一个自动生成结构体的功能,可以为我们免去书写大量括号、冒号、逗号、引号、空格等json体的必须元素,而且自动排版,避免手写出错,达到零错误。在真正通过页面的api接口测试的时候,只需要简单输入几个value值就可以“try it out”了,着实提高了不少效率。

其次,方便前端开发。我们都知道,不论是传入JavaBean对象,还是传入没有在后端强制类型约束的Json字符串,前端调用controller中的接口时,仅仅是传入一个key-value的结构,才不会管你什么JavaBean。对于springboot,其一系列内嵌的HttpMessageConverter会将json结构转化成对应的JavaBean,再交给Controller。前端开发人员甚至可以将小黄框内的内容,直接拷贝过来,稍作修改(value赋值)即可完成对后端接口对接的全部编码。

第三,覆盖了其他部分注解。个人认为,swagger中的注解关于参数注释方面,有些重复,这一点不做展开讨论,且仅仅是个人观点,可以参考官方api文档体会一下。另外关于response一类的注解,完全没有必要。返回值是什么结构的,完全可以通过“try it out”调用一次接口即可了解到。估计swagger开发团队考虑到功能的完整性,或者在后端由于某种原因导致接口不可用而做的一种补足方案(比如,数据库中暂无数据等原因)。

虽然这个功能实用,但是依然存在一个很别扭的情况。

那就是,我们不得不因为要在“参数样例功能”中展示我们的参数结构而创建一个Java Bean。不论这个Java Bean在后台逻辑中有无实际意义。

就比方说我之前的那个接口:

    @ApiOperation(value = "添加景区下的特价门票", notes = "{\"scenicIdArr\" : [53361,53356]}")@PostMapping(value = "/special_price/add")public JSONObject addSpecialPrice(@RequestBody JSONObject scenicIdArr)

我需要拿到一个有景区id组成的json体的数据结构,然后跑到service中去处理,可能我的这种api结构并不规范,但是不可能不存在这样一种情况:仅仅规定一个json结构,而不是Java Bean来作为参数进行处理。(抱歉,最近在看《Thinking In Java》句子写起来有那么一点模仿布鲁斯埃克尔的腔调)

我查找了很多资料,包括官方的API说明,并没有很好解决方案。于是,才有了后面的成员内部类的出现。但是这种代码除了方便测试以外完全没有实际意义。如果为每个以json结构体作为参数的接口另起一个class文件去明确传入参数的结构,就显得有些愚蠢。它会使你的代码非常的臃肿和凌乱。

这就是我说的swagger的这个缺陷,以纯json结构体作为参数的接口,无法实现非常重要的“参数样例功能”

综上,就是我对swagger框架的一点看法和总结,如有疑问,欢迎文末留言。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558999.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分布式事务最终一致性常用方案

分布式事务最终一致性常用方案目前的应用系统,不管是企业级应用还是互联网应用,最终数据的一致性是每个应用系统都要面临的问题,随着分布式的逐渐普及,数据一致性更加艰难,但是也很难有银弹的解决方案,也并…

数据列表的分页实现————分页敏捷开发

概要 分页功能是比较常见的基础功能,虽然比较简单,但是每次需要用到这个功能的时候还是需要现写一遍。为了实现更加宏观的业务复用,特将本人特别喜欢的简易分页逻辑在此记述,以备日后重用。 逻辑描述 一般的分页实现方式多是通…

Java基础————理解Integer对象的缓存策略

一个简单的面试题public static void main(String[] args) {Integer in1 100;Integer in2 100;Integer in3 200;Integer in4 200;System.out.println(in1 in2);System.out.println(in3 in4);} 运行结果: true false 从自动装箱谈Integer缓存 上述面试题中&…

Java面试日常总结大杂烩

日常总结大杂烩:一。 取出特定行数的数据1. select* from 表名 limit m,n; 2. select * from 表名 limit [offset,] rows;1. m代表从m1条记录行开始检索,n代表取出n条数据。(m可设为0)如:select * from表名 limit 6,5…

Eclipse深度患者设置VSCode快捷键

VSCode设置Eclipse中常用的快捷键 将eclipse中一些基本的快捷键输入右侧用户快捷键设置中: // Place your key bindings in this file to overwrite the defaults [{ "key": "alt/", "command": "editor.action.triggerSugges…

Java基础日常总结!!

Java基础日常总结!!1. Java的字符类型采用的是Unicode编码方案,每个Unicode码占用( )个比特位 在java中一个unicode占2个字节(byte).一个字节等于8比特位(bit).所以每个Unicode码占用 16 个比特…

NodeJS学习————关于let和const命令的使用理解

let的基本用法 在新的js规范ES6中,新增了let 命令,用来声明变量。用法类似于var,但不同的是所声明的变量,只在let 命令所在的代码块内有效。 { let a 10; var b 10; } //ReferenceError: a is not defined console.log(a …

forward和redirect的区别是什么?

forward和redirect是什么? 是servlet种的两种主要的跳转方式。forward又叫转发,redirect叫做重定向。 区别:(本地效应次数) 地址栏,数据共享,应用场景,效率,本质&…

MYSQL的索引类型:PRIMARY, INDEX,UNIQUE,FULLTEXT,SPAIAL 有什么区别?各适用于什么场合?

一、MySQL索引类型 MySql常见索引类型有:主键索引、唯一索引、普通索引、全文索引、组合索引 PRIMARY KEY(主键索引) ALTER TABLE table_name ADD PRIMARY KEY ( column ) UNIQUE(唯一索引) ALTER TABLE table_name ADD UNIQUE (colu…

Servlet入门总结

一、了解Servlet的概念Servlet定义:Servlet是基于Java技术的Web组件,由容器管理并产生动态的内容。Servlet引擎作为WEB服务器的扩展提供支持Servlet的功能。Servlet与客户端通过Servlet容器实现的请求/响应模型进行交互。 注意:Servlet不是从…

MySQL日期类型的处理总结

一、概述 MySQL中的日期类型包括以下5种: 类型大小 (字节)范围格式用途DATE31000-01-01/9999-12-31YYYY-MM-DD日期值TIME3-838:59:59/838:59:59HH:MM:SS时间值或持续时间YEAR11901/2155YYYY年份值DATETIME81000-01-01 00:00:00/9999-12-31 23:59:59YYYY-MM-DD HH:…

详解HTTP协议~~~

详解HTTP协议~~~HTTP 简介HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。。HTTP是一个基于TCP/IP通信协议来传递数据(…

MyBatis基础知识概述

一、依赖配置 添加依赖即可&#xff0c;jar包或pom依赖&#xff1a; <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>x.x.x</version> </dependency> 二、SqlSessionFactory 2.1 什…

Mybatis Plus————代码生成器

代码生成器 MyBatis Plus是MyBatis的扩展框架&#xff0c;而代码生成器是MP的核心功能之一&#xff0c;另外还有 “条件构造器”和“通用CRUD”等功能。 步骤演示 mp的代码生成器有两种方式自动生成代码&#xff0c;一种是通过main方法来执行程序&#xff0c;另一种是通过maven…

Spring MVC 流程图解析

Spring MVC 流程图解析Spring MVC工作流程图图一图二 SpringMVC工作流程描述DispatcherServlet&#xff0c;HandlerMapping&#xff0c;HandlerExecutionChain&#xff0c;HandlerAdapter&#xff0c;HttpMessageConveter&#xff0c;BindingResult&#xff0c;ModelAndView&am…

Java并发编程实战————可重入内置锁

引言 在《Java Concurrency in Practice》的加锁机制一节中作者提到&#xff1a; Java提供一种内置的锁机制来支持原子性&#xff1a;同步代码块。“重入”意味着获取锁的操作的粒度是“线程”&#xff0c;而不是调用。当某个线程请求一个由其他线程持有的锁时&#xff0c;发出…

java的守护进程与非守护进程

java的守护进程与非守护进程 最近重新研究Java基础知识&#xff0c;发现以前太多知识知识略略带过了&#xff0c;比较说Java的线程机制&#xff0c;在Java中有两类线程&#xff1a; User Thread(用户线程)、Daemon Thread(守护线程) &#xff0c;&#xff08;PS:以前忽略了&a…

双剑合璧————Spring Boot + Mybatis Plus

引言 最近在学习Mybatis Plus的使用&#xff0c;希望通过spring boot快速将mybatis plus整合进来。 对于springboot项目&#xff0c;mybatis plus团队也有自己的启动器 &#xff1a;mybatis-plus-boot-starter。这个依赖内部已经整合了mybatis-spring&#xff0c;也包括非快速…

Java中常用的类,包,接口

Java中常用的类&#xff0c;包&#xff0c;接口包名说明java.lang该包提供了Java编程的基础类&#xff0c;例如 Object、Math、String、StringBuffer、System、Thread等&#xff0c;不使用该包就很难编写Java代码了。java.util该包提供了包含集合框架、遗留的集合类、事件模型、…

Collection框架介绍

Collection&#xff1a;List列表&#xff0c;Set集&#xff0c; Map&#xff1a;Hashtable&#xff0c;HashMap&#xff0c;TreeMapCollection 是单列集合 List 元素是有序的、可重复 有序的 collection&#xff0c;可以对列表中每个元素的插入位置进行精确地控制。 可以根据…