前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >swagger&knife4j

swagger&knife4j

原创
作者头像
java小黑
修改2023-04-24 17:50:27
4940
修改2023-04-24 17:50:27
举报
文章被收录于专栏:加哇

Swagger

方案一

一、认识Swagger

1.Swagger简介

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。

2.Swagger主要功能

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。功能主要包含以下几点:

A. 使得前后端分离开发更加方便,有利于团队协作

B. 接口文档在线自动生成,降低后端开发人员编写接口文档的负担

C. 接口功能测试

使用Swagger只需要按照它的规范去定义接口及接口相关的信息,再通过Swagger衍生出来的一系列项目和工具,就可以做到生成各种格式的接口文档,以及在线接口调试页面等等。

3.官方网站

官网:https://swagger.io/

二、使用方式

1.引入Srpingfox依赖

代码语言:javascript
复制
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.9.2</version>
    </dependency>
​
    <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.9.2</version>
    </dependency>
​

[注意]

1..使用swagger要求jdk1.8及以上,否则swagger2不能运行

2.springboot集成swagger需要引入两个包即以上两个

2.创建配置类

代码语言:javascript
复制
@Configuration
@EnableSwagger2
public class Swagger2Config {
    /**
     * 创建API应用
     * apiInfo() 增加API相关信息
     * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现,
     * 指定扫描的包路径来定义指定要建立API的目录。
     * @return
     */
    @Bean
    public Docket coreApiConfig(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(adminApiInfo())
                .groupName("adminApi")
                .select()
                //只显示admin下面的路径
                .paths(Predicates.and(PathSelectors.regex("/admin/.*")))
                .build();
    }
​
    private ApiInfo adminApiInfo(){
        return new ApiInfoBuilder()
                .title("尚融宝后台管理系统--api文档")
                .description("尚融宝后台管理系统接口描述")
                .version("1.0")
                .contact(new Contact("李燕茹","http://baidu.com","728831102@qq.com"))
                .build();
    }
}
​

3.API详解

@Api:用在类上,说明该类的作用。 @ApiOperation:注解来给API增加方法说明。 @ApiParam:定义在参数上 @ApiResponses:用于表示一组响应 @ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息 l code:数字,例如400 l message:信息,例如"请求参数没填好" l response:抛出异常的类

@ApiModel:描述一个Model的信息(一般用在请求参数无法使用@ApiImplicitParam注解进行描述的时候)

l @ApiModelProperty:描述一个model的属性

@ApiImplicitParams: 用在方法上包含一组参数说明。

@ApiImplicitParam:用来注解来给方法入参增加说明

例子:

代码语言:javascript
复制
//实体类
//entity的实体类中可以添加一些自定义设置
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="IntegralGrade对象", description="积分等级表")
public class IntegralGrade implements Serializable {
​
    private static final long serialVersionUID = 1L;
​
    @ApiModelProperty(value = "编号")
      @TableId(value = "id", type = IdType.AUTO)
    private Long id;
​
    @ApiModelProperty(value = "积分区间开始")
    private Integer integralStart;
​
    @ApiModelProperty(value = "积分区间结束")
    private Integer integralEnd;
​
    @ApiModelProperty(value = "借款额度")
    private BigDecimal borrowAmount;
​
    @ApiModelProperty(value = "创建时间")
    private LocalDateTime createTime;
​
    @ApiModelProperty(value = "更新时间")
    private LocalDateTime updateTime;
​
    @ApiModelProperty(value = "逻辑删除(1:已删除,0:未删除)")
    @TableField("is_deleted")
    @TableLogic
    private Boolean deleted;
}
​
代码语言:javascript
复制
//controler层
@RestController
@RequestMapping("/admin/integralGrade")
@Api(value = "积分等级管理")
public class IntegralGradeController {
​
    @Resource
    private IntegralGradeService integralGradeService;
​
    @GetMapping("/list")
    @ApiOperation("积分等级列表")
    public Result listAll(){
        List<IntegralGrade> list = integralGradeService.list();
        return Result.ok().data("list",list);
    }
​
    @DeleteMapping("/remove/{id}")
    @ApiOperation(value = "根据id删除积分等级",notes = "逻辑删除")
    public Result removeById(
        @ApiParam(value = "数据id",required = true,example = "1")
        @PathVariable Long id){
        boolean result = integralGradeService.removeById(id);
        if (result){
            return Result.ok().message("删除成功");
        }else {
            return Result.error().message("删除失败");
        }
    }
​
    @PostMapping("/save")
    @ApiOperation(value = "新增积分等级")
    public Result save(@ApiParam(value = "积分等级对象",required = true) @RequestBody IntegralGrade integralGrade){
        boolean result = integralGradeService.save(integralGrade);
        if (result){
            return Result.ok().message("新增成功");
        }else {
            return Result.error().message("新增失败");
        }
    }
​
    @PutMapping("/updateById")
    @ApiOperation(value = "根据id修改积分等级")
    public Result updateById(@ApiParam(value = "积分等级对象",required = true) @RequestBody IntegralGrade integralGrade){
        boolean result = integralGradeService.updateById(integralGrade);
        if (result){
            return Result.ok().message("修改成功");
        }else {
            return Result.error().message("修改失败");
        }
    }
​
    @GetMapping("/getById/{id}")
    @ApiOperation(value = "根据id查询积分等级")
    public Result getById(@ApiParam(value = "数据id",required = true,example = "1") @PathVariable Long id){
        IntegralGrade result = integralGradeService.getById(id);
        if (result == null){
            return Result.error().message("查询失败");
        }else {
            return Result.ok().data("integralGrade",result);
        }
    }
}
​

