zoukankan      html  css  js  c++  java
  • SpringBoot系列: 使用 Swagger 生成 API 文档

    SpringBoot非常适合开发 Restful API程序, 我们都知道为API文档非常重要, 但要维护好难度也很大, 原因有:

    1. API文档如何能被方便地找到? 以文件的形式编写API文档都有这个问题, 使用在线 Wiki 等知识平台部分地能解决这个问题.
    2. API文档经常过期. API 接口不断地被改进, 有些项目组使用Word软件编写API文档, 因版本管理难度大, 最后往往是API文档严重过时. 使用 Markdown 格式编写会好一些.


    Swagger 是一个非常好的工具, 用的好能解决上面的两个顽疾. Swagger解决方法也很直接:
    1. 我们的 Restful API项目自动会暴露一个Swagger UI endpoint 来呈现 API 文档, 访问 http://localhost:8080/swagger-ui.html 即可查看API文档.
    2. API 文档是以 Java 注解的形式埋点在代码中, 我们修改Rest API的同时, 顺便就能修改相应的文档注解, Release 新版API.

    Swagger 文档主要包括:
    1. 一个 Docket 摘要信息
    2. 多个 Model 类的说明
    3. 多个 Controller 类的说明


    SpringBoot 可以使用 SpringFox 直接集成 Swagger 功能, SpringFox同时支持 Swagger1.2 和 Swagger2, 推荐使用 Swagger2, 相关文档 http://springfox.github.io/springfox/docs/current/#springfox-spring-mvc-and-spring-boot

    ====================================
    Swagger常用注解
    ====================================
    我们项目在增加了 @EnableSwagger2 之后, swagger 会很为几乎所有的自定义类生成文档信息(当然 swagger 内置一个 ignore 清单), 背后的技术可能是 reflection 吧, 可以想象通过发射机制生成的文档就是一个代码的缩略版, 用处不大.
    要想丰富 swagger 文档, 需要使用它提供的一系列注解, 通过注解表明生成高质量的Api文档,包括接口名、请求方法、参数、返回信息的等等.

    @ApiModel: 修饰 Pojo 类.
    @ApiModelProperty: 修饰 Pojo 类属性

    @Api: 修饰Controller 类, 说明该 controller 的作用
    @ApiOperation: 描述 controller类的一个方法, 说明该方法的作用
    @ApiImplicitParams: Api方法的参数注解, 通常包含多个 @ApiImplicitParam 注解.
    @ApiImplicitParam: 一个具体参数的注解, 该注解需要放在 @ApiImplicitParams 注解内, 该注解的选项有:
            1. paramType 选项: 用来说明参数应该被放置的地方, 有 query/header/pathy/body/form 等取值, query 取值适合于 @RequstParam 参数, header取值适合于@RequestHeader参数, path取值适合于@PathVariable参数, body 取值适合于 @RequestBody 参数.
            2. name 选项: 参数名
            3. dataType 选项: 参数类型
            4. required 选项: 是否必须传
            5. value 选项: 参数值
            6. defaultValue 选项: 参数默认值

    @ApiResponses: 为controller方法增加 HTTP响应整体描述, 通常包含多个 @ApiResponse 注解.
    @ApiResponse: HTTP响应其中一个描述, 该注解需要放在 @ApiResponses 注解内, 该注解的选项有:
            1. code 选项: 即 httpCode 或 httpStatus, 比如 200 等.
            2. message 选项, code 对应的自定义文字说明.

    @ApiIgnore: 让 Swagger 忽略被本注解标注的类/方法/属性. (经我的测试, 2.9.2版不能忽略类).


    ====================================
    pom.xml
    ====================================
    增加 springfox 两个依赖包. 

    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.9.2</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.9.2</version>
    </dependency> 


    ====================================
    新建一个 SwaggerConfig 配置类
    ====================================
    在项目中需要增加一个 Swagger Config 类, 该类需要加上 @EnableSwagger2 注解, 在该类中需要声明一个 Docket bean, Docket 这个词我理解应该是 DocumentLet 的缩写, 相当于API文档的摘要信息.

    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
    
        /*
         * Docket 是 DocumentLet 的缩写, 相当于摘要
         */
        @Bean
        public Docket createRestApi() {
            Docket docklet = new Docket(DocumentationType.SWAGGER_2).apiInfo(metaData())
                    .select()
                    // apis() 作用是通过 basePackage 或 withClassAnnotation 来指定swagger扫描的类的范围
                    .apis(RequestHandlerSelectors.basePackage("com.example.demo"))
                    // paths() 是通过路径的方式来指定swagger扫描的类的范围
                    .paths(PathSelectors.any())
                    .build();
     
            return docklet;
        }
    
        private ApiInfo metaData() {
            return new ApiInfoBuilder().title("Spring Boot中使用Swagger2构建RESTful APIs")
                    .description("学习使用 Swagger2 ")
                    .contact(new Contact("author name", "http://about.me", "email@email.com"))
                    .version("1.0")
                    .build();
        }
    }
    
    /*
     *
     * //如果集成了 Spring Security , 需要加一个Spring Security配置类允许访问 swagger 相关资源
     *
     * @Configuration public class SpringSecConfig extends
     * WebSecurityConfigurerAdapter {
     *
     * @Override protected void configure(HttpSecurity httpSecurity) throws
     * Exception {
     * httpSecurity.authorizeRequests().antMatchers("/","/swagger-resources").
     * permitAll(); httpSecurity.csrf().disable();
     * httpSecurity.headers().frameOptions().disable(); } }
     */


    ====================================
    Pojo 类
    ====================================
    Pojo 类加上 @ApiModel 注解, 仅仅是能增加点 description 选项. 每个属性可以用 @ApiModelProperty 注解.

    @ApiModel(description="Product model object")
    class Product {
        @ApiModelProperty(notes = "The application-specific product id", dataType = "String")
        private String productId;
        @ApiModelProperty(notes = "The product description")
        private String description;
        @ApiModelProperty(notes = "The price of the product", required = true, dataType = "Decimal")
        private BigDecimal price;
    
        public Product() {
        }
    
        public static Product getEmptyProduct() {
            Product product = new Product();
            product.setProductId("===empty===");
            return product;
        }
    
        public Product(String productId, String description, BigDecimal price) {
            this.productId = productId;
            this.description = description;
            this.price = price;
        }
    
       //省略 getter/setter 
    }


    ====================================
    Controller 类
    ====================================
    Controller 类是 API 文档的重点, 使用 @Api 注解类, 使用 @ApiOperation/@ApiResponses/@ApiImplicitParams 来注解方法.

    @RestController
    @RequestMapping("/product")
    @Api(tags = "Product Controller", description = "Operations pertaining to products in online store")
    class ProductController {
        private ProductService productService;
    
        @Autowired
        void setProductService(ProductService productService) {
            this.productService = productService;
        }
    
        @ApiOperation(value = "view of list of available products", response = Iterable.class)
        @ApiResponses(value = { @ApiResponse(code = 200, message = "Sucessfully retrieve list"),
                @ApiResponse(code = 401, message = "You are not authorized to view the resource"),
                @ApiResponse(code = 403, message = "Accessing the resource you were trying to reach is forbidden") })
        @RequestMapping(value = "/list", method = RequestMethod.GET, produces = "application/json")
        public Iterable<Product> list(Model model) {
            return productService.listAllProducts();
        }
    
        @ApiOperation(value = "Search a product by productId", response = Product.class)
        @RequestMapping(value = "/show/{productId}", method = RequestMethod.GET, produces = "application/json")
        public Product showProduct(@PathVariable String productId, Model model) {
            Optional<Product> optional = productService.getProductById(productId);
            return optional.orElse(Product.getEmptyProduct());
        }
    }

    ====================================
    Service 类
    ====================================
    这里 Service 有一个 ProductService 接口和 ProductServiceImpl 实现类, 它们和 swagger 没有关系.

    /*
     * Product Service 接口
     */
    interface ProductService {
        Iterable<Product> listAllProducts();
    
        Optional<Product> getProductById(String productId);
    
        Product saveProduct(Product product);
    
        void deleteProduct(String productId);
    }
    
    /*
     * Product Service 的实现类
     */
    @Service
    @Scope("singleton")
    class ProductServiceImpl implements ProductService {
        private static List<Product> productStore = new ArrayList<Product>();
    
        public ProductServiceImpl() {
            productStore.add(new Product("Product1", "About Product1", new BigDecimal("1")));
            productStore.add(new Product("Product2", "About Product2", new BigDecimal("2")));
            productStore.add(new Product("Product3", "About Product3", new BigDecimal("3")));
        }
    
        @Override
        public Iterable<Product> listAllProducts() {
            return productStore;
        }
    
        @Override
        public Product saveProduct(Product product) {
            deleteProduct(product.getProductId());
            productStore.add(product);
            return product;
        }
    
        @Override
        public Optional<Product> getProductById(String productId) {
            return productStore.stream()
                    .filter(p -> productId.equals(p.getProductId()))
                    .findFirst();
        }
    
        @Override
        public void deleteProduct(String productId) {
            productStore.removeIf(p -> p.getProductId()
                    .equals(productId));
        }
    }
    View Code

    ====================================
    测试效果
    ====================================
    访问 http://localhost:8080/swagger-ui.html


    ====================================
    参考
    ====================================
    https://springframework.guru/spring-boot-restful-api-documentation-with-swagger-2/
    https://www.jianshu.com/p/8033ef83a8ed
    https://www.jianshu.com/p/be05aa96fd29

  • 相关阅读:
    [轉]Linux kernel <2.6.29 exit_notify() local root exploit分析(2009-1337)
    [轉]udp_sendmsg空指针漏洞分析 by wzt
    linux 中mmap的用法
    [轉]Exploit The Linux Kernel NULL Pointer Dereference
    [轉]Exploit Linux Kernel Slub Overflow
    Linux 2.6.x fs/pipe.c local kernel root(kit?) exploit (x86)
    字符串哈希专题
    树形DP
    ACM中的正则表达式
    回文树学习笔记
  • 原文地址:https://www.cnblogs.com/harrychinese/p/springboot_swagger.html
Copyright © 2011-2022 走看看