【问题标题】:swagger read documentation from properties file大摇大摆地从属性文件中读取文档
【发布时间】:2020-03-18 18:55:12
【问题描述】:


我试图让 Swagger 从属性文件 swagger.properties 中读取 API 文档,但不能。在@ApiOperation 注释中有一个错误说:Attribute value must be constant。有关如何解决此问题并能够从属性文件中读取文档的任何建议?
这是控制器代码:

package com.demo.student.demo.controller;

import com.demo.student.demo.entity.Student;
import com.demo.student.demo.service.StudentService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping(value = "/v1/students")
@Api(description = "Set of endpoints for Creating, Retrieving, Updating and Deleting of Students.")
public class StudentController {
    private final String message;

    public StudentController(@Value("${test.swagger.message}") String message){
        this.message=message;
    }

    @Autowired
    private StudentService studentService;

    @GetMapping
    @ApiOperation(message)
    public List<Student> findAll(){
        return studentService.findAl();
    }

}

另外,我如何在@API(description) 中注入类级别的值?

【问题讨论】:

    标签: spring spring-boot swagger swagger-ui openapi


    【解决方案1】:

    有一个解决方法。但是你需要一个额外的依赖 - springfox

    您可以编写一个插件,将来自外部文件的文本注入到您的 @ApiOperation description 字段中。我在我的项目中使用它来注入降价文件。它非常方便,因为 Swagger 支持 markdown,并且每个端点都有一个单独的文件,让您有机会编写广泛的 API 描述(如果您使用 IntelliJ IDEA 或类似工具,也可以在 markdown 编辑器中)。

    这是你需要的代码:

    1. 为您要提供描述的每个端点的自定义注释 (@ApiDescription)。注释的值将是您的降价文件或属性文件的文件路径。稍后插件将在提供的文件路径中查找文件并将描述设置为文件的内容。

      @Target({ ElementType.METHOD })
      @Retention(RetentionPolicy.RUNTIME)
      public @interface ApiDescription {
          String value() default "";
      }
      
    2. 插件本身。这是一个可扩展点。在这种情况下,我们希望稍后交换或设置@ApiOperation 注释的描述值。查看Springfox Plugins

      ...
      
      import springfox.documentation.spi.DocumentationType;
      import springfox.documentation.spi.service.OperationBuilderPlugin;
      import springfox.documentation.spi.service.contexts.OperationContext;
      import springfox.documentation.spring.web.DescriptionResolver;
      
      ...
      
      @Component
      public class ApiDescriptionPlugin implements OperationBuilderPlugin {
      
          private final DescriptionResolver resolver;
      
          @Autowired
          public ApiDescriptionPlugin(DescriptionResolver resolver) {
              this.resolver = resolver;
          }
      
          @Override
          public void apply(OperationContext context) {
      
              Optional<ApiDescription> descOptional = context.findAnnotation(ApiDescription.class);
              boolean hasText = descOptional.isPresent() && StringUtils.hasText(descOptional.get().value());
              if(!hasText) {
                  return;
              }
      
              final String file = descOptional.get().value();
              final URL url = Resources.getResource(file);
      
              String description;
              try {
                  description = Resources.toString(url, StandardCharsets.UTF_8);
              } catch(IOException e) {
                  log.error("Error while reading markdown description file {}", file, e);
                  description = String.format("Markdown file %s not loaded", file);
              }
              context.operationBuilder().notes(resolver.resolve(description));
          }
      
          @Override
          public boolean supports(DocumentationType type) {
              return true;
          }
      }
      
    3. 只需用@ApiDescription("/notes/auth/login.md") 注释端点(文件必须在resources 文件夹中)

    您可以调整此示例以使用属性文件(我不知道您的结构是什么样的以及您如何分隔不同的 API 描述)。这种使用 markdown 文件的解决方法对于编写大量描述并使它们远离实际代码非常有用。

    它适用于 Swagger 2.0

    试一试。

    【讨论】:

    • 这就是我想要的!非常感谢@Vladas。如果可以的话,我会在你和 Janar 之间分享赏金。你们帮了我很多!真是无语!我试过了,为我工作。
    • @Janar 检查这个。
    【解决方案2】:

    正如错误消息所说,属性值必须是常量,并且 Spring 不能将值注入静态最终字段。同样,在类级别之外注入值也是不可能的(即@Api注解的描述)

    一种解决方法是创建一个只有常量的类,这些常量都是final static Strings,就像这样

    public final class Constants {
      public static final String API_DESCRIPTION = "description";
      public static final String FIND_ALL_MESSAGE= "message";
    }
    

    并在控制器中使用它

    @Api(description = Constants.API_DESCRIPTION)
    public class StudentController {
       @ApiOperation(Constants.FIND_ALL_MESSAGE)
        public List<Student> findAll(){...}
    }
    

    然而,对于 Swagger,对于某些字段,可以使用 ${key} 语法。根据https://springfox.github.io/springfox/docs/current/#property-file-lookup 的文档,自 2.7 版以来,以下字段可能是:

    @ApiParam#value()
    @ApiImplicitParam#value()
    @ApiModelProperty#value()
    @ApiOperation#value()
    @ApiOperation#notes()
    @RequestParam#defaultValue()
    @RequestHeader#defaultValue()
    

    【讨论】:

    • 如何将 swagger.properties 文件中的值注入到 Constants 类中,而不是在类本身中对其进行硬编码?
    • 如前所述,Spring 无法将值注入静态最终字段。
    • 没有工作机会?我读到 swagger 可以从属性文件中读取值。
    • 据我所知,没有
    • 构造函数注入呢。我读了它可以用来分配最终字段吗? @贾纳尔
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-12
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    相关资源
    最近更新 更多