Swagger介绍和应用

1.什么是swagger
Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务。简单来说,Swagger是一个功能强大的接口管理工具,并且提供了多种编程语言的前后端分离解决方案。
Swagger有大致有3个优点:
1.Swagger可以整合到代码中,在开发时通过注解,编写注释,自动生成API文档。
2.将前端后台分开,不会有过分的依赖。
3.界面清晰,无论是editor的实时展示还是ui的展示都十分人性化,如果自己仅仅用markdown来编写,又要纠结该如何展现,十分痛苦。

2.swagger注解
swagger通过注解表明该接口会生成文档,包括接口名、请求方法、参数、返回信息的等等。

@Api:修饰整个类,描述Controller的作用
@ApiOperation:描述一个类的一个方法,或者说一个接口
@ApiParam:单个参数描述
@ApiModel:用对象来接收参数
@ApiProperty:用对象接收参数时,描述对象的一个字段
@ApiResponse:HTTP响应其中1个描述
@ApiResponses:HTTP响应整体描述
@ApiIgnore:使用该注解忽略这个API
@ApiError :发生错误返回的信息
@ApiImplicitParam:一个请求参数
@ApiImplicitParams:多个请求参数

 

一、Swagger2 介绍

前后端分离开发模式中,api文档是最好的沟通方式。

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务。

  • 及时性(接口变更后,能够及时准确的通知前后端开发人员)
  • 规范性(并且保证接口的规范性,如接口的地址,请求方式,参数,响应格式和错误信息)
  • 一致性(接口信息一致,不糊出现文档版本不一致产生分歧)
  • 可测性(直接在接口文档上进行测试)

二、 配置文件

1、依赖:

<!--swagger-->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.7.0</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.7.0</version>
</dependency>
复制代码

2、配置类:

@Configuration
@EnableSwagger2
public class Swagger2Config {
    @Bean
    public Docket webApiConfig(){
        return new Docket(DocumentationType.SWAGGER_2);
    }
}
复制代码

image.png

3、配置config

@Configuration
@EnableSwagger2
public class Swagger2Config {
    /**
     * web端
     *  给命名然后过滤接口。
     * @return
     */
    @Bean
    public Docket webApiConfig(){
        return new Docket(DocumentationType.SWAGGER_2).groupName("webApi")
                .apiInfo(webApiInfo())
                .select()
                .paths(Predicates.and(PathSelectors.regex("/api/.*"))).build();
    }

    /**
     * 后台管理端
     * @return
     */
    @Bean
    public Docket adminApiConfig(){
        return new Docket(DocumentationType.SWAGGER_2).groupName("adminApi")
                .apiInfo(adminApiInfo())
                .select()
                .paths(Predicates.and(PathSelectors.regex("/admin/.*"))).build();
    }

    private ApiInfo webApiInfo(){
        return new ApiInfoBuilder().title("网站的API文档")
                .description("本文档描述了潇雷视频网的api接口定义")
                .version("1.0")
                .contact(new Contact("xiaolei","https://juejin.cn/user/96412756360526","***@qq.com"))
                .build();
    }
    private ApiInfo adminApiInfo(){
        return new ApiInfoBuilder().title("后台管理系统的API文档")
                .description("本文档描述了潇雷视频网的后台管理端api接口定义")
                .version("1.0")
                .contact(new Contact("xiaolei","https://juejin.cn/user/96412756360526","****@qq.com"))
                .build();
    }
}
复制代码

image.png

三、常见注解

3.1 API模型

entity的实体类中可以添加一些自定义设置,例如:

    @ApiModelProperty(value = "入驻时间",example = "2021-05-31")
    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
    private Date joinDate;
复制代码

3.2 定义接口说明和参数说明

  • @Api:修饰整个类,描述Controller的作用
  • @ApiOperation:描述一个类的一个方法,或者说一个接口
  • @ApiParam:单个参数描述
  • @ApiModel:用对象来接收参数
  • @ApiProperty:用对象接收参数时,描述对象的一个字段
  • @ApiResponse:HTTP响应其中1个描述
  • @ApiResponses:HTTP响应整体描述
  • @ApiIgnore:使用该注解忽略这个API
  • @ApiError :发生错误返回的信息
  • @ApiImplicitParam:描述一个请求参数,可以配置参数的中文含义,还可以给参数设置默认值
  • @ApiImplicitParams:描述由多个 @ApiImplicitParam 注解的参数组成的请求参数列表