4.访问页面

完成上述代码,启动Spring Boot程序,

访问:http://localhost:8080/swagger-ui.html

5.测试

点击try it out 可以测试接口

方案二

1.导包

引入依赖 需要依赖的工程

代码语言:javascript
复制
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
</dependency>

2.配置

代码语言:javascript
复制
package com.heima.common.swagger;
​
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
​
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
​
   @Bean
   public Docket buildDocket() {
      return new Docket(DocumentationType.SWAGGER_2)
              .apiInfo(buildApiInfo())
              .select()
              // 要扫描的API(Controller)基础包
              .apis(RequestHandlerSelectors.basePackage("com.heima"))
              .paths(PathSelectors.any())
              .build();
   }
​
   private ApiInfo buildApiInfo() {
      Contact contact = new Contact("总标题","","");
      return new ApiInfoBuilder()
              .title("API文档")
              .description("后台api")
              .contact(contact)
              .version("1.0.0").build();
   }
}

resources/META-INF/Spring.factories

代码语言:javascript
复制
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.heima.common.swagger.SwaggerConfiguration

加上注解就能使用了

Swagger常用注解

代码语言:javascript
复制
在Java类中添加Swagger的注解即可生成Swagger接口文档,常用Swagger注解如下:
​
@Api:修饰整个类,描述Controller的作用  
​
@ApiOperation:描述一个类的一个方法,或者说一个接口  
​
@ApiParam:单个参数的描述信息  
​
@ApiModel:用对象来接收参数  
​
@ApiModelProperty:用对象接收参数时,描述对象的一个字段  
​
@ApiResponse:HTTP响应其中1个描述  
​
@ApiResponses:HTTP响应整体描述  
​
@ApiIgnore:使用该注解忽略这个API  
​
@ApiError :发生错误返回的信息  
​
@ApiImplicitParam:一个请求参数  
​
@ApiImplicitParams:多个请求参数的描述信息

三、技术概述

参考:

http://blog.didispace.com/springbootswagger2/

Swagger官网 :

http://swagger.io/

Spring Boot & Swagger UI :

http://fruzenshtein.com/spring-boot-swagger-ui/

Github:

https://github.com/swagger-api/swagger-core/wiki/Annotations

knife4j

一、认识knife4j

knife4j是swagger的增强版,更契合微服务架构,ui前身是swagger-bootstrap-ui,api注解的使用方式和swagger一致。

二、使用方式

1.引入依赖

代码语言:javascript
复制
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>3.0.2</version>
</dependency>

2、导入相关配置类

这里我们就不需要再创建一个新的配置类了,我们直接在WebMvcConfig配置类中声明即可。

A. 在该配置类中加上两个注解 @EnableSwagger2 @EnableKnife4j ,开启Swagger和Knife4j的功能。

B. 在配置类中声明一个Docket类型的bean, 通过该bean来指定生成文档的信息。

代码语言:javascript
复制
@Slf4j
@Configuration
@EnableSwagger2
@EnableKnife4j
public class WebMvcConfig extends WebMvcConfigurationSupport {
	
