【问题标题】:Swagger: Spring MVC models in GET requestSwagger:GET 请求中的 Spring MVC 模型
【发布时间】:2017-12-10 14:38:11
【问题描述】:

在 MVC 中,您会期望控制器接收模型作为输入并生成模型作为输出。在 Swagger 中,后者不是问题,但我对前者有问题。我不明白如何让 Swagger 从传入的 GET 参数构建输入模型。

考虑:

"paths": {
    "/search": {
        "get": {
            "consumes": [],
            "produces": [
                "application/json"
            ],
            "parameters": [
                // What goes here?
            ],
            "responses": {
                "200": {
                    "description": "Success",
                    "schema": { 
                        "$ref": "#/definitions/SearchResponse"
                    }
                },
            }
        }
    }
}

如何使生成的控制器的方法具有如下签名:

    public ResponseEntity<ResultModel> controllerGet(ModelFromParameters input);

其中 ModelFromParameters 会有几个字段对应不同的 GET 参数。

示例主要关注 POST 请求或 GET 请求,其中 20 多个参数中的每一个都填充在方法的参数列表中,这显然是反 MVC。

所讨论的 API 是一个复杂的无状态查询系统,有很多参数。

【问题讨论】:

  • 这应该可以正常工作。只要参数不是@RequestBody@RequestPart。或者,如果您想显式地使用 @ModelAttribute 注释参数将导致所需的行为
  • @DilipKrishnan 在 Spring MVC 中会,但我将如何使用 Swagger 对其进行建模?
  • @DilipKrishnan 也不是 @RequestBody@RequestPart 都是 POST 而不是 GET?
  • 在设计优先的方法中使用 swagger 时,您不能,也不确定为什么需要这样做。
  • true 是一般性评论

标签: java spring-mvc get swagger


【解决方案1】:

假设:您希望创建一个对象作为服务方法的参数,但仍将对象的每个字段作为实际 http 请求中的查询参数传递,并且能够以 swagger 记录各个字段。

例如获取http://localhost:8080/search?parameter1=value1&parameter2=value2

典型的服务方法定义,其中每个查询参数都定义为实际方法中的参数

@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<List<String>> search(@RequestParam parameter1, @RequestParam parameter2) {
...
}

使用带有 @ModelAttribute 注释的 Object(a.k.a Bean)修改了具有单个参数的服务方法。虽然它是一个对象,但就 REST API 而言,它仍然与上面相同。

@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<List<String>> search(@ModelAttribute FormParam formParam) {
...
}

FormParam 类。您可以使用 @ApiParam

记录每个字段
public class FormParam {
    @ApiParam(value = "parameter1 - description here", required = true)
    private String parameter1;
    @ApiParam(value = "parameter2 - description here", required = true)
    private String parameter2;
    //define getter setters below
}

这就是它在招摇中的表现

这是生成的 swagger.json sn-p

"paths": {
    "/search": {
        "get": {
            "tags": ["search-service"],
            "summary": "Search with Object as parameter",
            "description": "Search with Object as parameter",
            "operationId": "searchUsingGET",
            "consumes": ["application/json"],
            "produces": ["*/*"],
            "parameters": [{
                "name": "parameter1",
                "in": "query",
                "description": "parameter1 - description here",
                "required": true,
                "type": "string"
            },
            {
                "name": "parameter2",
                "in": "query",
                "description": "parameter2 - description here",
                "required": true,
                "type": "string"
            }],
            "responses": {
                "200": {
                    "description": "OK",
                    "schema": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    }
                },
                "401": {
                    "description": "Unauthorized"
                },
                "403": {
                    "description": "Forbidden"
                },
                "404": {
                    "description": "Not Found"
                }
            }
        }
    },

如果您手动创建 swagger.json,则可以记录查询参数

"parameters": [{
    "name": "parameter1",
    "in": "query",
    "description": "parameter1 - description here",
    "required": true,
    "type": "string"
},
{
    "name": "parameter2",
    "in": "query",
    "description": "parameter2 - description here",
    "required": true,
    "type": "string"
}],

【讨论】:

  • 我将如何在 Swagger 的 swagger.json 中建模?那么该代码将由此生成,JSON-first?
  • @alamar,我已经用生成的 swagger.json 更新了答案。
  • 我看不出这个 swagger.json 不会生成带有两个原始参数的控制器方法。
  • 你用的是什么版本的swagger?它是从注释自动生成的,还是您手动编辑 swagger.json?
  • Swagger 只是一个文档。它与使用两个原始参数生成控制器方法无关。 Spring 基本上通过 @ModelAttribute 注释解决了这个问题,并将这些请求参数映射到 bean 而不是单个参数。
