记一次Swagger-UI的封装以及文档JSON数据的解析处理

1 篇文章 0 订阅
1 篇文章 0 订阅

记一次Swagger-UI的封装以及文档JSON数据的解析处理

起源

Spring工程往往要最后形成文档,供其他人使用,尤其是开发的接口。Java中的类文档有很多种,比如:javadoc,genDoc,SwaggerUI等。按照要求,我们首先,需要对不同的Controller包进行分组,每个controller包都代表一类接口,其次,原有SwagerUI显示界面也许不是我们想要的,所以我们需要改造。

注意,我代码中用到的SwaggerUI版本是2.7.0,每个版本的SwaggerUI差异比较大。

按照代码Controller包对接口进行分组

我们需要对SwaggerUI进行全局配置,让他支持按照包动态生成DocketBean。
首先我们需要定义一个用于说明文档描述的类,用于自动化配置。

private class SwaggerConfigProperties {
        private String version;
        private Boolean enable;
        private String groupName;
        private String title;
        private String description;
        private String basePackage;

        public SwaggerConfigProperties(Environment env, String groupName) {
            this.groupName = env.getProperty("swagger2." + groupName + ".groupName", "groupName");
            this.title = env.getProperty("swagger2." + groupName + ".title", "title");
            this.description = env.getProperty("swagger2." + groupName + ".description", "description");
            this.version = env.getProperty("swagger2." + groupName + ".version", "version");
            this.basePackage = env.getProperty("swagger2." + groupName + ".basePackage", "basePackage");
            this.enable = Boolean.parseBoolean(env.getProperty("swagger2.enable", "false"));
        }
       
        ///getter
        ///setter
    }

该类对应于配置文件:

#启用/禁用swagger
swagger2.enable=true
# rest API 标题
#服务器启动后可以通过访问http://your ip:8090/api/swagger-ui.html查看发布的REST接口
swagger2.title=BFSAPP相关Restfull API接口

# group1
swagger2.group1.groupName=文档分组1
swagger2.group1.title=文档分组1文档
swagger2.group1.description=文档分组1
swagger2.group1.version=1.0
swagger2.group1.basePackage=com.xxx.group1 # 这里是第一个controller组对应的包名
# group2
swagger2.group2.groupName=文档分组2
swagger2.group2.title=文档分组1文档
swagger2.group2.description=文档分组2
swagger2.group2.version=1.0
swagger2.group2.basePackage=com.xxx.group2 # 这里是第二个controller组对应的包名
# groups
swagger2.groups=group1,group2

然后我们使用全局配置文件,来实现动态Bean的注入,如下:

@Configuration
@PropertySources({@PropertySource(value = "classpath:swagger2.properties", ignoreResourceNotFound = true, encoding = "UTF-8")})
@EnableSwagger2
@RestController
public class Swagger2UIConfig implements ApplicationContextAware {
    private ConfigurableApplicationContext configurableApplicationContext;

    @Autowired
    private Environment env;

    @Value("#{'${swagger2.groups}'.split(',')}")
    private List<String> groups;

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
    }
	
	/**
     * 按照group的个数,自动生成一系列的Docket bean对象。
     *
     * @return
     */
    @Bean
    public String createDocket() {
        groups.forEach(group -> {
            SwaggerConfigProperties properties = new SwaggerConfigProperties(env, group);

            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Docket.class);
            beanDefinitionBuilder.addConstructorArgValue(DocumentationType.SWAGGER_2);

            BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
            BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry) configurableApplicationContext.getBeanFactory();
            beanFactory.registerBeanDefinition(group, beanDefinition);

            Docket docket = configurableApplicationContext.getBean(group, Docket.class);
            docket.groupName(properties.getGroupName())
                    .enable(properties.getEnable())
                    .apiInfo(apiInfo(properties.getTitle(), properties.getTitle(), properties.getVersion()))
                    .select()
                    .apis(basePackage(properties.getBasePackage()))
                    .paths(PathSelectors.any())
                    .build();
        });
        return "createDocket";
    }

    
    public static Predicate<RequestHandler> basePackage(final String basePackage) {
        return input -> Optional.fromNullable(input.declaringClass()).transform(
                (Function<Class<?>, Boolean>) input1 -> {
                    for (String strPackage : basePackage.split(",")) {
                        boolean isMatch = input1.getPackage().getName().startsWith(strPackage);
                        if (isMatch) {
                            return true;
                        }
                    }
                    return false;
                }
        ).or(true);
    }
    
    public ApiInfo apiInfo(String title, String description, String version) {
        return new ApiInfoBuilder()
                .title(title)
                .version(version)
                .description(description)
                .termsOfServiceUrl("https://springfox.github.io/springfox/docs/current/")
                .version(version)
                .build();
    }
}

