spring boot 项目集成 knife4j 2.0.5 并实现入参分组校验显示

本贴最后更新于 1113 天前,其中的信息可能已经时移俗易

之前写过一篇:前后端分离时如何优雅的编写 API 文档

不过其中的部分配置还不够完善,本次对其进行一定的优化。

1 路径分组配置

项目中,有的路径需要登录,有的不需要登录,需要登录的接口还可能需要配置全局 header,用于传输校验使用的 token 等

这里是使用路径进行是否需要登录的匹配,其中,路径包含/pub,则不需要登录,否则,需要登录,同时扫描多个路径,路径之前用英文逗号(,)隔开即可

具体实现如下:

@Autowired
    private SwaggerProperties properties;
	
	@Bean(value = "defaultApi")
    public Docket defaultApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .useDefaultResponseMessages(false)
                .apiInfo(apiInfo())
                .groupName(properties.getGroupName() + "-待认证")
                .select()
                .apis(getPredicate())
                .paths(PathSelectors.regex("^((?!pub).)*$"))
                .build()
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
    }

    @Bean(value = "pubApi")
    public Docket pubApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .useDefaultResponseMessages(false)
                .apiInfo(apiInfo())
                .groupName(properties.getGroupName() + "-无认证")
                .select()
                .apis(getPredicate())
                .paths(PathSelectors.regex("^.*pub.*$"))
                .build();
    }
    
    //拼接多路径扫描以实现多包扫描支持
    private Predicate getPredicate() {
        String[] split = properties.getBasePackage().split(",");
        Predicate predicate = null;
        for (String s : split) {
            Predicate secPredicate = RequestHandlerSelectors.basePackage(s);
            predicate = predicate == null ? secPredicate : Predicates.or(secPredicate, predicate);
        }
        return predicate;
    }

    private List<ApiKey> securitySchemes() {
        return newArrayList(
                new ApiKey(properties.getHeader(), properties.getHeader(), "header"));
    }

    private List<SecurityContext> securityContexts() {
        return newArrayList(
                SecurityContext.builder()
                        .securityReferences(defaultAuth())
                        .forPaths(PathSelectors.regex("^((?!pub).)*$"))
                        .build()
        );
    }

    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return newArrayList(
                new SecurityReference(properties.getHeader(), authorizationScopes));
    }

SwaggerProperties 配置文件只是把变化的配置放到了配置文件中进行配置

这样,访问 http://{IP}:{port}/doc.html 地址,即可看到效果

2 访问控制

knife 提供了简单的 basic 认证,其中

登录访问:SecurityBasicAuthFilter、生产环境屏蔽:ProductionSecurityFilter

由于项目自定义了部分配置,为了统一,自己实现注入时机

@Bean
    @ConditionalOnMissingBean(SecurityBasicAuthFilter.class)
    @ConditionalOnProperty(name = "swagger.certifiable", havingValue = "true")
    public SecurityBasicAuthFilter securityBasicAuthFilter(SwaggerProperties properties) {
        return new SecurityBasicAuthFilter(properties.getCertifiable(), properties.getUsername(), properties.getPassword());
    }

    @Bean
    @ConditionalOnMissingBean(ProductionSecurityFilter.class)
    @ConditionalOnProperty(name = "swagger.prod", havingValue = "true")
    public ProductionSecurityFilter productionSecurityFilter(SwaggerProperties properties) {
        return new ProductionSecurityFilter(properties.getProd());
    }

这样,在 SwaggerProperties 中配置相应的信息,即可实现相关功能

3 入参分组

在开发的时候,会遇到这样一个情况:

一个 VO 对象在新增的时候某些字段为必填,在更新的时候又非必填。比如用户新增和编辑功能,新增时 id 不是必填,编辑时是必须的,其他的字段如用户名等都是一样新增、编辑都为必填。

而在 swagger 中,不属于新增接口的 id 字段,就不应该显示到文档上,避免前端集成接口不知如何传参的问题

以前是新增、编辑使用不同的实体,或者编辑继承新增实体,再加上 id 字段,但是这样会造成项目中有很多的实体,类臃肿

基于此需求,可以借助 javax.validation.groups 分组功能以及 @Validated 来实现,同时扩展 swagger 的功能,此处参考:https://blog.csdn.net/jianzhang11/article/details/119632467

3.1 自定义分组

import javax.validation.groups.Default;

public interface ValidGroup extends Default {
    interface Create extends ValidGroup {
    }

    interface Update extends ValidGroup {
    }

    interface Query extends ValidGroup {
    }

    interface Delete extends ValidGroup {
    }
}

3.2 使用

controller 层入参上添加分组信息,如:

新增:ValidGroup.Create.class

public RestResult<String> insertUser(@RequestBody @Validated(ValidGroup.Create.class) UserBO user) {
    return usersService.insertUser(user);
}

编辑:ValidGroup.Update.class

public RestResult<String> updateUser(@RequestBody @Validated(ValidGroup.Update.class) UserBO user) {
    return usersService.updateUser(user);
}

入参实体中:

public class UserBO implements Serializable {
    private static final long serialVersionUID = 5699245096095831445L;

    @ApiModelProperty(value = "ID")
    @Null(groups = ValidGroup.Create.class)
    @NotNull(groups = ValidGroup.Update.class, message = "ID不可为空")
    private Long id;
}

这样,再访问新增、编辑接口,即可看到效果。

  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    942 引用 • 1459 回帖 • 58 关注
  • knife4j
    4 引用
  • Swagger

    Swagger 是一款非常流行的 API 开发工具,它遵循 OpenAPI Specification(这是一种通用的、和编程语言无关的 API 描述规范)。Swagger 贯穿整个 API 生命周期,如 API 的设计、编写文档、测试和部署。

    26 引用 • 35 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...