————————————————

1. Swagger是什么?

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

个人觉得,swagger的一个最大的优点是能实时同步api与文档。在项目开发过程中,发生过多次:修改代码但是没有更新文档,前端还是按照老旧的文档进行开发,在联调过程中才发现问题的情况(当然依据开闭原则,对接口的修改是不允许的,但是在项目不稳定阶段,这种情况很难避免)。

2. spring boot 集成 Swagger

目前维护的系统是基于springboot框架开发的,因此本文会详细描述springboot与swagger集成的过程。

spring-boot系统集成swagger需要进行如下操作:

  1. 添加maven依赖,需要在系统的pom中添加如下依赖:

     <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.2.2</version>
     </dependency>
    
  2. 添加swagger配置文件,配置文件如下:

    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
    
        @Bean
        public Docket api() {
            return new Docket(DocumentationType.SWAGGER_2)
                    .select()  // 选择那些路径和api会生成document
                    .apis(RequestHandlerSelectors.any()) // 对所有api进行监控
                    .paths(PathSelectors.any()) // 对所有路径进行监控
                    .build();
        }
    
    }

    通过注解EnableSwagger2声明Swagger的可用性,此处会定义一个类型为Docket的bean,
    关于docket类的说明如下:

    A builder which is intended to be the primary interface into the swagger-springmvc framework.Provides sensible defaults and convenience methods for configuration.

    Docket的select()方法会提供给swagger-springmvc framework的一个默认构造器(ApiSelectorBuilder),这个构造器为配置swagger提供了一系列的默认属性和便利方法。

  3. 测试

    通过访问:http://localhost:8080/your-app-root/v2/api-docs ,能测试生成的api是否可用。此时返回的是一个json形式的页面,可读性不好。可以通过Swagger UI来生成一个可读性良好的api页面。具体做法就是,在pom中添加相关依赖。如下:

    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.2.2</version>
    </dependency>
    XML 复制 全屏

    再次访问:http://localhost:8080/your-app-root/swagger-ui.html 就可以看到可读性较好的api文档页面。

  4. 注意:

    1. http://localhost:8080/your-app-root/v2/api-docs 中your-app-root指的你的wabapp的根路径,我目前的webapp就默认在根路径下,所以地址是:http://localhost:8080/v2/api-docs
    2. spring-mvc上引用swagger需要做其他相关的配置,具体请查看参考文献
    3. swagger对restful风格的api支持的比较好,非restful风格的api支持的不是很好,对于非restful风格的api或者其他语言(非java语言)可以采用 http://editor.swagger 编辑器来收工完成相关的API编写

Swagger

1、集成springboot

第一步:pom

  <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>

第二步:swagger在springboot中配置

属性类(省略get/set方法)

/**
 * swagger配置,生成api
 *
 * @author lirui
 * @date 2018-07-26
 */
@ConfigurationProperties(prefix = "hyboot.api")
public class HySwaggerProperties {

    /**
     * 是否开启swagger
     */
    private boolean enabled = false;

    /**
     * API服务标题
     */
    private String title;

    /**
     * API服务描述
     */
    private String description;

    /**
     * API服务版本
     */
    private String version;

    /**
     * Api负责人相关信息
     */
    private Leader leader = new Leader();

    public static class Leader{

        /**
         * 负责人姓名
         */
        private String name;

        /**
         * 负责人邮箱
         */
        private String email;
    }

    /**
     * 用于生成api的html静态文档,需要配置
     */
    private Swagger swagger = new Swagger();

    public static class Swagger{
        /**
         * api 接口获取数据地址
         */
        private String apiUrl;

        /**
         * 生成文件的位置
         */
        private String filePath;
    }
}

