zoukankan      html  css  js  c++  java
  • SpringBoot整合Swagger2

    相信各位在公司写API文档数量应该不少,当然如果你还处在自己一个人开发前后台的年代,当我没说,如今为了前后台更好的对接,还是为了以后交接方便,都有要求写API文档。

    手写Api文档的几个痛点:

    1. 文档需要更新的时候,需要再次发送一份给前端,也就是文档更新交流不及时。
    2. 接口返回结果不明确
    3. 不能直接在线测试接口,通常需要使用工具,比如postman
    4. 接口文档太多,不好管理

    Swagger也就是为了解决这个问题,当然也不能说Swagger就一定是完美的,当然也有缺点,最明显的就是代码移入性比较强。

    其他的不多说,想要了解Swagger的,可以去Swagger官网,可以直接使用Swagger editor编写接口文档,当然我们这里讲解的是SpringBoot整合Swagger2,直接生成接口文档的方式。

    一、依赖

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

    二、Swagger配置类

    其实这个配置类,只要了解具体能配置哪些东西就好了,毕竟这个东西配置一次之后就不用再动了。 特别要注意的是里面配置了api文件也就是controller包的路径,不然生成的文档扫描不到接口。

    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
        /**
         * 创建API
         */
        @Bean
        public Docket createRestApi() {
            return new Docket(DocumentationType.SWAGGER_2)
                    // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
                    .apiInfo(apiInfo())
                    // 设置哪些接口暴露给Swagger展示
                    .select()
                    // 扫描所有有注解的api,用这种方式更灵活
                    .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                    // 扫描指定包中的swagger注解
                    // .apis(RequestHandlerSelectors.basePackage("com.ruoyi.project.tool.swagger"))
                    // 扫描所有 .apis(RequestHandlerSelectors.any())
                    .paths(PathSelectors.any()).build();
        }
    
        /**
         * 添加摘要信息
         */
        private ApiInfo apiInfo() {
            // 用ApiInfoBuilder进行定制
            return new ApiInfoBuilder()
                    // 设置标题
                    .title("标题:若依管理系统_接口文档")
                    // 描述
                    .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
                    // 作者信息
                    .contact(new Contact(Global.getName(), null, null))
                    // 版本
                    .version("版本号:" + Global.getVersion()).build();
        }
    }

    用@Configuration注解该类,等价于XML中配置beans;用@Bean标注方法等价于XML中配置bean。

    Application.class 加上注解@EnableSwagger2 表示开启Swagger

    package cn.saytime;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    @SpringBootApplication
    @EnableSwagger2
    public class SpringbootSwagger2Application {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootSwagger2Application.class, args);
        }
    }

    三、Restful 接口

    package cn.saytime.web;
    
    import cn.saytime.bean.JsonResult;
    import cn.saytime.bean.User;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiImplicitParam;
    import io.swagger.annotations.ApiImplicitParams;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    import springfox.documentation.annotations.ApiIgnore;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @author zh
     * @ClassName cn.saytime.web.UserController
     * @Description
     */
    @RestController
    public class UserController {
    
        // 创建线程安全的Map
        static Map<Integer, User> users = Collections.synchronizedMap(new HashMap<Integer, User>());
    
        /**
         * 根据ID查询用户
         * @param id
         * @return
         */
        @ApiOperation(value="获取用户详细信息", notes="根据url的id来获取用户详细信息")
        @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Integer", paramType = "path")
        @RequestMapping(value = "user/{id}", method = RequestMethod.GET)
        public ResponseEntity<JsonResult> getUserById (@PathVariable(value = "id") Integer id){
            JsonResult r = new JsonResult();
            try {
                User user = users.get(id);
                r.setResult(user);
                r.setStatus("ok");
            } catch (Exception e) {
                r.setResult(e.getClass().getName() + ":" + e.getMessage());
                r.setStatus("error");
                e.printStackTrace();
            }
            return ResponseEntity.ok(r);
        }
    
        /**
         * 查询用户列表
         * @return
         */
        @ApiOperation(value="获取用户列表", notes="获取用户列表")
        @RequestMapping(value = "users", method = RequestMethod.GET)
        public ResponseEntity<JsonResult> getUserList (){
            JsonResult r = new JsonResult();
            try {
                List<User> userList = new ArrayList<User>(users.values());
                r.setResult(userList);
                r.setStatus("ok");
            } catch (Exception e) {
                r.setResult(e.getClass().getName() + ":" + e.getMessage());
                r.setStatus("error");
                e.printStackTrace();
            }
            return ResponseEntity.ok(r);
        }
    
        /**
         * 添加用户
         * @param user
         * @return
         */
        @ApiOperation(value="创建用户", notes="根据User对象创建用户")
        @ApiImplicitParam(name = "user", value = "用户详细实体user", required = true, dataType = "User")
        @RequestMapping(value = "user", method = RequestMethod.POST)
        public ResponseEntity<JsonResult> add (@RequestBody User user){
            JsonResult r = new JsonResult();
            try {
                users.put(user.getId(), user);
                r.setResult(user.getId());
                r.setStatus("ok");
            } catch (Exception e) {
                r.setResult(e.getClass().getName() + ":" + e.getMessage());
                r.setStatus("error");
    
                e.printStackTrace();
            }
            return ResponseEntity.ok(r);
        }
    
        /**
         * 根据id删除用户
         * @param id
         * @return
         */
        @ApiOperation(value="删除用户", notes="根据url的id来指定删除用户")
        @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long", paramType = "path")
        @RequestMapping(value = "user/{id}", method = RequestMethod.DELETE)
        public ResponseEntity<JsonResult> delete (@PathVariable(value = "id") Integer id){
            JsonResult r = new JsonResult();
            try {
                users.remove(id);
                r.setResult(id);
                r.setStatus("ok");
            } catch (Exception e) {
                r.setResult(e.getClass().getName() + ":" + e.getMessage());
                r.setStatus("error");
    
                e.printStackTrace();
            }
            return ResponseEntity.ok(r);
        }
    
        /**
         * 根据id修改用户信息
         * @param user
         * @return
         */
        @ApiOperation(value="更新信息", notes="根据url的id来指定更新用户信息")
        @ApiImplicitParams({
                @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long",paramType = "path"),
                @ApiImplicitParam(name = "user", value = "用户实体user", required = true, dataType = "User")
        })
        @RequestMapping(value = "user/{id}", method = RequestMethod.PUT)
        public ResponseEntity<JsonResult> update (@PathVariable("id") Integer id, @RequestBody User user){
            JsonResult r = new JsonResult();
            try {
                User u = users.get(id);
                u.setUsername(user.getUsername());
                u.setAge(user.getAge());
                users.put(id, u);
                r.setResult(u);
                r.setStatus("ok");
            } catch (Exception e) {
                r.setResult(e.getClass().getName() + ":" + e.getMessage());
                r.setStatus("error");
    
                e.printStackTrace();
            }
            return ResponseEntity.ok(r);
        }
    
        @ApiIgnore//使用该注解忽略这个API
        @RequestMapping(value = "/hi", method = RequestMethod.GET)
        public String  jsonTest() {
            return " hi you!";
        }
    }

    Json格式输出类 JsonResult.class

    package cn.saytime.bean;
    
    public class JsonResult {
    
        private String status = null;
    
        private Object result = null;
    
        // Getter Setter
    }

    实体User.class

    package cn.saytime.bean;
    
    import java.util.Date;
    
    /**
     * @author zh
     * @ClassName cn.saytime.bean.User
     * @Description
     */
    public class User {
    
        private int id;
        private String username;
        private int age;
        private Date ctm;
    
        // Getter Setter
    }

    四、Swagger2文档

    启动SpringBoot项目,访问 http://localhost:8080/swagger-ui.html

    运行项目,这个时候可能会报这个错,如下所示

    2018-05-28 14:40:56.887 ERROR [main] o.s.boot.SpringApplication - Application startup failed
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerAdapter' defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Initialization of bean failed; nested exception is java.lang.NoSuchMethodError: com.google.common.collect.FluentIterable.toList()Lcom/google/common/collect/ImmutableList;
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107)
        at com.qtay.gls.Application.main(Application.java:24)
    Caused by: java.lang.NoSuchMethodError: com.google.common.collect.FluentIterable.toList()Lcom/google/common/collect/ImmutableList;
        at springfox.documentation.spring.web.ObjectMapperConfigurer.jackson2Converters(ObjectMapperConfigurer.java:76)
        at springfox.documentation.spring.web.ObjectMapperConfigurer.configureMessageConverters(ObjectMapperConfigurer.java:63)
        at springfox.documentation.spring.web.ObjectMapperConfigurer.postProcessBeforeInitialization(ObjectMapperConfigurer.java:47)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:409)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1620)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
        ... 15 common frames omitted
    
    Process finished with exit code 1

    在网上搜索了下,加入下面这段代码就OK了!

    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.8.0</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.8.0</version>
    </dependency>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>25.1-jre</version>
    </dependency>

    五、Swagger注解

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

    • @Api:修饰整个类,描述Controller的作用
    • @ApiOperation:描述一个类的一个方法,或者说一个接口
    • @ApiParam:单个参数描述
    • @ApiModel:用对象来接收参数
    • @ApiProperty:用对象接收参数时,描述对象的一个字段
    • @ApiResponse:HTTP响应其中1个描述
    • @ApiResponses:HTTP响应整体描述
    • @ApiIgnore:使用该注解忽略这个API
    • @ApiError :发生错误返回的信息
    • @ApiImplicitParam:一个请求参数
    • @ApiImplicitParams:多个请求参数
  • 相关阅读:
    python time 转换&运算tips
    Web.py session用户认证
    简单的内存池实现gko_alloc
    cpp(第十章)
    cpp(第九章)
    cpp(第八章)
    cpp(第七章)
    cpp(第六章)
    cpp(第五章)
    结构中的位字段
  • 原文地址:https://www.cnblogs.com/deityjian/p/10946253.html
Copyright © 2011-2022 走看看