Swagger2企业实战

一、引入swagger的目的

相信看这篇文章的小伙伴已经知道它的好处了,此次就不多说了,还不清楚的找谷歌、百度。

二、本文借用Swagger要实现的效果

1.后端人员在代码里根据swagger语法打些标签,生成可预览的Api文档,方便前端及app人员开发,无须再维护一份Word文档。
2.Swagger文档token机制的优化
3.分组显示api
4.最核心、最重要的一点:让Swagger支持自定义注解。

三、功能实现

1.添加依赖
spring-boot版本:1.5.7;swagger2版本:2.7.0

      <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.创建swagger2配置类

@Configuration
@EnableSwagger2
//@Profile({"dev", "test"})//在生产环境不开启,此方式有问题,待查找资料解决,故用下面设置布尔值来实现安全控制
public class Swagger2 {

    @Value("${swagger.show}")
    private boolean swaggerShow;

    /**
     * 全局设置Content Type,默认是application/json
     * 如果想只针对某个方法,则注释掉改语句,在特定的方法加上下面信息
     * @ApiOperation(consumes="application/x-www-form-urlencoded")
     */

    public static final HashSet<String> consumes = new HashSet<String>() {{
        add("application/x-www-form-urlencoded");
    }};

    /**实现点:业务系统的token认证机制**/
    public List getTokenPar(){
         ParameterBuilder tokenPar = new ParameterBuilder();
         List<Parameter> pars = new ArrayList<Parameter>();
         tokenPar.name("Authorization")
                 .description("认证信息")
                 .modelRef(new ModelRef("string")).parameterType("header").required(true).build();
         pars.add(tokenPar.build());
         
         return pars;
    }

    @Bean
    public Docket createRestApi() {
        
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(this.swaggerShow)//是否开启swagger
                .groupName("例子")
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.zxy.product.training.web.example"))//扫描包
                .paths(
())
                .build()
                .globalOperationParameters(getTokenPar())
                .consumes(Swagger2.consumes);
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("例子模块")//标题
                .description("例子模块接口调试")
                .contact("cenjiajun的简书")
                .version("1.0")
                .build();
    }
    /**实现点:分组显示api**/
    private Predicate<String> examplePaths() {
        return PathSelectors.regex("/cjj-example.*");
    }
}

如上,已经实现了前三点功能:生成api文档,分组显示api,业务系统token认证。

3.实现swagger支持自定义注解

@Component
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 10000)
public class SwaggerRequestConditionReader extends AbstractOperationParameterRequestConditionReader {

    @Autowired
    private TypeResolver paramTypeResolver;

    public SwaggerRequestConditionReader(TypeResolver resolver) {
        super(resolver);
    }

    @Override
    public void apply(OperationContext context) {
        // @Params为业务系统自定义注解,主要是做入参校验跟swagger2原生标签@ApiImplicitParams类似
        Optional<Params> paramsAnnotation =  context.findAnnotation(Params.class);
        // @Param为业务系统自定义注解,主要是做入参校验跟swagger2原生标签@ApiImplicitParam类似
        Optional<Param> paramAnnotation =  context.findAnnotation(Param.class);

        // 获取标签上的属性
        if (paramsAnnotation.isPresent()) {
            Params params = paramsAnnotation.get();
            List<Parameter> parameters = Arrays.stream(params.value()).map(param -> {
                Parameter parameter = createParameter(param);
                return parameter;
            }).collect(Collectors.toList());
            context.operationBuilder().parameters(parameters);
        }

        if (paramAnnotation.isPresent()) {
            Param param = paramAnnotation.get();
            List<Parameter> parameters = newArrayList();
            parameters.add(createParameter(param));
            context.operationBuilder().parameters(parameters);
        }
    }

    private Parameter createParameter(Param param) {
        Parameter parameter = (new ParameterBuilder())
                .name(param.name())
                .description(param.value())
                .defaultValue(param.defaultValue())
                .required(param.required())
                .type(paramTypeResolver.resolve(param.type()))
                .modelRef(new ModelRef(param.type().getSimpleName().equals(Integer.class.getSimpleName())?int.class.getSimpleName():param.type().getSimpleName()))//解决无法识别Integer问题
                .parameterType(StringUtils.isEmpty(param.paramType())?"query":param.paramType()).build();//如果不传paramType字段取默认值
        return parameter;
    }
}

4.在方法上使用自定义标签

    @ApiOperation(value = "xxx数据请求接口", notes = "xx请求数据接口,用于判断当前是否允许报名等")
    @RequestMapping(value = "/front-check/{id}", method = RequestMethod.GET)
    @Permitted
    @Param(name = "id", required = true, value="班级id", paramType = "path",type = String.class)
    @JSON("xx,xx,xx,xx,xx")
    @JSON("classStudent.(id,xx,status,xx)")
    public ClassInfo getForRegisterCheck(RequestContext requestContext, Subject<Member> subject) {
        return classInfoService.getForRegisterCheck(requestContext.getString("id"), subject.getCurrentUserId());
    }

说明:swagger2默认的contenttype为json,上面配置类我已改成表单格式。 @Param里的name属性就是表单上的key,required表示该字段是否为必填项,value就是对属性的解释说明,type说明了该字段的数据类型,而paramType = "path"用来获取/{xx}参数,其它情况下用query即可,我已改成默认,详情见第三点

四、API文档访问与调试

访问方式:ip地址+:8010/api/v1/xx(如果配置了代理,就无需这段)+/swagger-ui.htm。如:http://192.168.0.145:8010/api/v1/xx/swagger-ui.html

分组效果.png

带有token的模拟请求.png

五、安全问题

系统上生产环境时应当禁止访问swagger,防止被攻击,所以该插件只适用于开发和测试环境。目前有两种灵活切换方式,其中有一种存在bug,待寻求解决方案。

方案一:配置文件的多环境配置(有问题,暂时不用)

application-pro.properties
application-dev.properties
application-test.properties
application.properties
在application.properties加入以下配置:
spring.profiles.active=dev或者test或者pro

方案二:在配置文件给一个布尔值
swagger.show=true

最后:如果想通过命令修改配置文件信息,可这样操作java -jar xxx.jar --spring.profiles.active=dev java -jar xxx.jar --swagger.show=false。不过采用微服务架构一般都会配套使用自动发版工具,此时就只能配置个环境变量了。

六、支持自定义返回注解@xx(待研究)实现返回值带有解释说明。

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,465评论 25 707
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,744评论 6 342
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • R: 《爱的五种能力》赵永久 I:引导促进 之前也一直知道共情的重要性,尤其是在很多亲子育儿书中经常会提到要想更好...
    心有jing气阅读 450评论 0 1
  • 力合股份(000532) 公司拟更名为“华金资本”,已获董事会和股东大会通过,尚待工商部门和交易所核准,未来将不断...
    每日一股ngtt600519阅读 215评论 0 0