配置application.yml

 enabled: false
 title: 测试服务api
 description: 用于测试
 leader:
   name: 汤姆
   email: tom@163.com
 version: 1.0.0

配置类

/**
 * swagger配置,生成api
 *
 * @author lirui
 * @date 2018-07-26
 */
@Configuration
@EnableConfigurationProperties({HySwaggerProperties.class})
@EnableSwagger2
public class HySwaggerAutoConfiguration {

    private Logger logger = LoggerFactory.getLogger(HySwaggerAutoConfiguration.class);
    @Autowired
    private ApplicationContext applicationContext;
    
    @Autowired
    private HySwaggerProperties hySwaggerProperties;
    
    @Autowired
    private ServerProperties serverProperties;

    /**
     * 定义api生成规则
     *
     * @return
     */
    @Bean
    public Docket hyApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                  //group为系统编号(我们spring的id设置为了系统编号)
                .groupName(applicationContext.getId())
                .apiInfo(apiInfo())
                //支持协议
                .protocols(Set.of("http", "https"))
                .select()
                 //限制只有在类上加@Api才添加到swagger,默认是都添加的
                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                 //限制只有在方法上加@Api才添加到swagger,默认是都添加的
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .build();
    }

    /**
     * api相关信息
     *
     * @return
     */
    public ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                //服务标题
                .title(hySwaggerProperties.getTitle() == null ?
                    applicationContext.getId() + "系统服务API" :                                                   hySwaggerProperties.getTitle())
                //api服务描述
                .description(hySwaggerProperties.getDescription())
                //api版本
                .version(hySwaggerProperties.getVersion())
                //联系人
                .contact(
                        new Contact(hySwaggerProperties.getLeader().getName(), "",
                                hySwaggerProperties.getLeader().getEmail()))
                .build();
    }
}

第三步:访问

http://host:port/contentPath/swagger-ui.html

swagger注解说明

    1、与模型相关的注解,用在bean上面

    @ApiModel:用在bean上,对模型类做注释;

    @ApiModelProperty:用在属性上,对属性做注释

  2、与接口相关的注解

    @Api:用在controller上,对controller进行注释;

    @ApiOperation:用在API方法上,对该API做注释,说明API的作用;

    @ApiImplicitParams:用来包含API的一组参数注解,可以简单的理解为参数注解的集合声明; 

    @ApiImplicitParam:用在@ApiImplicitParams注解中,也可以单独使用,说明一个请求参数的各个方面,该注解包含的常用选项有:

      paramType:参数所放置的地方,包含query、header、path、body以及form,最常用的是前四个。

      name:参数名;

      dataType:参数类型,可以是基础数据类型,也可以是一个class;

      required:参数是否必须传;

      value:参数的注释,说明参数的意义;

      defaultValue:参数的默认值;

    

    @ApiResponses:通常用来包含接口的一组响应注解,可以简单的理解为响应注解的集合声明;

    @ApiResponse:用在@ApiResponses中,一般用于表达一个响应信息

      code:即httpCode,例如400 

      message:信息,例如"操作成功"

      response = UserVo.class  这里UserVo是一个配置了@ApiModel注解的对像,该是对像属性已配置 @ApiModelProperty,swagger可以通过这些配置,生 成接口返回值

 

代码例子:

    @ApiOperation(value="获取用户详细信息", notes="根据url的id来获取用户详细信息")
    @ApiImplicitParam(paramType="path", name = "id", value = "用户ID", required = true, dataType = "Long")
    @RequestMapping(value="/{id}", method=RequestMethod.GET)
    public User getUser(@PathVariable Long id) {
        return users.get(id);
    }

 

网上好多例子都没有paramType这个参数,导致获取不到URL的参数,特意记录一下

