• 如何基于SpringBoot搭建Swagger接口文档
  • 发布于 2个月前
  • 222 热度
    0 评论
前言
平时做接口测试接触最多的就是Swagger,之前还用过 YApi,但YApi被爆出漏洞后,就被我们开发抛弃了。最近对swagger的搭建有一定兴趣,所以实践了一下。

操作
1、导入依赖
        <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>
2、编写Swagger配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;
import java.util.List;

/**
 * @堆代码 duidaima.com
 * @date 2023/2/28 16:20
 */


@Configuration
@EnableSwagger2
public class SwaggerConfig {


    /**
     * 设置多个:
     *
     * @return
     * @Bean public Docket appApi() {
     * <p>
     * List<Parameter> pars = new ArrayList<>();
     * ParameterBuilder token = new ParameterBuilder();
     * token.name("token").description("用户令牌").modelRef(new ModelRef("string")).parameterType("header").required(false)
     * .build();
     * pars.add(token.build());
     * <p>
     * return new Docket(DocumentationType.SWAGGER_2).select().paths(regex("/app/.*")).build()
     * .globalOperationParameters(pars).apiInfo(pdaApiInfo()).useDefaultResponseMessages(false)
     * .enable(enableSwagger)
     * .groupName("appApi");
     * <p>
     * }
     * @Bean public Docket adminApi() {
     * <p>
     * List<Parameter> pars = new ArrayList<>();
     * ParameterBuilder token = new ParameterBuilder();
     * token.name("token").description("用户令牌").modelRef(new ModelRef("string")).parameterType("header").required(false)
     * .build();
     * pars.add(token.build());
     * return new Docket(DocumentationType.SWAGGER_2).select().paths(regex("/admin/.*")).build()
     * .globalOperationParameters(pars).apiInfo(pdaApiInfo()).useDefaultResponseMessages(false)
     * .enable(enableSwagger)
     * .groupName("adminApi");
     * <p>
     * }
     */

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
                .apis(RequestHandlerSelectors.basePackage("com.xcj.jmeterdemo.controller")).paths(PathSelectors.any())
                .build().globalOperationParameters(setHeaderToken());

    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder().title("action-swagger").description("swagger接口文档").termsOfServiceUrl("")
                .version("1.0").build();
    }

    /**
     * @param
     * @Description: 设置swagger文档中全局参数
     * @Date: 2020/9/11 10:15
     * @return: java.util.List<springfox.documentation.service.Parameter>
     */

    private List<Parameter> setHeaderToken() {
        List<Parameter> pars = new ArrayList<>();
        ParameterBuilder userId = new ParameterBuilder();
        userId.name("token").description("用户TOKEN").modelRef(new ModelRef("string")).parameterType("header")
                .required(true).build();
        pars.add(userId.build());
        return pars;
    }

}
3、为VO、DTO添加注解
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
 * @堆代码 duidaima.com
 */
@Data
@ApiModel("订单对象")
public class OrderDto {
    @ApiModelProperty("订单号")
    private String orderId;
    @ApiModelProperty("商品名称")
    private String productName;
    @ApiModelProperty("商品数量")
    private int productNumber;
}
package com.xcj.jmeterdemo.vo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
 * @堆代码 duidaima.com
 * 
 */
@Data
@ApiModel("统一响应结果")
public class ResultVo<T> {

    @ApiModelProperty("响应码")
    private int code;
    @ApiModelProperty("响应信息")
    private String msg;
    @ApiModelProperty("响应对象")
    private T data;

}
4、为Controller添加注解
package com.xcj.jmeterdemo.controller;

import com.xcj.jmeterdemo.entity.OrderDto;
import com.xcj.jmeterdemo.entity.ProductDto;
import com.xcj.jmeterdemo.enums.AllEnum;
import com.xcj.jmeterdemo.vo.ResultVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Controller
@Api(value = "乱七八糟的接口集",tags = {"乱七八糟的接口集"})
public class MainController {

    final String TOKEN = "SnhHsOcabQ66CeaI";

    Map<String, Integer> productMap = new HashMap<String, Integer>() {{
        put("牛奶", Integer.valueOf("1"));
    }};

    ArrayList<OrderDto> orderDtoList = new ArrayList<>();

    /**
     * 账号密码登录
     *
     * @param name
     * @param password
     * @return
     */
    @PostMapping("login")
    @ResponseBody
    @ApiOperation("账号密码登录")
    public ResultVo login(String name, String password) {

        ResultVo resultVo = new ResultVo();
        resultVo.setCode(200);
        resultVo.setMsg("获取下单身份token成功");
        Map map = new HashMap();
        map.put("token", TOKEN);
        resultVo.setData(map);
        return resultVo;

    }

