大摇大摆地从属性文件中读取文档

时间:2019-11-22 17:01:12

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


我试图让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)中插入值?

2 个答案:

答案 0 :(得分:2)

如错误消息所述,属性值必须为常量,并且Spring无法将值注入静态final字段。同样,也无法在类级别之外插入值(即@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}语法。根据{{​​3}}版本2.7起的文档,以下字段是可能的:

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

答案 1 :(得分:2)

有一种解决方法。但是您需要为此附加依赖项- springfox

您可以编写一个插件,该插件将从外部文件中向@ApiOperation description字段中注入文本。我在项目中使用它来注入Markdown文件。 Swagger支持markdown,并且非常方便,因为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 一起使用。

尝试一下。