详细的注解说明

  • @Api:用在类上,说明该类的作用
  • @ApiOperation:用在方法上,说明方法的作用
  • @ApiImplicitParams:用在方法上包含一组参数说明
  • @ApiImplicitParam:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面
    • paramType:参数放在哪个地方
      • header-->请求参数的获取:@RequestHeader
      • query-->请求参数的获取:@RequestParam
      • path(用于restful接口)-->请求参数的获取:@PathVariable
      • body(不常用)
      • form(不常用)
    • name:参数名
    • dataType:参数类型
    • required:参数是否必须传
    • value:参数的意思
    • defaultValue:参数的默认值
  • @ApiResponses:用于表示一组响应
  • @ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息
    • code:数字,例如400
    • message:信息,例如"请求参数没填好"
    • response:抛出异常的类
  • @ApiModel:描述一个Model的信息(这种一般用在post创建的时候,使用@RequestBody这样的场景,请求参数无法使用@ApiImplicitParam注解进行描述的时候)
    • @ApiModelProperty:描述一个model的属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@ApiOperation(value="添加博客", notes="新增博客")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "mess", value = "博客内容",
                    required = true, paramType = "query", dataType = "String")
    })
    @RequestMapping(value = "/addblog", method = RequestMethod.POST)
    public Result addBlog(@RequestBody Blog blog, @RequestParam(name = "mess", required = true)String mess, HttpServletRequest request){
        Integer userId = (Integer) request.getSession().getAttribute("userId");
        userId = 12;
        Integer effecNum = blogService.addBlog(blog, mess, userId);
        if(effecNum > 0)
            return new Result(ResultEnums.SUCCESS);
        return new Result(ResultEnums.PARAM_IS_INVAILD);
    }

这里只讲述@Api、@ApiOperation、@ApiImplicitParams、@ApiImplicitParam、@ApiParam、@ApiModel、@ApiModelProperty、ApiResponses、@ApiResponse这几个常用的。