做到这一步,你访问http://your ip:port/api/swagger-ui.html的时候就能看到,swaggerUI已经按照你的意思进行了分组,分组工作结束。

文档JSON的自定义处理

SwaggerUI的组织方式为:

包括
包括
包括
包括
包括
包括
包括
包括
group
swagger
info
host
basePath
tags
schemes
consumes
...

因此我们第一步需要获取到groups:

RestTemplate restTemplate = new RestTemplate();
List groupEntities = restTemplate.getForObject("http://ip:port/contextPath/swagger-resources", ArrayList.class);

获取所有的分组之后,我们可以逐个获取分组内部的swagger:

Swagger swagger = getSwagger(groupName, httpServletRequest);

为了获取Swagger我们需要注入两个对象,方法如下:

@Autowired
    private DocumentationCache documentationCache;

    @Autowired
    private ServiceModelToSwagger2Mapper mapper;

    private String hostNameOverride = "DEFAULT";

    private String hostName(UriComponents uriComponents) {
        if ("DEFAULT".equals(this.hostNameOverride)) {
            String host = uriComponents.getHost();
            int port = uriComponents.getPort();
            return port > -1 ? String.format("%s:%d", host, port) : host;
        } else {
            return this.hostNameOverride;
        }
    }

    private Swagger getSwagger(String groupName, HttpServletRequest request) {
        Documentation documentation = this.documentationCache.documentationByGroup(groupName);
        if (documentation != null) {
            Swagger swagger = this.mapper.mapDocumentation(documentation);
            UriComponents uriComponents = HostNameProvider.componentsFrom(request, swagger.getBasePath());
            swagger.basePath(Strings.isNullOrEmpty(uriComponents.getPath()) ? "/" : uriComponents.getPath());
            if (Strings.isNullOrEmpty(swagger.getHost())) {
                swagger.host(this.hostName(uriComponents));
            }
            return swagger;
        }
        return null;
    }

其中用到一个HostNameProvider类:

public class HostNameProvider {
    public HostNameProvider() {
        throw new UnsupportedOperationException();
    }

    public static UriComponents componentsFrom(HttpServletRequest request, String basePath) {
        ServletUriComponentsBuilder builder = fromServletMapping(request, basePath);
        UriComponents components = UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request)).build();
        String host = components.getHost();
        if (!StringUtils.hasText(host)) {
            return builder.build();
        } else {
            builder.host(host);
            builder.port(components.getPort());
            return builder.build();
        }
    }

    private static ServletUriComponentsBuilder fromServletMapping(HttpServletRequest request, String basePath) {
        ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromContextPath(request);
        builder.replacePath(prependForwardedPrefix(request, basePath));
        if (StringUtils.hasText((new UrlPathHelper()).getPathWithinServletMapping(request))) {
            builder.path(request.getServletPath());
        }

        return builder;
    }

    private static String prependForwardedPrefix(HttpServletRequest request, String path) {
        String prefix = request.getHeader("X-Forwarded-Prefix");
        return prefix != null ? prefix + path : path;
    }
}

这样,Swagger对象已经获取到了。剩下的就可以自己对Swagger对象进行处理。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Swagger-UI在线接口文档的优点包括以下几个方面: 1. 支持接口文档导出:Swagger-UI可以将接口文档以PDF、Word和Markdown等格式导出,方便开发者进行离线查阅和分享。[2] 2. 多种方式使用:Swagger-UI可以与其他工具同时使用,比如springfox-swagger-ui,可以根据项目需求选择最适合的方式。[2] 3. 友好的界面:相比于springfox-swagger-uiSwagger-UI的界面更加友好,排版结构更加清晰,使得接口文档更易于理解和使用。[2] 4. 搜索功能:Swagger-UI支持接口内容的搜索,可以快速定位到需要查找的接口,提高了开发效率。[2] 5. 接口版本管理:Swagger-UI可以对接口进行版本管理,方便开发者对接口进行更新和维护。[2] 6. 国际化支持:Swagger-UI支持多语言界面,可以根据用户的语言偏好进行界面显示。[2] 7. 自定义文档Swagger-UI支持开发者对接口文档进行自定义,可以根据项目需求添加额外的信息和说明。[2] 8. 生产环境屏蔽:Swagger-UI支持在生产环境中屏蔽Swagger的所有资源接口,保护接口文档的安全性。[2] 9. 接口权限控制:Swagger-UI可以设置在线接口文档的权限控制,限制不同用户对接口文档的访问权限。[2] 综上所述,Swagger-UI在线接口文档具有导出、多种使用方式、友好界面、搜索功能、版本管理、国际化支持、自定义文档、生产环境屏蔽和权限控制等优点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值