    /**
     * 检查库存
     *
     * @param productName
     * @param number
     * @return
     */
    @GetMapping("checkStock")
    @ResponseBody
    @ApiOperation("检查库存")
    public ResultVo checkStock(String productName, int number) {

        ResultVo resultVo = new ResultVo();

        Integer num = productMap.get(productName);
        if (num != null) {
            if (number <= num) {
                resultVo.setCode(200);
                resultVo.setMsg("库存充足");
                resultVo.setData("true");
            } else {
                resultVo.setCode(AllEnum.Not_Enough_Stock.getCode());
                resultVo.setMsg(AllEnum.Not_Enough_Stock.getMsg());
                resultVo.setData("false");
            }
        } else {
            resultVo.setCode(AllEnum.Not_Exist_Stock.getCode());
            resultVo.setMsg(AllEnum.Not_Exist_Stock.getMsg());
            resultVo.setData(productMap);
        }
        return resultVo;
    }

    /**
     * 添加商品库存
     *
     * @param productDto
     * @return
     */
    @PostMapping("addProductStock")
    @ResponseBody
    @ApiOperation("添加商品库存")
    public ResultVo addProductStock(@RequestBody ProductDto productDto) {

        ResultVo resultVo = new ResultVo();

        Integer number = productMap.get(productDto.getName());


        if (number != null && number > 0) {
            number += productDto.getNumber();
            productMap.put(productDto.getName(), number);

            resultVo.setCode(200);
            resultVo.setMsg("添加库存成功");
            resultVo.setData(productMap);

        } else {
            productMap.put(productDto.getName(), productDto.getNumber());
            resultVo.setCode(200);
            resultVo.setMsg("新增商品成功");
            resultVo.setData(productMap);
        }

        return resultVo;
    }

    /**
     * 更新库存
     *
     * @param productDto
     * @return
     */
    @PutMapping("updateProductStock")
    @ResponseBody
    @ApiOperation("更新库存")
    public ResultVo updateProductStock(@RequestBody ProductDto productDto) {

        ResultVo resultVo = new ResultVo();
        Integer num = productMap.get(productDto.getName());
        if (num != null) {
            productMap.put(productDto.getName(), productDto.getNumber());
            resultVo.setCode(200);
            resultVo.setMsg("修改" + productDto.getName() + "库存信息成功,该商品剩余库存数量为:" + productDto.getNumber());
            resultVo.setData(productMap);
        } else {
            resultVo.setCode(AllEnum.Failed_To_Modify_Commodity_Quantity.getCode());
            resultVo.setMsg(AllEnum.Failed_To_Modify_Commodity_Quantity.getMsg());
            resultVo.setData(false);
        }

        return resultVo;
    }

    /**
     * 消耗库存
     *
     * @param productName
     * @return
     */
    @DeleteMapping("removeProductStock")
    @ResponseBody
    @ApiOperation("消耗库存")
    public ResultVo removeProductStock(String productName) {
        ResultVo resultVo = new ResultVo();
        Integer num = productMap.get(productName);
        if (num != null) {
            productMap.remove(productName);
            resultVo.setCode(200);
            resultVo.setMsg("移除商品:" + productName + "成功!");
            resultVo.setData(productMap);
        } else {
            resultVo.setCode(AllEnum.Failed_To_Remove_Product.getCode());
            resultVo.setMsg(AllEnum.Failed_To_Remove_Product.getMsg());
            resultVo.setData(false);
        }
        return resultVo;
    }

    /**
     * 展示所有商品库存
     * @return
     */
    @GetMapping(value = "showAllStock")
    @ResponseBody
    @ApiOperation("展示所有商品库存")
    public ResultVo showAllStock(){
        ResultVo resultVo = new ResultVo();
        if (productMap!=null && productMap.size()!=0){
            resultVo.setCode(200);
            resultVo.setMsg("展示所有库存");
            resultVo.setData(productMap);
        }else {
            resultVo.setCode(AllEnum.Inventory_Is_Empty.getCode());
            resultVo.setMsg(AllEnum.Inventory_Is_Empty.getMsg());
        }
        return resultVo;

    }


