Spring Boot 使用swagger2

swagger2可以减少我们的编写文档工作,尤其现在是前后端分离。后端写好接口之后还需要写API使用文档给客户端人员,尤其是在接口变更之后,文档往往就得不到及时的更新甚至是遗忘,导致文档最终变得不可信。这个框架可以帮助解决此类问题,减少后端人员的工作量,同时还能保持维护文档的地方只有一处。

这个框架也只是帮助减少上述问题,如果只是修改了代码,而没有更新相应的描述信息等,也是会存在上述问题的。

一、准备工作

添加依赖,在pom.xml文件添加如下的依赖:

        <!--swagger2-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.6.1</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.6.1</version>
        </dependency>

二、配置swagger2

在Application.java平级的包下,新建一个Swagger2的类,内容如下,其中需要注意的是createRestApi方法下的包名为自己项目中的包名,一般为控制器所在的包。

**
 * Swagger2配置类
 * 1)在集成spring boot时,放在与Application.java同级目录下
 * 2)@Configuration注解的作用是让spring 来加载该类的配置
 * 3)@EnableSwagger2 是用来启用swagger2
 *
 * @author xiaozhao
 * @date 2018/10/19下午3:14
 */
@Configuration
@EnableSwagger2
public class Swagger2 {

    /**
     * 指定扫描包的路径来指定要创建API的目录,一般是控制器这个包
     *
     * @return
     */
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.xiaozhao.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    /**
     * 设置API的基本信息
     *
     * @return
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("我的公司")
                .description("后端接口说明文档")
                .termsOfServiceUrl("https://www.jianshu.com")
                .version("1.0")
                .build();
    }
}
image.png

三、swagger2常用注解说明

  • @Api()
    value: 不能显示到UI上
    tags:一个字符串数组,说明整个类的作用,会显示在UI上。此处发现一个问题,就是为中文时,导致接口在UI上不能展开。

修饰在类上,描述一个类的作用。例如:

@Api(value = "欢迎", tags = {"用户操作接口说明"})
public class HelloController {
}
  • @ApiOperation()
    value:说明方法的用途、作用
    notes:方法的备注说明
    修饰方法,说明方法的作用,例如:
    @GetMapping("/hi")
    @ApiOperation(value = "问候语", notes = "这是一个问候", httpMethod = "GET")
    public String hello() {
        return "Hell World";
    }
  • @ApiImplicitParams
    是一个@ApiImplicitParam的数组,用在请求的方法上,包含一组参数说明

  • @ApiImplicitParam
    name:参数名
    value:参数的汉字说明,描述信息
    required:是否必需
    dataType:参数类型,默认String,其它值dataType="Integer" 或dataType="User" 或 ......
    defaultValue:参数的默认值
    paramType:参数放在哪个地方

            header --> 请求参数的获取:@RequestHeader
            query --> 请求参数的获取:@RequestParam
            path(用于restful接口)--> 请求参数的获取:@PathVariable
            body(不常用)
            form(不常用)  

用来说明方法的参数,例如:

    @RequestMapping(value = "/update/{id}", method = RequestMethod.PUT)
    @ApiOperation(value = "更新信息", notes = "根据url的id来指定更新用户信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long", paramType = "path"),
            @ApiImplicitParam(name = "user", value = "用户实体", required = true, dataType = "User")
    })
    public String putUser(@PathVariable Long id, @RequestBody User user) {
        System.out.println(id);
        System.out.println(user.getId());
        System.out.println(user.getName());
        return "修改成功";
    }
  • @ApiParam
    name:参数名
    value:参数的汉字说明,描述信息
    required:是否必需
    用于方法、参数的说明,例如:
    @ApiOperation("更改用户信息")
    @PostMapping("/updateUserInfo")
    public int test(@RequestBody @ApiParam(name = "用户对象", value = "传入json格式", required = true) User user) {
        return 1;
    }
  • @ApiResponses
    是一个@ApiResponse的数组,用于请求的方法上,表示一组响应

  • @ApiResponse()
    code:标准的http响应码,例如404,500,502等
    message:错误信息,例如“参数错误”
    response:抛出异常的类
    修饰方法,表达一个错误的响应,例如:

    @GetMapping("/hi")
    @ApiOperation(value = "问候语", notes = "这是一个问候", httpMethod = "GET")
    @ApiResponses({
            @ApiResponse(code = 400, message = "请求参数没填好"),
            @ApiResponse(code = 404, message = "请求路径没有或页面跳转路径不对")
    })
    public String hello() {
        return "Hell World";
    }
  • @ApiModel()
    value:类名
    description:描述

一般用于参数为一个实体类时,说明这个类的各项属性的含义。只能修饰在类上,需要配合@ApiProperty一起使用,例如:

@ApiModel
public class User implements Serializable {
    private static final long serialVersionUID = -1084928517040754103L;
}
  • @ApiModelProperty()
    name:属性名称
    value:描述
    dataType:属性的数据类型
    required:是否必填
    example:举例说明
    hidden:在文档上是否不可见

修饰实体类的属性,例如:

    @ApiModelProperty(value = "用户id", name = "id", required = false)
    private Integer id;

    @ApiModelProperty(value = "用户名称", name = "name", required = true,example = "张飒")
    private String name;


   //省略  getter and setter 
image.png

*@ApiIgnore
可以修饰类或者非法,然后在文档中不再显示

四、项目中使用

用户实体类

/**
 * 用户实体类
 *
 * @author xiaozhao
 * @date 2018/10/19下午3:35
 */
@ApiModel
public class User implements Serializable {

