Remember the encapsulation of Swagger-UI and the parsing and processing of document JSON data

Remember the encapsulation of Swagger-UI and the parsing and processing of document JSON data

origin

Spring projects often have to form a document for other people to use, especially the developed interface. There are many kinds of class documents in Java, such as javadoc, genDoc, SwaggerUI, etc. According to the requirements, we first need to group different Controller packages. Each controller package represents a type of interface. Secondly, the original SwagerUI display interface may not be what we want, so we need to transform it.

Note that the version of SwaggerUI used in my code is 2.7.0, and the difference between each version of SwaggerUI is relatively large.

Group the interfaces according to the code Controller package

We need to configure SwaggerUI globally so that it supports dynamically generating DocketBean according to the package.
First of all, we need to define a class used to illustrate the description of the document for automated configuration.

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
    }

This class corresponds to the configuration file:

#启用/禁用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

Then we use the global configuration file to implement dynamic bean injection, as follows:

@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();
    }
}

After doing this, you can see when you visit http://your ip:port/api/swagger-ui.html that swaggerUI has been grouped according to your meaning, and the grouping work is over.

Custom processing of document JSON

The organization of SwaggerUI is:

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

So we need to get the groups in the first step:

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

After getting all the groups, we can get the swagger inside the groups one by one:

Swagger swagger = getSwagger(groupName, httpServletRequest);

In order to obtain Swagger we need to inject two objects, the method is as follows:

@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;
    }

Which uses a HostNameProvider class:

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;
    }
}

In this way, the Swagger object has been obtained. The rest can be processed on the Swagger object yourself.

Guess you like

Origin blog.csdn.net/polixiaohai/article/details/107082976