【解决方案2】:

我认为你不能。对于列表页面+搜索,我也有类似的问题,使用 GET 和正文。没有办法让大摇大摆地代表这一点,即使它在 Tomcat 中也有效; Elasticsearch 也支持它。看起来没有计划大摇大摆地改变这方面。我采用招摇将两者分开:list-without-search 为 GET,list+search 为 POST,只是为了将页面放入 swagger 文档中,如果后者实际上也可以作为 GET。

我没有使用 swagger 代码生成的经验,但是,如果您的配置使用 POST 生成了您期望的结果,但使用 GET 没有生成,那么您可能遇到了同样的限制。

https://github.com/swagger-api/swagger-ui/issues/2867

https://github.com/swagger-api/swagger-ui/issues/2136

https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.md#operationRequestBody

仅在 HTTP 1.1 规范 RFC7231 明确定义了请求正文语义的 HTTP 方法中才支持 requestBody。在 HTTP 规范含糊不清的其他情况下,requestBody 应被消费者忽略。

【讨论】:

  • 我没有使用 GET 和 body。叹息。
  • 我认为它在正文中,因为 AFAIK 无法通过参数发送复杂类型的值,只能在请求正文中。 stackoverflow.com/a/39194484/1536382
  • 叹息。我不需要发送复杂的类型值。我想将简单的值作为简单的查询参数发送,并从中制作一个简单的普通模型对象。这里没有什么复杂的,除了我有超过 10 个查询参数,所以不将它们作为方法参数是完全有意义的。
  • 啊,你希望 spring mvc 的 swagger 生成器有一个选项来实现将所有请求参数(在 swagger conf 中定义)绑定到对象而不是方法参数,使用 @ 中描述的 spring 特性987654326@ (并且可能也有 swagger 生成对象)?
  • 正是这样!我最终删除了 Swagger 生成的控制器,因为我从来没有让它工作。
【解决方案3】:

通常,http 服务器(例如 tomcat、jetty)不会接受 get 请求中的正文消息。如果客户端需要通过 http get 方法向服务器传递参数,它应该使用 query string 。 '?' 之后的 URL 的最后一部分特点。查询字符串详情可以看query string

但是在 spring mvc 的帮助下,查询字符串中的 http 请求参数将绑定到控制器方法参数的字段。所以看起来客户端向服务器端传递了一个 pojo 参数。

参数部分应如下所示:

"parameters" : [ {
      "name" : "age",
      "in" : "query",
      "required" : false,
      "type" : "integer"
    }, {
      "name" : "firstName",
      "in" : "query",
      "required" : false,
      "type" : "string"
    }]

请注意,“in”字段的值为“query”。这意味着参数是通过查询字符串传递的。

【讨论】:

  • 您在问题描述中的什么地方看到过有关正文的信息?它只是反复谈论参数。有一个长的非结构化参数“胡须”正是我在这里试图避免的,而是希望从所有这些参数中创建一个模型对象。
  • 对不起,中止冗长无用的描述。但请耐心阅读全文。你想要的答案就在那里。
  • 如何在 Swagger 中生成它?因为默认情况下,它会为这种情况生成一个带有两个参数的方法。就像serviceGet(int age, String firstName),这不是我们想要的。
【解决方案4】:

我想你需要的是在请求正文中发布你的参数,它是这样的:

...
{
  "name": "files",
  "in": "body",
  "required": true,
  "schema": {
    "type": "array",
    "items": {
      "$ref": "#/definitions/FileRequest"
    }
  }
}

翻译为:

public Response storageFilePost(
            @NotEmpty(message = "systemID is required!") @QueryParam("systemID") final String systemID,
            @NotNull(message = "qParam is required!") @QueryParam("qParam") final Long qParam,
            @NotNull(message = "files are required!") final List<FileRequest> files) {

【讨论】:

  • 不,它不需要在请求正文中发布我的论点。我一直在写关于 GET 和查询参数的问题。
  • 重新阅读问题几次后,我认为没有简单的方法可以解决这个问题。最好的选择是提供所有查询输入的工厂类。
  • @PanBramor 基本问题是否可以使用 Swagger 进行建模
  • 那么答案是否定的。 swagger 只允许查询中的原始类型,并且从中生成一个对象远不及它的能力,你所提议的基本上是在两者之间生成一个客户端。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-21
  • 1970-01-01
  • 1970-01-01
  • 2020-12-11
  • 2011-04-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多