    private static final long serialVersionUID = -1084928517040754103L;
    @ApiModelProperty(value = "用户id", name = "id", required = false)
    private Integer id;

    @ApiModelProperty(value = "用户名称", name = "name", required = true, example = "张飒")
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

控制器

/**
 * swagger2 示例
 *
 * @author xiaozhao
 * @date 2018/10/19下午3:17
 */
@RestController
@RequestMapping("/api")
@Api(value = "Welcome", tags = {"User Guide"})
public class HelloController {

    /**
     * 无参数,只有说明
     *
     * @return 返回字符串
     */
    @GetMapping("/hi")
    @ApiOperation(value = "问候语", notes = "这是一个问候", httpMethod = "GET")
    @ApiResponses({
            @ApiResponse(code = 400, message = "请求参数没填好"),
            @ApiResponse(code = 404, message = "请求路径没有或页面跳转路径不对")
    })
    public String hello() {
        return "Hell World";
    }

    /**
     * 无参数
     *
     * @return 返回一个对象
     */
    @GetMapping("/list")
    @ApiOperation(value = "列表", notes = "获取用户列表", httpMethod = "GET")
    public HttpResult list() {
        HttpResult httpResult = new HttpResult();
        httpResult.setCode(0);
        httpResult.setMsg("");
        List<User> list = new ArrayList<>();
        User user = new User();
        user.setId(1);
        user.setName("James");
        list.add(user);
        httpResult.setData(list);
        return httpResult;
    }


    /**
     * 有一个简单类型的参数,rest风格
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/find/{id}", method = RequestMethod.GET)
    @ApiOperation(value = "查找用户", notes = "查找某个用户的详细信息")
    @ApiImplicitParam(name = "id", value = "用户唯一标识", required = true, dataType = "Long", paramType = "path")
    public User getBook(@PathVariable Long id) {
        System.out.println(id);
        User user = new User();
        user.setId(1);
        user.setName("库里");
        return user;
    }

    /**
     * 有一个引用类型的参数
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    @ApiOperation(value = "添加用户", notes = "添加一个新的用户")
    @ApiImplicitParam(name = "user", value = "用户详细实体", required = true, dataType = "User")
    public String postBook(@RequestBody User user) {
        System.out.println(user);
        return "添加用户成功";
    }


    /**
     * 有一个简单类型的参数和一个引用类型的参数
     *
     * @param id
     * @param user
     * @return
     */
    @RequestMapping(value = "/update/{id}", method = RequestMethod.PUT)
    @ApiOperation(value = "更新信息", notes = "根据url的id来指定更新用户信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long", paramType = "path"),
            @ApiImplicitParam(name = "user", value = "用户实体", required = true, dataType = "User")
    })
    public String putUser(@PathVariable Long id, @RequestBody User user) {
        System.out.println(id);
        System.out.println(user.getId());
        System.out.println(user.getName());
        return "修改成功";
    }

    /**
     * 有一个Long的参数
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/del_user/{id}", method = RequestMethod.DELETE)
    @ApiOperation(value = "删除用户", notes = "根据id来删除指定用户")
    @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long", paramType = "path")
    public String deleteUser(@PathVariable Long id) {
        System.out.println("删除用户:" + id);
        return "success";
    }

    /**
     * 使用该注解忽略这个API
     *
     * @return
     */
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    @ApiIgnore
    public String jsonTest() {
        return " hi you!";
    }


    @ApiOperation("更改用户信息")
    @PostMapping("/updateUserInfo")
    public int test(@RequestBody @ApiParam(name = "用户对象", value = "传入json格式", required = true) User user) {
        return 1;
    }
}

最后运行项目,然后在浏览器中打开 http://localhost:8080/swagger-ui.html

看到如下界面

image.png

image.png

完整代码

https://github.com/xiaozhaowen/spring-boot-in-action/tree/master/springboot-swagger2

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351