    /**
     * 设置静态资源映射
     * @param registry
     */
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        log.info("开始进行静态资源映射...");
        registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
        registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
    }
	
    /**
     * 扩展mvc框架的消息转换器
     * @param converters
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("扩展消息转换器...");
        //创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        //设置对象转换器,底层使用Jackson将Java对象转为json
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        //将上面的消息转换器对象追加到mvc框架的转换器集合中
        converters.add(0,messageConverter);
    }
	
    @Bean
    public Docket createRestApi() {
        // 文档类型
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.itheima.reggie.controller"))
                .paths(PathSelectors.any())
                .build();
    }
	
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("瑞吉外卖")
                .version("1.0")
                .description("瑞吉外卖接口文档")
                .build();
    }
}

注意: Docket声明时,指定的有一个包扫描的路径,该路径指定的是Controller所在包的路径。因为Swagger在生成接口文档时,就是根据这里指定的包路径,自动的扫描该包下的@Controller, @RestController, @RequestMapping等SpringMVC的注解,依据这些注解来生成对应的接口文档。

3.设置静态资源映射

代码语言:javascript
复制
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");

4.在LoginCheckFilter中设置不需要处理的请求路径

需要将Swagger及Knife4j相关的静态资源直接放行,无需登录即可访问,否则我们就需要登录之后,才可以访问接口文档的页面。

在原有的不需要处理的请求路径中,再增加如下链接:

代码语言:javascript
复制
"/doc.html",
"/webjars/**",
"/swagger-resources",
"/v2/api-docs"

5.查看接口文档

经过上面的集成配置之后,我们的项目集成Swagger及Knife4j就已经完成了,接下来我们可以重新启动项目,访问接口文档,访问链接为: http://localhost:8080/doc.html

我们可以看到,在所有的Controller中提供的所有的业务增删改查的接口,全部都已经自动生成了,我们通过接口文档可以看到请求的url、请求方式、请求参数、请求实例、响应的参数,响应的示例。 并且呢,我们也可以通过这份在线的接口文档,对接口进行测试。

注意: 由于我们服务端的Controller中的业务增删改查的方法,都是必须登录之后才可以访问的,所以,我们在测试时候,也是需要先访问登录接口。登录完成之后,我们可以再访问其他接口进行测试。

我们不仅可以在浏览器浏览生成的接口文档,Knife4j还支持离线文档,对接口文档进行下载,支持下载的格式有:markdown、html、word、openApi。

6.常用注解

注解

位置

说明

@Api

加载Controller类上,表示对类的说明

@ApiModel

类(通常是实体类)

描述实体类的作用

@ApiModelProperty

属性

描述实体类的属性

@ApiOperation

方法

说明方法的用途、作用

@ApiImplicitParams

方法

表示一组参数说明

@ApiImplicitParam

方法

用在@ApiImplicitParams注解中,指定一个请求参数的各个方面的属性

例子:

代码语言:javascript
复制
@Data
@ApiModel("套餐")
public class Setmeal implements Serializable {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty("主键")
    private Long id;
    
    //分类id
    @ApiModelProperty("分类id")
    private Long categoryId;
    
    //套餐名称
    @ApiModelProperty("套餐名称")
    private String name;

    //套餐价格
    @ApiModelProperty("套餐价格")
    private BigDecimal price;

    //状态 0:停用 1:启用
    @ApiModelProperty("状态")
    private Integer status;

    //编码
    @ApiModelProperty("套餐编号")
    private String code;

    //描述信息
    @ApiModelProperty("描述信息")
    private String description;

    //图片
    @ApiModelProperty("图片")
    private String image;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    @TableField(fill = FieldFill.INSERT)
    private Long createUser;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
}
代码语言:javascript
复制
@Data
@ApiModel("返回结果")
public class R<T> implements Serializable{

    @ApiModelProperty("编码")
    private Integer code; //编码:1成功,0和其它数字为失败

    @ApiModelProperty("错误信息")
    private String msg; //错误信息

    @ApiModelProperty("数据")
    private T data; //数据

    @ApiModelProperty("动态数据")
    private Map map = new HashMap(); //动态数据
	
	//省略静态方法 ....
}    
代码语言:javascript
复制
@RestController
@RequestMapping("/setmeal")
@Slf4j
@Api(tags = "套餐相关接口")
public class SetmealController {

    @Autowired
    private SetmealService setmealService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private SetmealDishService setmealDishService;

    /**
     * 新增套餐
     * @param setmealDto
     * @return
     */
    @PostMapping
    @CacheEvict(value = "setmealCache",allEntries = true)
    @ApiOperation(value = "新增套餐接口")
    public R<String> save(@RequestBody SetmealDto setmealDto){
        log.info("套餐信息:{}",setmealDto);

        setmealService.saveWithDish(setmealDto);

        return R.success("新增套餐成功");
    }

    /**
     * 套餐分页查询
     * @param page
     * @param pageSize
     * @param name
     * @return
     */
    @GetMapping("/page")
    @ApiOperation(value = "套餐分页查询接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page",value = "页码",required = true),
            @ApiImplicitParam(name = "pageSize",value = "每页记录数",required = true),
            @ApiImplicitParam(name = "name",value = "套餐名称",required = false)
    })
    public R<Page> page(int page,int pageSize,String name){
        //分页构造器对象
        Page<Setmeal> pageInfo = new Page<>(page,pageSize);
        Page<SetmealDto> dtoPage = new Page<>();

        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        //添加查询条件,根据name进行like模糊查询
        queryWrapper.like(name != null,Setmeal::getName,name);
        //添加排序条件,根据更新时间降序排列
        queryWrapper.orderByDesc(Setmeal::getUpdateTime);

        setmealService.page(pageInfo,queryWrapper);

        //对象拷贝
        BeanUtils.copyProperties(pageInfo,dtoPage,"records");
        List<Setmeal> records = pageInfo.getRecords();

        List<SetmealDto> list = records.stream().map((item) -> {
            SetmealDto setmealDto = new SetmealDto();
            //对象拷贝
            BeanUtils.copyProperties(item,setmealDto);
            //分类id
            Long categoryId = item.getCategoryId();
            //根据分类id查询分类对象
            Category category = categoryService.getById(categoryId);
            if(category != null){
                //分类名称
                String categoryName = category.getName();
                setmealDto.setCategoryName(categoryName);
            }
            return setmealDto;
        }).collect(Collectors.toList());

        dtoPage.setRecords(list);
        return R.success(dtoPage);
    }

    /**
     * 删除套餐
     * @param ids
     * @return
     */
    @DeleteMapping
    @CacheEvict(value = "setmealCache",allEntries = true)
    @ApiOperation(value = "套餐删除接口")
    public R<String> delete(@RequestParam List<Long> ids){
        log.info("ids:{}",ids);

        setmealService.removeWithDish(ids);

        return R.success("套餐数据删除成功");
    }

    /**
     * 根据条件查询套餐数据
     * @param setmeal
     * @return
     */
    @GetMapping("/list")
    @Cacheable(value = "setmealCache",key = "#setmeal.categoryId + '_' + #setmeal.status")
    @ApiOperation(value = "套餐条件查询接口")
    public R<List<Setmeal>> list(Setmeal setmeal){
        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(setmeal.getCategoryId() != null,Setmeal::getCategoryId,setmeal.getCategoryId());
        queryWrapper.eq(setmeal.getStatus() != null,Setmeal::getStatus,setmeal.getStatus());
        queryWrapper.orderByDesc(Setmeal::getUpdateTime);

        List<Setmeal> list = setmealService.list(queryWrapper);

        return R.success(list);
    }
}

