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

      
           io.springfox
           springfox-swagger2
           2.7.0
       
       
           io.springfox
           springfox-swagger-ui
           2.7.0
       

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 consumes = new HashSet() {{
        add("application/x-www-form-urlencoded");
    }};

    /**实现点:业务系统的token认证机制**/
    public List getTokenPar(){
         ParameterBuilder tokenPar = new ParameterBuilder();
         List pars = new ArrayList();
         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 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 paramsAnnotation =  context.findAnnotation(Params.class);
        // @Param为业务系统自定义注解,主要是做入参校验跟swagger2原生标签@ApiImplicitParam类似
        Optional paramAnnotation =  context.findAnnotation(Param.class);

        // 获取标签上的属性
        if (paramsAnnotation.isPresent()) {
            Params params = paramsAnnotation.get();
            List 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 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 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

Swagger2企业实战_第1张图片
分组效果.png

Swagger2企业实战_第2张图片
带有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(待研究)实现返回值带有解释说明。

你可能感兴趣的:(Swagger2企业实战)