方法/步骤

 
  1.  

    @Api:用在请求的类上,表示对类的说明常用参数:

    tags="说明该类的作用,非空时将覆盖value的值"

    value="描述类的作用"

    其他参数:

    description 对api资源的描述,在1.5版本后不再支持

    basePath 基本路径可以不配置,在1.5版本后不再支持

    position 如果配置多个Api 想改变显示的顺序位置,在1.5版本后不再支持

    produces 设置MIME类型列表(output),例:"application/json, application/xml",默认为空

    consumes 设置MIME类型列表(input),例:"application/json, application/xml",默认为空

    protocols 设置特定协议,例:http, https, ws, wss。

    authorizations 获取授权列表(安全声明),如果未设置,则返回一个空的授权值。

    hidden 默认为false, 配置为true 将在文档中隐藏

    示例:

    @Api(tags="登录请求")

    @Controller

    @RequestMapping(value="/highPregnant")

    public class LoginController {}

  2.  

    @ApiOperation:用在请求的方法上,说明方法的用途、作用

    常用参数:

    value="说明方法的用途、作用"

    notes="方法的备注说明"

    其他参数:

    tags 操作标签,非空时将覆盖value的值

    response 响应类型(即返回对象)

    responseContainer 声明包装的响应容器(返回对象类型)。有效值为 "List", "Set" or "Map"。

    responseReference 指定对响应类型的引用。将覆盖任何指定的response()类

    httpMethod 指定HTTP方法,"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS" and "PATCH"

    position 如果配置多个Api 想改变显示的顺序位置,在1.5版本后不再支持

    nickname 第三方工具唯一标识,默认为空

    produces 设置MIME类型列表(output),例:"application/json, application/xml",默认为空

    consumes 设置MIME类型列表(input),例:"application/json, application/xml",默认为空

    protocols 设置特定协议,例:http, https, ws, wss。

    authorizations 获取授权列表(安全声明),如果未设置,则返回一个空的授权值。

    hidden 默认为false, 配置为true 将在文档中隐藏

    responseHeaders 响应头列表

    code 响应的HTTP状态代码。默认 200

    extensions 扩展属性列表数组

    示例:

    @ResponseBody

    @PostMapping(value="/login")

    @ApiOperation(value = "登录检测", notes="根据用户名、密码判断该用户是否存在")

    public UserModel login(@RequestParam(value = "name", required = false) String account,

    @RequestParam(value = "pass", required = false) String password){}

  3.  

    @ApiImplicitParams:用在请求的方法上,表示一组参数说明

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

    name:参数名,参数名称可以覆盖方法参数名称,路径参数必须与方法参数一致

    value:参数的汉字说明、解释

    required:参数是否必须传,默认为false [路径参数必填]

    paramType:参数放在哪个地方

    · header --> 请求参数的获取:@RequestHeader

    · query --> 请求参数的获取:@RequestParam

    · path(用于restful接口)--> 请求参数的获取:@PathVariable

    · body(不常用)

    · form(不常用)

    dataType:参数类型,默认String,其它值dataType="Integer"

    defaultValue:参数的默认值

    示例:

    @ResponseBody

    @PostMapping(value="/login")

    @ApiOperation(value = "登录检测", notes="根据用户名、密码判断该用户是否存在")

    @ApiImplicitParams({

    @ApiImplicitParam(name = "name", value = "用户名", required = false, paramType = "query", dataType = "String"),

    @ApiImplicitParam(name = "pass", value = "密码", required = false, paramType = "query", dataType = "String")

    })

    public UserModel login(@RequestParam(value = "name", required = false) String account,

    @RequestParam(value = "pass", required = false) String password){}

    其他参数(@ApiImplicitParam):

    allowableValues 限制参数的可接受值。1.以逗号分隔的列表 2、范围值 3、设置最小值/最大值

    access 允许从API文档中过滤参数。

    allowMultiple 指定参数是否可以通过具有多个事件接受多个值,默认为false

    example 单个示例

    examples 参数示例。仅适用于BodyParameters

    @ApiModel:用于响应类上,表示一个返回响应数据的信息(这种一般用在post创建的时候,使用@RequestBody这样的场景,请求参数无法使用@ApiImplicitParam注解进行描述的时候)

    @ApiModelProperty:用在属性上,描述响应类的属性

    示例:

    @ApiModel(value="用户登录信息", description="用于判断用户是否存在")

    public class UserModel implements Serializable{

    private static final long serialVersionUID = 1L;

    /**

    * 用户名

    */

    @ApiModelProperty(value="用户名")

    private String account;

    /**

    * 密码

    */

    @ApiModelProperty(value="密码")

    private String password;

    }

    其他(@ApiModelProperty):

    value 此属性的简要说明。

    name 允许覆盖属性名称

    allowableValues 限制参数的可接受值。1.以逗号分隔的列表 2、范围值 3、设置最小值/最大值

    access 允许从API文档中过滤属性。

    notes 目前尚未使用。

    dataType 参数的数据类型。可以是类名或者参数名,会覆盖类的属性名称。

    required 参数是否必传,默认为false

    position 允许在类中对属性进行排序。默认为0

    hidden 允许在Swagger模型定义中隐藏该属性。

    example 属性的示例。

    readOnly 将属性设定为只读。

    reference 指定对相应类型定义的引用,覆盖指定的任何参数值

Swagger与SpringMVC整合

依赖管理

  在整合之前,需要把所有使用到的依赖包全部引入。网上很多文章只是简单告诉读者引入swagger-springmvc-1.0.2.jar包,但是随后你发现这远远不够,还需要很多包,如下所示:

<!-- swagger-springmvc -->
    <dependency>
        <groupId>com.mangofactory</groupId>
        <artifactId>swagger-springmvc</artifactId>
        <version>1.0.2</version>
    </dependency>
    <dependency>
        <groupId>com.mangofactory</groupId>
        <artifactId>swagger-models</artifactId>
        <version>1.0.2</version>
    </dependency>
    <dependency>
        <groupId>com.wordnik</groupId>
        <artifactId>swagger-annotations</artifactId>
        <version>1.3.11</version>
    </dependency>
    <!-- swagger-springmvc dependencies -->
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>15.0</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.4.4</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.4.4</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.4.4</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml</groupId>
        <artifactId>classmate</artifactId>
        <version>1.1.0</version>
    </dependency>

  以上是比较完整的依赖列表,本文搭建的项目可以正常运行。读者可能会有疑问,maven管理的依赖包不是具有传递性吗?是的,是有传递性,但是传递性是根据<scope>来界定的。打开swagger-springmvc依赖包的pom文件可以发现,其很多依赖包的scope值为compile或者provider,不会根据传递性自动引入。