7.重启服务测试

我们上述通过Swagger的注解,对实体类及实体类中的属性,以及Controller和Controller的方法进行描述,接下来,我们重新启动服务,然后看一下自动生成的接口文档有何变化。

在接口文档的页面中,我们可以看到接口的中文描述,清晰的看到每一个接口是做什么的,接口方法参数什么含义,参数是否是必填的,响应结果的参数是什么含义等,都可以清楚的描述出来。

总之,我们要想清晰的描述一个接口,就需要借助于Swagger给我们提供的注解。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Swagger
    • 方案一
      • 一、认识Swagger
        • 1.Swagger简介
          • 2.Swagger主要功能
            • 3.官方网站
          • 二、使用方式
            • 1.引入Srpingfox依赖
              • 2.创建配置类
                • 3.API详解
                  • 4.访问页面
                    • 5.测试
                      • 方案二
                        • 1.导包
                      • 三、技术概述
                      • knife4j
                        • 一、认识knife4j
                          • 二、使用方式
                            • 1.引入依赖
                              • 2、导入相关配置类
                                • 3.设置静态资源映射
                                  • 4.在LoginCheckFilter中设置不需要处理的请求路径
                                    • 5.查看接口文档
                                      • 6.常用注解
                                        • 7.重启服务测试
                                        相关产品与服务
                                        云服务器
                                        云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
                                        领券
                                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档