导入依赖

Knife4j的依赖坐标如下:

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>3.0.2</version>
</dependency>

配置类

编写(或修改)配置类:

@Configuration
@EnableSwagger2 // 开启Swagger2
@EnableKnife4j  // 开启Knife4j
public class WebMvcConfig extends WebMvcConfigurationSupport {

    @Bean
    public Docket createRestApi() {
        // 设置文档类型
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                // 设置Controller的包名
                .apis(RequestHandlerSelectors.basePackage("com.linner.reggie.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    /**
     * API文档描述
     * @return
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                // 文档标题
                .title("瑞吉外卖")
                // 文档版本
                .version("1.0")
                // 文档描述
                .description("瑞吉外卖接口文档")
                .build();
    }

    /**
     * 设置静态资源映射
     * <p>放行静态页面资源</p>
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // API文档的静态资源映射
        registry.addResourceHandler("doc.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}

资源放行

放行文档静态页面请求。必须确保以下静态资源路径可以被访问,不被拦截:

/doc.html
/webjars/**
/swagger-resources
/v2/api-docs

API 文档注解

注解 说明
@Api 用在请求的类上(例如Controller,使用tags元素指定文档的标签。
@ApiModel 用在类上(例如实体类),表示一个返回响应数据的信息。
@ApiModelProperty 用在属性上,描述响应类(实体类)的属性。
@ApiOperation 用在请求的方法上,说明方法的用途、作用。
@ApiImplicitParams 用在请求的方法上,表示一组参数说明。
@ApiImplicitParam 用在@ApiImplicitParams注解中,指定一个请求参数的各个方面。
如果只用说明一个参数的话,@ApiImplicitParam可以单独用在方法上。

注意:@ApiImplicitParam不能对实体类进行定义,否则访问API文档时/v2/api-docs会出现接口异常(500状态码)。


示例

标识响应数据信息:

/**
 菜品
 */
@Data
@ApiModel("菜品")   // 标识实体类的名称
public class Dish implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty("菜品ID")     // 标识实体类属性的名称
    private Long id;

    //菜品名称
    @ApiModelProperty("菜品名称")   // 标识实体类属性的名称
    private String name;

    //菜品分类id
    @ApiModelProperty("菜品分类ID") // 标识实体类属性的名称
    private Long categoryId;

    //菜品价格
    @ApiModelProperty("菜品价格")   // 标识实体类属性的名称
    private BigDecimal price;

    //商品码
    @ApiModelProperty("商品码")     // 标识实体类属性的名称
    private String code;

    //图片
    @ApiModelProperty("菜品图片")   // 标识实体类属性的名称
    private String image;

    //描述信息
    @ApiModelProperty("描述信息")   // 标识实体类属性的名称
    private String description;

    //0 停售 1 起售
    @ApiModelProperty("商品状态")   // 标识实体类属性的名称
    private Integer status;

    //顺序
    @ApiModelProperty("展示顺序")   // 标识实体类属性的名称
    private Integer sort;

    /* ... */
}

标识请求类:

/**
 * 菜品管理
 */
@RestController
@RequestMapping("/dish")
@Api(tags = "菜品管理")
public class DishController {

    @Autowired
    private DishService dishService;
    @Autowired
    private DishFlavorService dishFlavorService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 新增菜品
     * @param dishDto
     * @return
     */
    @PostMapping
    @ApiOperation("新增菜品")   // 标识API方法,对API请求进行说明
    public R<String> save(@RequestBody DishDto dishDto) {
        // 清理某个分类下面的菜品缓存
        String key = this.getRedisKey(dishDto);
        redisTemplate.delete(key);

        dishService.saveWithFlavor(dishDto);
        return R.success("新增菜品成功");   // 返回一个请求成功的响应体信息
    }

    /**
     * 菜品信息分页查询
     * @param page
     * @param pageSize
     */
    @GetMapping("/page")
    @ApiOperation("菜品信息分页查询")   // 标识API方法,对API请求进行说明
    @ApiImplicitParams({    // 标识API方法,对API请求参数进行说明
            /**
             * @ApiImplicitParam 对请求参数进行具体的说明,它的属性有:
             * - name:标识请求参数的名称,与API方法的参数名对应
             * - value:对name对应的参数进行说明
             * - required:对name对应的参数是否为必须的请求参数进行说明
             *   - true:值为true表示该参数是请求时必须携带的
             *   - false:值为false表示在进行请求时,可以不必携带该参数
             */
            @ApiImplicitParam(name = "page", value = "页码", required = true),
            @ApiImplicitParam(name = "pageSize", value = "每页展示数据条数", required = true),
            @ApiImplicitParam(name = "name", value = "要搜索的菜品名称")
    })
    public R<Page> page(int page, int pageSize, String name) {
        // 构造分页构造器对象
        Page<Dish> pageInfo = new Page<>(page, pageSize);
        Page<DishDto> dishDtoPage = new Page<>();

        // 条件构造器
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        // 添加过滤条件
        queryWrapper.like(name != null, Dish::getName, name);
        // 添加排序条件(降序排序)
        queryWrapper.orderByDesc(Dish::getUpdateTime);
        // isDeleted不为1(为1表示被删除)
        queryWrapper.ne(Dish::getIsDeleted, 1);

        // 执行分页查询
        dishService.page(pageInfo, queryWrapper);

        // 对象拷贝
        BeanUtils.copyProperties(pageInfo, dishDtoPage, "records");

        List<Dish> records = pageInfo.getRecords();
        List<DishDto> list = records.stream().map((item) -> {
            DishDto dishDto = new DishDto();

            BeanUtils.copyProperties(item, dishDto);

            Long categoryId = item.getCategoryId(); // 分类id
            Category category = categoryService.getById(categoryId);    // 根据id查询分类对象
            if (category != null) {
                String categoryName = category.getName();
                dishDto.setCategoryName(categoryName);
            }
            return dishDto;
        }).collect(Collectors.toList());

        dishDtoPage.setRecords(list);

        return R.success(dishDtoPage);
    }

    /**
     * 根据id查询菜品全部信息(包括口味)
     * @param id
     */
    @GetMapping("/{id}")
    @ApiOperation("根据id查询菜品全部信息(包括口味)")
    // 如果方法仅有一个参数,可以使用一个@ApiImplicitParam标识,无需使用@ApiImplicitParams
    @ApiImplicitParam(name = "id", value = "要查询的菜品ID", required = true)
    public R<DishDto> get(@PathVariable Long id) {

        DishDto dishDto = dishService.getByIdWithFlavor(id);

        return R.success(dishDto);
    }
}

更多详细用法,请参考:瑞吉外卖项目 Knife4j 笔记