二、Swagger配置

  Swagger的配置实际上就是自定义一个Config类,通过java编码的方式实现配置。代码如下:

import com.mangofactory.swagger.configuration.SpringSwaggerConfig;
import com.mangofactory.swagger.models.dto.ApiInfo;
import com.mangofactory.swagger.plugin.EnableSwagger;
import com.mangofactory.swagger.plugin.SwaggerSpringMvcPlugin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Created by xiaohui on 2016/1/14.
 */
@Configuration
@EnableSwagger
@EnableWebMvc
public class SwaggerConfig {

    private SpringSwaggerConfig springSwaggerConfig;

    /**
     * Required to autowire SpringSwaggerConfig
     */
    @Autowired
    public void setSpringSwaggerConfig(SpringSwaggerConfig springSwaggerConfig)
    {
        this.springSwaggerConfig = springSwaggerConfig;
    }

    /**
     * Every SwaggerSpringMvcPlugin bean is picked up by the swagger-mvc
     * framework - allowing for multiple swagger groups i.e. same code base
     * multiple swagger resource listings.
     */
    @Bean
    public SwaggerSpringMvcPlugin customImplementation()
    {
        return new SwaggerSpringMvcPlugin(this.springSwaggerConfig)
                .apiInfo(apiInfo())
                .includePatterns(".*?");
    }

    private ApiInfo apiInfo()
    {
        ApiInfo apiInfo = new ApiInfo(
                "My Apps API Title",
                "My Apps API Description",
                "My Apps API terms of service",
                "My Apps API Contact Email",
                "My Apps API Licence Type",
                "My Apps API License URL");
        return apiInfo;
    }
}

  上面这段代码是从网络上找到的,你也肯定找到了,对吧!但是,你会发现一个问题:SpringSwaggerConfig无法注入。这是为什么呢?其实很简单,因为spring容器里没有SpringSwaggerConfig类型的对象。解决办法:在springmvc的配置文件中加入以下配置即可。

<bean class="com.mangofactory.swagger.configuration.SpringSwaggerConfig" />

  到目前为止,我们已经完成了对所有接口方法的扫描解析功能,那解析得到什么内容呢?这需要我们自定义,自定义操作的对象就是接口方法。先看段代码:

/**
 * 根据用户名获取用户对象
 * @param name
 * @return
 */
