• swagger-03-文档注释使用


    1.7 文档注释使用

    1.7.1 接口组定义
    • 接口有时候应该是分组的,而且大部分都是在一个controller中的,比如app管理相关的接口应该都在AppController中,那么不同的业务的时候,应该定义/划分不同的接口组。接口组可以使用@Api来划分。

    注意,对于swagger,不要使用@RequestMapping

    因为@RequestMapping支持任意请求方式,swagger会为这个接口生成7种请求方式的接口文档

    @Api(tags = "app管理")  //可以当作是这个组的名字。
    @RestController
    @RequestMapping("app")
    public class AppController {
        @RequestMapping(value = "/hello",method = RequestMethod.GET)
        public String hello(){
            return "hello swagger!";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    可以理解成基于tags来分组

    如果这个Controller下(接口组)下面没有接口,那么在swagger ui中是不会显示的,如果有的话就会这样显示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CS340edl-1660311086604)(../../typora-user-images/image-20220810151510792.png)]

    1.7.2 接口定义
    • 使用了@Api来标注一个Controller之后,如果下面有接口,那么就会默认生成文档,但没有我们自定义的说明:

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qAk9GVN3-1660311086607)(../../typora-user-images/image-20220810153325738.png)]

    • 我们可以使用@ApiOperation来描述接口,比如:
     //只要我们的接口中,返回值中存在实体类,他就会被扫描外wagger中
        @ApiOperation(value = "获取用户",notes = "获取用户接口")
        @GetMapping("/getUser")
        public User getUser(String name,String password){
            return new User(name,password);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    常用配置项:

    • value:可以当作是接口的简称
    • notes:接口的描述
    • tags:可以额外定义接口组,比如这个接口外层已经有@Api(tags = "用户管理"),将接口划分到了“用户管理”中,但你可以额外的使用tags,例如tags = "角色管理"让角色管理中也有这个接口文档。
    1.7.3 定义接口请求参数
    • 上面使用了@ApiOperation来了描述接口,还缺少接口请求参数的说明.

    对于GET方式,swagger不推荐使用body方式来传递数据所以虽然Spring MVC可以自动封装参数,也是不希望在GET方式时使用json、form-data等方式来传递,这时候最好使用路径参数或者url参数。(虽然POSTMAN等是支持的,swagger在线测试是不支持这个操作的),所以如果接口传递的数据是json或者form-data方式的,还是使用POST方式好。可翻看之前的博客SpringMVC-09-传递参数的几种方式

    1.7.3.1 请求参数是实体类
    • 此时我们需要使用@ApiModel来标注实体类,然后在接口中定义入参为实体类即可:

    • @ApiModel:用来标类,@ApiModel内的注释 不要出现相同 否则会将相同的vo字段进行合并

      • 常用配置项:
        • value:实体类简称
        • description:实体类说明
    • @ApiModelProperty:用来描述类的字段的意义。

      • 常用配置项:
        • value:字段说明
        • example:设置请求示例(Example Value)的默认值,如果不配置,当字段为string的时候,此时请求示例中默认值为"“,对于int类型数据若没有默认值,则默认是”"空字符串,会造成NumberFormatException,

    1.给int类型的字段使用@ApiModelPorperty注解时添加example属性

    2.去除原swagger中的swagger-models和swagger-annotations,自行引入高版本的annotations和models

    
                io.springfox
                springfox-swagger2
                2.9.2
                
                    
                        io.swagger
                        swagger-annotations
                    
                    
                        io.swagger
                        swagger-models
                    
                
            
            
                io.swagger
                swagger-annotations
                1.5.22
            
            
                io.swagger
                swagger-models
                1.5.22
            
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • notes:参数类型为String,作用为该字段的注释说明
    • name:用新的字段名来替代旧的字段名。
    • position:参数类型为int,作用为允许显式地对模型中的属性排序。
    • allowableValues:限制值得范围,例如{1,2,3}代表只能取这三个值;[1,6]代表取1到6的值;(1,6)代表1到6的值,不包括1和6;还可以使用infinity或-infinity来无限值,比如[1, infinity]代表最小值为1,最大值无穷大。
    • required:标记字段是否必填,默认是false,
    • hidden:用来隐藏字段,默认是false,如果要隐藏需要使用true,因为字段默认都会显示,就算没有@ApiModelProperty
    • allowEmptyValue:参数类型为boolean,作用为是否允许传递空值,默认为false
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @ApiModel(value = "用户实体类",description = "用户实体对象")  // 先使用@ApiModel来标注类
    public class User {
    
        // 使用ApiModelProperty来标注字段属性。
        @ApiModelProperty(value = "name",required = true,example = "toy")
        private String name;
        @ApiModelProperty(value = "name",required = true,example = "123456")
        private String password;
        
        //swagger在入参赋值时需要的getter,setter来置值
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 定义成入参:
    @ApiOperation(value = "获取用户",notes = "获取用户通过传递实体json")
    @PostMapping("/getUser")
    public User getUserPost(@RequestBody User user){
        return user;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    • try it out 结果
      在这里插入图片描述
    1.7.2.2 请求参数是非实体类
    • 对于非实体类参数,可以使用@ApiImplicitParams@ApiImplicitParam来声明请求参数。
      @ApiImplicitParams用在方法头上,@ApiImplicitParam定义在@ApiImplicitParams里面,一个@ApiImplicitParam对应一个参数。

      @ApiImplicitParam常用配置项:

    • name:用来定义参数的名字,也就是字段的名字,可以与接口的入参名对应。如果不对应,也会生成,所以可以用来定义额外参数!

    • value:用来描述参数

    • required:用来标注参数是否必填

    • paramType有path,query,body,form,header等方式,但对于对于非实体类参数的时候,常用的只有path,query,header;body和form是不常用的。body不适用于多个零散参数的情况,只适用于json对象等情况。【如果你的接口是form-data,x-www-form-urlencoded的时候可能不能使用swagger页面API调试,但可以在后面讲到基于BootstrapUI的swagger增强中调试,基于BootstrapUI的swagger支持指定form-datax-www-form-urlencoded

    • 也可以仅仅使用@ApiParam作用在方法上参数不用声明,@ApiParam使用配置和@ApiImplicitParam一样对于3.0.0比2.X有点是可以适配所有类型的参数请求方式,2.x需要测试时手动选择

    //只要我们的接口中,返回值中存在实体类,他就会被扫描外wagger中
        @ApiOperation(value = "获取用户",notes = "获取用户接口")
        @GetMapping("/getUser")
        public User getUser(@ApiParam(name = "name",value = "账户",required = true) String name,@ApiParam(name = "password",value = "密码",required = true)String password){
            return new User(name,password);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    query方式入参

    //query方式入参
    @ApiOperation(value = "获取用户1",notes = "获取用户接口1-query方式入参")
    @GetMapping("/getUser1")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "name",value = "账户",required = true,paramType = "query"),
            @ApiImplicitParam(name = "password",value = "密码",required = true,paramType = "query")
    })
    public User getUser1(String name,String password){
        return new User(name,password);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    在这里插入图片描述

    path方式入参

    //path方式入参
    @ApiOperation(value = "获取用户2",notes = "获取用户接口2-path方式入参")
    @GetMapping("/getUser/{name}/{password}")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "name",value = "账户",required = true,paramType = "path"),
            @ApiImplicitParam(name = "password",value = "密码",required = true,paramType = "path")
    })
    public User getUser2(@PathVariable("name") String name,@PathVariable("password")String password){
        return new User(name,password);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FFiaweHT-1660311086611)(../../typora-user-images/image-20220810183314191.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qeouf7Ic-1660311086612)(../../typora-user-images/image-20220810183440703.png)]

    header方式入参

    //header方式入参
    @ApiOperation(value = "获取用户3",notes = "获取用户接口3-header方式入参")
    @GetMapping("/getUser3")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "name",value = "账户",required = true,paramType = "header"),
            @ApiImplicitParam(name = "password",value = "密码",required = true,paramType = "header")
    })
    public User getUser3(@RequestHeader String name,@RequestHeader String password){
        return new User(name,password);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    在这里插入图片描述

    单件上传入参

    文件上传时要用@ApiImplicitParams @ApiImplicitParam @ApiParam作用在方法上作为入参@RequestPart用在参数上,用于将“multipart/form-data”请求的一部分与方法参数相关联的注释

    //单件上传入参
        @ApiOperation(value = "文件上传1",notes = "文件上传-单文件")
        @ApiImplicitParams({
                @ApiImplicitParam(name = "uploadFile", paramType="form", value = "上传文件", dataType="uploadFile", required = true)
        })
        @PostMapping(value = "/upload1", headers = "content-type=multipart/form-data")
        public String upload(@RequestPart("uploadFile") MultipartFile uploadFile, HttpSession session, HttpServletRequest req){
            String originalFilename = uploadFile.getOriginalFilename();
            //若文件名为空则返回到上传页
            if (!StringUtils.hasText(originalFilename)) {
                return "originalFilename is error";
            }
    
            //上传路径保存设置
            //String uploadPath = session.getServletContext().getRealPath("/uploadFile/");
    
            System.out.println("fileSavePath====="+fileSavePath);
            File file1 = new File(fileSavePath);
            if (!file1.exists()) {
                file1.mkdirs();
            }
            try {
                uploadFile.transferTo(new File(file1,originalFilename));
            } catch (IOException e) {
                e.printStackTrace();
                return "uploadFile is error!";
            }
            return req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort()+"/workspace_idea01/uploadFile/"+originalFilename;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    多件上传入参

    多个文件上传时,swagger只能测试单文件上传,需要用postman或Apifox等工具测试

    @ApiOperation(value = "文件上传2",notes = "文件上传-多文件")
    @PostMapping(value = "/upload2",consumes = "multipart/*", headers = "content-type=multipart/form-data")
    public ArrayList upload2(@ApiParam(name = "uploadFile",value = "上传文件",required = true,allowMultiple = true) MultipartFile[] uploadFile, HttpSession session, HttpServletRequest req){
        String originalFilename ="";
        //若文件名为空则返回到上传页
        if (!StringUtils.hasText(originalFilename)) {
            System.out.println("originalFilename is error");
        }
        ArrayList filePathList=new ArrayList();
    
        System.out.println("fileSavePath====="+fileSavePath);
        File file1 = new File(fileSavePath);
        if (!file1.exists()) {
            file1.mkdirs();
        }
        for (MultipartFile file: uploadFile) {
            originalFilename = file.getOriginalFilename();
            if (!StringUtils.hasText(originalFilename)) {
                System.out.println("originalFilename is error");
            }
            try {
                file.transferTo(new File(file1,originalFilename));
                filePathList.add(req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort()+"/workspace_idea01/uploadFile/"+originalFilename);
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("uploadFile is error!");
            }
        }
    
        return filePathList;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    通过reuestbody传递数据等方式

    //通过reuestbody传递数据等方式
    @ApiOperation(value = "测试requestBody", notes = "测试requestBody")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType="query", name="userId", value="用户id", dataTypeClass = Integer.class, required = true),
            @ApiImplicitParam(paramType="body", name = "body",dataType = "string", example = "", required = false)
    })
    @PostMapping(value="/command",produces = {"application/json;charset=UTF-8"})
        public String getHttpInfo(@RequestBody User user, Integer userId) throws IOException {
            //InputStream in = request.getInputStream();
            // TODO. LOGIC
            return user.toString();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 也可以从request流中取值
    public String getHttpInfo(HttpServletRequest request, Integer userId) throws IOException {
    InputStream in = request.getInputStream();
    }
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    在这里插入图片描述

    既有文件,又有参数

    @ApiOperation(value = "文件上传3",notes = "文件上传-携带参数")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "uploadFile", paramType="form", value = "上传文件", dataType="uploadFile", required = true),
            @ApiImplicitParam(name = "id", paramType="query", value = "参数id", dataTypeClass= Integer.class, required = true)
    })
    @PostMapping(value = "/upload3", headers = "content-type=multipart/form-data")
    public String upload3(@RequestPart("uploadFile") MultipartFile uploadFile,Integer id, HttpServletRequest req){
        String originalFilename = uploadFile.getOriginalFilename();
        //若文件名为空则返回到上传页
        if (!StringUtils.hasText(originalFilename)) {
            return "originalFilename is error";
        }
    
        //上传路径保存设置
        //String uploadPath = session.getServletContext().getRealPath("/uploadFile/");
    
        System.out.println("fileSavePath====="+fileSavePath);
        File file1 = new File(fileSavePath);
        if (!file1.exists()) {
            file1.mkdirs();
        }
        try {
            uploadFile.transferTo(new File(file1,originalFilename));
        } catch (IOException e) {
            e.printStackTrace();
            return "uploadFile is error!";
        }
        return req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort()+"/workspace_idea01/uploadFile/"+originalFilename+"&id="+id;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    在这里插入图片描述

    在这里插入图片描述

    1.7.4 定义接口响应
    • 定义接口响应,即查看接口文档的人能够知道接口返回的数据的意义。
    1.7.4.1 响应是实体类
    • 只要在接口请求参数上使用@ApiModel来标注类,如果接口返回了这个类,那么这个类上的说明也会作为响应的说明:
    @ApiOperation(value = "返回实体对象",notes = "返回实体对象描述user")
    @PostMapping("/getUser4")
    public User getUser4(@RequestBody User user){
        return user;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    在这里插入图片描述

    1.7.4.2 响应非实体类
    • swagger无法对非实体类的响应进行详细说明,只能标注响应码等信息。是通过@ApiResponses@ApiResponse来实现的。
    @ApiOperation(value = "返回非实体",notes = "返回非实体描述Stirng")
    @PostMapping("/getUser5")
    @ApiResponses({
            @ApiResponse(code = 200,message = "请求-响应成功"),
            @ApiResponse(code = 404,message = "页面异常"),
    })
    public String getUser5(@RequestBody User user){
        return user.toString();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    在这里插入图片描述

    1.8 Swagger UI增强

    • 作为Swagger UI的衍生,可以使用第三方提供了一些Swagger UI增强,如swagger-bootstrap-ui
    1.8.1 使用
    • 补充导入swagger-bootstrap-ui,前面的swagger-ui不变
     
     
         com.github.xiaoymin
         swagger-bootstrap-ui
         1.8.7
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 在swagger配置类中增加注解@EnableSwaggerBootstrapUI:
    @Configuration // 标明是配置类
    //@EnableSwagger2  //开启swagger2功能 供3.0以下使用,swagger老版本
    @EnableOpenApi
    //@Profile({"dev","test"})
    @ConditionalOnProperty(name = "swagger.enable",havingValue = "true")
    @EnableSwaggerBootstrapUI
    public class SwaggerConfig {
    ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 访问API:http://localhost:8080/doc.html,可预览到基于bootstarp的Swagger UI界面。

    在这里插入图片描述

    在这里插入图片描述

    • 基于BootstrapUI的swagger支持指定form-datax-www-form-urlencoded

    • 支持复制单个API文档和导出全部API文档:

    在这里插入图片描述

    • 整合Spring Security注意

    在Spring Boot整合Spring Security和Swagger的时候,需要配置拦截的路径和放行的路径,注意是放行以下几个路径。

    .antMatchers("/swagger**/**").permitAll()
    .antMatchers("/webjars/**").permitAll()
    .antMatchers("/v2/**").permitAll()
    .antMatchers("/doc.html").permitAll() // 如果你用了bootstarp的Swagger UI界面,加一个这个。
    
    • 1
    • 2
    • 3
    • 4
    1.8.2 对于token的处理
    • 在swagger中只支持了简单的调试,但对于一些接口,我们测试的时候可能需要把token信息写到header中

    • 办法如下:

      • 在Swagger BootstrapUI,可以在“文档管理”中增加全局参数,这包括了添加header参数。
      • 在swagger配置类中增加全局参数配置
      @Bean
          public Docket docket(Environment environment){
              RequestParameterBuilder builder = new RequestParameterBuilder();
              RequestParameter requestParameter = builder.name("token").description("令牌").in(ParameterType.HEADER).required(false).build();
      
              List globalRequestParameters = new ArrayList<>();
              globalRequestParameters.add(requestParameter);
              //设置要显示的Swagger环境
              Profiles profiles = Profiles.of("dev", "test");
              //通过environment.acceptsProfiles配置文件中设置的环境来判断是否在设定的环境中
              boolean flag = environment.acceptsProfiles(profiles);
              return new Docket(DocumentationType.OAS_30)// DocumentationType.OAS_30 固定的,代表swagger3.0
                      .groupName("分组1") // 如果配置多个文档的时候,那么需要配置groupName来分组标识
                      .apiInfo(apiInfo())
                      .enable(flag)
                      .select() // select()函数返回一个ApiSelectorBuilder实例,用来控制接口被swagger做成文档
                      .apis(RequestHandlerSelectors.basePackage("com.example.controller"))// 用于指定扫描哪个包下的接口
                      //paths 指定扫描路径  PathSelectors.ant("/app/**")在controller包下,请求路径是/app/**可以扫描到
                      .paths(PathSelectors.any())// 选择所有的API,如果你想只为部分API生成文档,可以配置这里
                      .build().globalRequestParameters(globalRequestParameters);   //建造者模式
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21

    在这里插入图片描述

    • 使用@ApiImplicitParams来额外标注一个请求头参数,例如:
    @ApiOperation(value = "获取用户5",notes = "获取用户接口5-带token的接口")
    @GetMapping("/getUser5")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "name",value = "账户",required = true,paramType = "query"),
            @ApiImplicitParam(name = "password",value = "密码",required = true,paramType = "query"),
            @ApiImplicitParam(name = "token",value = "令牌",required = true,paramType = "header"),
    
    })
    public User getUser5(String name,String password){
        return new User(name,password);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    • 整合了权限管理,可以给swagger加上权限管理
  • 相关阅读:
    restore RMAN in 12c MT(Multitenant ) database flashback table
    MAC上修改mysql的密码(每一步都图文解释哦)
    [矩阵论] Unit 3. 矩阵的分解 - 知识点整理
    springCloudAlibaba之服务熔断组件---sentinel
    解决方案| anyRTC远程检修应用场景
    智慧工厂视频智能分析系统
    OpenAI Sora文本生成视频注册教程
    DevTools 无法加载来源映射:无法加载 chrome-extension: 警告的原因以及如何去除(全网最全 最详细解决方案)
    代码随想录算法训练营|五十七天
    【集训DAY N】词典【暴力】【字典树】
  • 原文地址:https://blog.csdn.net/weixin_42045639/article/details/126311790