    /**
     * 预下单
     *
     * @param productDto
     * @param authorization
     * @return
     */
    @PostMapping("preOrder")
    @ResponseBody
    @ApiOperation("预下单")
    public ResultVo preOrder(ProductDto productDto, @RequestHeader("Authorization") String authorization) {
        ResultVo resultVo = new ResultVo();
        System.out.println(productDto.getName() + "   " + productDto.getNumber() + "   " + authorization);
        if (productDto != null && productMap.get(productDto.getName()) != null){
            if (TOKEN.equals(authorization)) {
                if (productMap.get(productDto.getName()) >= productDto.getNumber()){
                    Map map = new HashMap();
                    String oId = new Date().getTime() + "";
                    map.put("orderId", oId);
                    resultVo.setCode(200);
                    resultVo.setMsg("身份校验通过," + productDto.getName() + "成功预下单" + productDto.getNumber() + "份!");
                    resultVo.setData(map);

                    OrderDto orderDto = new OrderDto();
                    orderDto.setOrderId(oId);
                    orderDto.setProductName(productDto.getName());
                    orderDto.setProductNumber(productDto.getNumber());
                    orderDtoList.add(orderDto);
                }else{
                    resultVo.setCode(AllEnum.Not_Enough_Stock.getCode());
                    resultVo.setMsg(AllEnum.Not_Enough_Stock.getMsg());
                }
            } else {
                resultVo.setCode(AllEnum.Authentication_Failed.getCode());
                resultVo.setMsg(AllEnum.Authentication_Failed.getMsg());
            }
        }else {
            resultVo.setCode(AllEnum.Illegal_Request_Parameters.getCode());
            resultVo.setMsg(AllEnum.Illegal_Request_Parameters.getMsg());
        }
        return resultVo;
    }

    /**
     * 支付订单
     *
     * @param orderIdMap
     * @return
     */
    @PostMapping("payOrder")
    @ResponseBody
    @ApiOperation("支付订单")
    public ResultVo payOrder(@RequestBody Map orderIdMap) {
        System.out.println("orderIdMap:"+orderIdMap);
        String orderId = String.valueOf(orderIdMap.get("orderId"));
        System.out.println("orderId:" + orderId);
        ResultVo resultVo = new ResultVo();
        if (orderId != null && !"".equals(orderId)) {
            if (orderDtoList.size()>0){
                for (OrderDto orderDto : orderDtoList) {
                    if (orderId.equals(orderDto.getOrderId())) {
                        //库存数量
                        Integer stock = productMap.get(orderDto.getProductName());
                        if (stock != null && orderDto.getProductNumber() <= stock) {
                            productMap.put(orderDto.getProductName(),stock - orderDto.getProductNumber());
                            resultVo.setCode(200);
                            resultVo.setMsg("模拟支付成功!");
                            resultVo.setData(orderId);
                        }else{
                            resultVo.setCode(AllEnum.Simulated_Payment_Failed.getCode());
                            resultVo.setMsg(AllEnum.Simulated_Payment_Failed.getMsg());
                        }
                    }else{
                        resultVo.setCode(AllEnum.Not_Exist_OrderId.getCode());
                        resultVo.setMsg(AllEnum.Not_Exist_OrderId.getMsg());
                    }
                }
            }else {
                resultVo.setCode(AllEnum.Not_Exist_OrderId.getCode());
                resultVo.setMsg(AllEnum.Not_Exist_OrderId.getMsg());
            }
        }else {
            resultVo.setCode(AllEnum.Illegal_Request_Parameters.getCode());
            resultVo.setMsg(AllEnum.Illegal_Request_Parameters.getMsg());
        }
        return resultVo;

    }

    public static void main(String[] args) {
        String format = new SimpleDateFormat("yyyyMMdd").format(new Date().getTime());
        System.out.println(format);
    }

}
5、应版本适配问题
springboot 2.6.3 swagger2 2.9.2
application.xml文件中添加:
spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER
6、效果如下:
访问地址:
ip:端口号/swagger-ui.html

其他 UI 对比
UI 1:
maven依赖
        <!-- https://mvnrepository.com/artifact/com.zyplayer/swagger-mg-ui -->
        <dependency>
            <groupId>com.zyplayer</groupId>
            <artifactId>swagger-mg-ui</artifactId>
            <version>1.0.6</version>
        </dependency>

访问地址:http://ip:端口/document.html

UI 2:
maven依赖
        <!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-spring-ui -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-ui</artifactId>
            <version>3.0.3</version>
        </dependency>

访问地址:http://ip:端口/doc.html


用户评论