@RequestMapping(value="/name/{name}", method = RequestMethod.GET)
@ResponseBody
@ApiOperation(value = "根据用户名获取用户对象", httpMethod = "GET", response = ApiResult.class, notes = "根据用户名获取用户对象")
public ApiResult getUserByName(@ApiParam(required = true, name = "name", value = "用户名") @PathVariable String name) throws Exception{
    UcUser ucUser = ucUserManager.getUserByName(name);

    if(ucUser != null) {
        ApiResult<UcUser> result = new ApiResult<UcUser>();
        result.setCode(ResultCode.SUCCESS.getCode());
        result.setData(ucUser);
        return result;
    } else {
        throw new BusinessException("根据{name=" + name + "}获取不到UcUser对象");
    }
}

  上述代码是Controller中的一个方法,@ApiOperation注解对这个方法进行了说明,@ApiParam注解对方法参数进行了说明。关于这两个注解的使用,可以参看源码。这样子,Swagger就可以扫描接口方法,得到我们自定义的接口说明内容。

     说明: 
     其中@ApiOperation和@ApiParam为添加的API相关注解,个参数说明如下: 
     @ApiOperation(value = “接口说明”, httpMethod = “接口请求方式”, response = “接口返回参数类型”, notes = “接口发布说明”;其他参数可参考源码; 
     @ApiParam(required = “是否必须参数”, name = “参数名称”, value = “参数具体描述”

三、Swagger-UI配置

  Swagger扫描解析得到的是一个json文档,对于用户不太友好。下面介绍swagger-ui,它能够友好的展示解析得到的接口说明内容。

  从https://github.com/swagger-api/swagger-ui 获取3.0版本以下,2.0版本以上。其所有的 dist 目录下东西放到需要集成的项目里,本文放入 src/main/webapp/WEB-INF/swagger/ 目录下。

  修改swagger/index.html文件,默认是从连接http://petstore.swagger.io/v2/swagger.json获取 API 的 JSON,这里需要将url值修改为http://{ip}:{port}/{projectName}/api-docs的形式,{}中的值根据自身情况填写。比如我的url值为:http://localhost:8083/arrow-api/api-docs

  因为swagger-ui项目都是静态资源,restful形式的拦截方法会将静态资源进行拦截处理,所以在springmvc配置文件中需要配置对静态文件的处理方式。

//所有swagger目录的访问,直接访问location指定的目录
<mvc:resources mapping="/swagger/**" location="/WEB-INF/swagger/"/>

  OK!大功告成,打开浏览器直接访问swagger目录下的index.html文件,即可看到接口文档说明了。注意访问地址哦!看下图:

 
@Bean
    public Docket apiDocument() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("api")
                .select() .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                .paths(regex("/api.*"))
                .build()
                .pathMapping("/")
                .globalOperationParameters(setHeaderToken())
                .apiInfo(metadata());
    }

主要添加 globalOperationParameters(setHeaderToken())

private List<Parameter> setHeaderToken() {
        ParameterBuilder tokenPar = new ParameterBuilder();
        List<Parameter> pars = new ArrayList<>();
        tokenPar.name("X-Auth-Token").description("token").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
        pars.add(tokenPar.build());
        return pars;
    }

简介

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。Swagger 让部署管理和使用功能强大的API从未如此简单。
这一次我将从零开始搭建一个工程来演示如何在Spring mvc中整合Swagger生成Restful接口文档。

新建工程

我们新建一个Maven工程,并添加Web Facet,工程结构如下图所示:

新建Maven工程

添加Maven依赖

 <properties>
        <spring.version>4.1.7.RELEASE</spring.version>
        <version.jackson>2.4.4</version.jackson>
        <swagger.version>2.2.2</swagger.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>com.mangofactory</groupId>
            <artifactId>swagger-springmvc</artifactId>
            <version>1.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>${version.jackson}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${version.jackson}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>${version.jackson}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${swagger.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <!--petstore是官方的一个demo,加入此依赖是为了稍后参考接口描述的编写-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-petstore</artifactId>
            <version>${swagger.version}</version>
        </dependency>

    </dependencies>

添加配置

添加一个ApplicationInitializer类,用于配置DispatchServlet启动:

在工程中的resources文件夹下新建一个spring的文件夹,并新建一个dispatcher-servlet.xml的spring mvc配置文件,添加如下内容:

添加一个SwaggerConfig类,用于配置Swagger接口的说明:

新建Controller

新建一个GroupController,并编写测试方法:

    package yay.apidoc.controller;

    import io.swagger.annotations.*;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import yay.apidoc.model.UamGroup;

    import java.util.LinkedList;
    import java.util.List;

    /**
     * Created by yuananyun on 2015/11/23.
     */
    @Controller
    @RequestMapping(value = "/group", produces = {"application/json;charset=UTF-8"})
    @Api(value = "/group", description = "群组的相关操作")
    public class GroupController {
        @RequestMapping(value = "addGroup", method = RequestMethod.PUT)
        @ApiOperation(notes = "addGroup", httpMethod = "POST", value = "添加一个新的群组")
        @ApiResponses(value = {@ApiResponse(code = 405, message = "invalid input")})
        public UamGroup addGroup(@ApiParam(required = true, value = "group data") @RequestBody UamGroup group) {
            return group;
        }

        @RequestMapping(value = "getAccessibleGroups", method = RequestMethod.GET)
        @ApiOperation(notes = "getAccessibleGroups", httpMethod = "GET", value = "获取我可以访问的群组的列表")
        public List<UamGroup> getAccessibleGroups() {
            UamGroup group1 = new UamGroup();
            group1.setGroupId("1");
            group1.setName("testGroup1");

            UamGroup group2 = new UamGroup();
            group2.setGroupId("2");
            group2.setName("testGroup2");

            List<UamGroup> groupList = new LinkedList<UamGroup>();
            groupList.add(group1);
            groupList.add(group2);

            return groupList;
        }
    }

其中UamGroup的定义如下:

    package yay.apidoc.model;
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;

    /**
     * 群组
     */
    @ApiModel
    public class UamGroup {
        /**
         * 编号
         */
        @ApiModelProperty(value = "群组的Id", required = true)
        private String groupId;
        /**
         * 名称
         */
        @ApiModelProperty(value = "群组的名称", required = true)
        private String name;
        /**
         * 群组图标
         */
        @ApiModelProperty(value = "群组的头像", required = false)
        private String icon;

        public String getGroupId() {
            return groupId;
        }

        public void setGroupId(String groupId) {
            this.groupId = groupId;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getIcon() {
            return icon;
        }

        public void setIcon(String icon) {
            this.icon = icon;
        }
    }

好,目前为止我们的代码已经编写完成,整个工程的目录结构如下:

为了让Swagger能够扫描Spring mvc中定义的Controller,我们需要在mvc的配置文件里面定义扫描的路径和相关的bean:

添加Swagger ui

在GitHub上下载SwaggerUI项目,将dist下所有内容拷贝到本地项目apidoc/web下面,结果目录如下图所示:

打开目录下的index.html文件,找到代码片段url = "http://petstore.swagger.io/v2/swagger.json";修改为“/apidoc/v2/api-docs”。
为了让网页显示中文,我们可以取消注释以下脚本:

为了能够访问index.html页面,我们在dispatcher-servlet.xml中添加如下配置:

        <!-- Enables swgger ui-->
        <mvc:resources mapping="*.html" location="/"/>
        <mvc:resources mapping="/**" location="/"/>

好,现在我们启动tomcat来看看效果:

解决中文乱码

可以看到,我们写在方法上说明居然成了乱码,为了解决这个问题,我们新建一个转换类:

    package yay.apidoc.converter;
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.databind.*;
    import org.springframework.http.HttpInputMessage;
    import org.springframework.http.converter.HttpMessageNotReadableException;
    import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

    import java.io.IOException;
    import java.text.SimpleDateFormat;

    /**
     * Created by yuananyun on 2015/11/23.
     */
    public class MappingJacksonHttpMessageConverterEx extends MappingJackson2HttpMessageConverter {
        private ObjectMapper objectMapper = new ObjectMapper();

        public MappingJacksonHttpMessageConverterEx() {
            super();
            DeserializationConfig deserializationConfig = objectMapper.getDeserializationConfig()
                    .without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
            objectMapper.setConfig(deserializationConfig);
            // Configure serialization
            SerializationConfig serializationConfig = objectMapper.getSerializationConfig()
                    .without(SerializationFeature.FAIL_ON_EMPTY_BEANS);
            //serializationConfig.withDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
            objectMapper.setConfig(serializationConfig);
            objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    //        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
            objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS,true);

            setObjectMapper(objectMapper);
        }

        @Override
        protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
                throws IOException, HttpMessageNotReadableException {
            JavaType javaType = getJavaType(null, clazz);
            return this.objectMapper.readValue(inputMessage.getBody(), javaType);
        }
    }

然后修改dispatcher-servlet.xml中的mvc:annotation-driven配置节:

        <!-- Standard xml based mvc config-->
        <mvc:annotation-driven>
            <mvc:message-converters>
                <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                    <property name="supportedMediaTypes">
                        <list>
                            <value>text/html;charset=UTF-8</value>
                        </list>
                    </property>
                </bean>
                <bean class="yay.apidoc.converter.MappingJacksonHttpMessageConverterEx"/>
                <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
            </mvc:message-converters>
        </mvc:annotation-driven>

我们再来看看效果:

 

posted @ 2022-05-07 22:56  hanease  阅读(1009)  评论(0编辑  收藏  举报