springboot集成swagger2出现404解决方案汇总

简介: springboot集成swagger2出现404解决方案汇总

springboot整合swagger2:

1、依赖包:

<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>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>1.8.3</version>
        </dependency>

image.gif

2、SwaggerConfig配置:

import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.util.UriComponentsBuilder;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.paths.AbstractPathProvider;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
import static com.google.common.base.Strings.isNullOrEmpty;
import static springfox.documentation.spring.web.paths.Paths.removeAdjacentForwardSlashes;
@Configuration
@EnableSwagger2
@Slf4j
@EnableConfigurationProperties(SwaggerYaml.class)
public class SwaggerConfig implements WebMvcConfigurer {
    private SwaggerYaml swaggerYaml;
    public SwaggerConfig(SwaggerYaml swaggerYaml) {
        this.swaggerYaml = swaggerYaml;
    }
    @Bean
    @ConditionalOnProperty(prefix = "swagger", name = "enable", havingValue = "true")
    public Docket api() {
        log.info("swagger配置信息初始化");
        return new Docket(DocumentationType.SWAGGER_2)
                .forCodeGeneration(true)
                .pathProvider(new CustRelativePathProvider())
                .select()
//                .apis(RequestHandlerSelectors.any())  //显示所有类
                //只显示添加@Api注解的类
                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                .paths(PathSelectors.any())
                .build()
                .apiInfo(apiInfo()).globalOperationParameters(parameters());
    }
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title(swaggerYaml.getTitle())
                .description(swaggerYaml.getDescription())
                .version(swaggerYaml.getVersion())
                .termsOfServiceUrl(swaggerYaml.getTermsOfServiceUrl())
                .build();
    }
    /**
     * 全局参数。 接口请求header中的token。 required false非必须
     * @return
     */
    private List<Parameter> parameters(){
        List<Parameter> params = new ArrayList<>();
        params.add(
                new ParameterBuilder()
                        .name("token")
                        .description("请求令牌")
                        .modelRef(new ModelRef("String"))
                        .parameterType("header")
                        .required(false)
                        .build());
        return params;
    }
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
        registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
        super.addResourceHandlers(registry);
    }
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
    /**
     * 重新pathprovider,给所有url添加后缀
     */
    public class CustRelativePathProvider extends AbstractPathProvider {
        public static final String ROOT = "/";
        @Override
        public String getOperationPath(String operationPath) {
            UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromPath("/");
            String uri = removeAdjacentForwardSlashes(uriComponentsBuilder.path(operationPath).build().toString());
            return uri + ".jhtml";
        }
        @Override
        protected String applicationPath() {
            return isNullOrEmpty(swaggerYaml.getContextPath()) ? ROOT : swaggerYaml.getContextPath();
        }
        @Override
        protected String getDocumentationPath() {
            return ROOT;
        }
    }
}

image.gif

3、SpringApplication.run(xxx.class, args)。

由于我使用了swagger第三方ui:swagger-bootstrap-ui,所以我直接访问url:http://localhost:8080/doc.html。结果:

image.png

开始百度搜索解决大法:

基本网上说的解决方法不都是静态资源映射的问题,解决方式为:

@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
        registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
        super.addResourceHandlers(registry);
    }
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

image.gif

但是我无效,而且我在springmvc上使用过swagger,自信配置应该是不缺。哈哈哈。

还有一个解决方式为:在application.yml上添加static资源映射,spring.resource.static-location:classpath:/resource/...等等类似,也无效。

最终:无意间在idea全局搜索WebMvcConfigurer发现自己曾经写的一个跨域的拦截器配置CrossOriginConfig同样实现了WebMvcConfigurer。于是抱着死马当活马的态度,将这个注释后,重启,发现熟悉的页面出来了:

image.png

于是百度了一圈,网上给出的解释大概为:springboot默认静态资源路径为

    • classpath:/META-INF/resources
    • classpath:/resources
    • classpath:/static
    • classpath:/public

    这也就是为什么我们前面要添加资源文件映射到swagger-ui.html的原因吧, 个人理解。

    然后,我们自己在容器中装配了自己的bean,springboot就不会帮我们自动装配(大概意思就是,CrossOriginConfig生成的baen把springboot的bean给覆盖了,菜鸟的白话理解,如有误,请指出

    这里更改后的两个配置,这里我是将CrossOriginConfig作为基类,供其他地方继承使用(当然,你可以直接在swaggerConfig中重写addCorsMappings也是一样的道理。):

    import org.springframework.web.servlet.config.annotation.CorsRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    /**
     * 处理跨域请求
     *
     * 这里不自动装配,作为基类提供子类继承。避免重复装配,导致bean被覆盖。(如被覆盖后,swagger-ui出现404)
     *
     * @author asus
     * @date 2020/4/8
     */
    //@Configuration
    public class CrossOriginConfig implements WebMvcConfigurer {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**").allowedOrigins("*")
                    .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
                    .maxAge(3600)
                    .allowCredentials(true);
        }
    }

    image.gif

    import com.kuria.config.cross.CrossOriginConfig;
    import io.swagger.annotations.Api;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.*;
    import org.springframework.web.util.UriComponentsBuilder;
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.ParameterBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.schema.ModelRef;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.service.Parameter;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.paths.AbstractPathProvider;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    import java.util.ArrayList;
    import java.util.List;
    import static com.google.common.base.Strings.isNullOrEmpty;
    import static springfox.documentation.spring.web.paths.Paths.removeAdjacentForwardSlashes;
    /**
     * swagger2 配置
     * @ConditionalOnProperty 用于控制当前config是否生效
     * swagger-open: true生效,false则关闭
     *
     * 继承CrossOriginConfig, 原因CrossOriginConfig配置跨域拦截处理,为了避免bean被覆盖,导致swagger-ui 404.这里不重复装配
     * 由CrossOriginConfig 作为基类,提供继承。当然,如果SwaggerConfig重写addCorsMappings也是可以的。
     *
     * @author pengyh
     * @date 2020/4/10
     */
    @Configuration
    @EnableSwagger2
    @Slf4j
    @EnableConfigurationProperties(SwaggerYaml.class)
    public class SwaggerConfig extends CrossOriginConfig {
        private SwaggerYaml swaggerYaml;
        public SwaggerConfig(SwaggerYaml swaggerYaml) {
            this.swaggerYaml = swaggerYaml;
        }
        @Bean
        @ConditionalOnProperty(prefix = "swagger", name = "enable", havingValue = "true")
        public Docket api() {
            log.info("swagger配置信息初始化");
            return new Docket(DocumentationType.SWAGGER_2)
                    .forCodeGeneration(true)
                    .pathProvider(new CustRelativePathProvider())
                    .select()
    //                .apis(RequestHandlerSelectors.any())  //显示所有类
    //                .apis(RequestHandlerSelectors.basePackage("com.kuria.site.controller"))
                    //只显示添加@Api注解的类
                    .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                    .paths(PathSelectors.any())
                    .build()
                    .apiInfo(apiInfo()).globalOperationParameters(parameters());
        }
        private ApiInfo apiInfo() {
            return new ApiInfoBuilder()
                    .title(swaggerYaml.getTitle())
                    .description(swaggerYaml.getDescription())
                    .version(swaggerYaml.getVersion())
                    .termsOfServiceUrl(swaggerYaml.getTermsOfServiceUrl())
                    .build();
        }
        /**
         * 全局参数。 接口请求header中的token。 required false非必须
         * @return
         */
        private List<Parameter> parameters(){
            List<Parameter> params = new ArrayList<>();
            params.add(
                    new ParameterBuilder()
                            .name("token")
                            .description("请求令牌")
                            .modelRef(new ModelRef("String"))
                            .parameterType("header")
                            .required(false)
                            .build());
            return params;
        }
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
            registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
            registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
            registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
            super.addResourceHandlers(registry);
        }
        @Override
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
            configurer.enable();
        }
        /**
         * 重新pathprovider,给所有url添加后缀
         */
        public class CustRelativePathProvider extends AbstractPathProvider {
            public static final String ROOT = "/";
            @Override
            public String getOperationPath(String operationPath) {
                UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromPath("/");
                String uri = removeAdjacentForwardSlashes(uriComponentsBuilder.path(operationPath).build().toString());
                return uri + ".jhtml";
            }
            @Override
            protected String applicationPath() {
                return isNullOrEmpty(swaggerYaml.getContextPath()) ? ROOT : swaggerYaml.getContextPath();
            }
            @Override
            protected String getDocumentationPath() {
                return ROOT;
            }
        }
    }

    image.gif

    问题解决。

    备注:测试发现,如果SwaggerConfig继承WebMvcConfigurationSupport类。而CrossOriginConfig实现WebMvcConfigurer接口,也是可以正常使用的, 不知道为何,待研究,也可能是我本地缓存,没有认真试验过。

    踩坑之路,备注,方便日后查阅。

    目录
    打赏
    0
    0
    0
    0
    175
    分享
    相关文章
    |
    6月前
    |
    微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 身份和权限认证
    本文介绍了 Apache Shiro 的身份认证与权限认证机制。在身份认证部分,分析了 Shiro 的认证流程,包括应用程序调用 `Subject.login(token)` 方法、SecurityManager 接管认证以及通过 Realm 进行具体的安全验证。权限认证部分阐述了权限(permission)、角色(role)和用户(user)三者的关系,其中用户可拥有多个角色,角色则对应不同的权限组合,例如普通用户仅能查看或添加信息,而管理员可执行所有操作。
    284 0
    微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 三大核心组件
    本课程介绍如何在Spring Boot中集成Shiro框架,主要讲解Shiro的认证与授权功能。Shiro是一个简单易用的Java安全框架,用于认证、授权、加密和会话管理等。其核心组件包括Subject(认证主体)、SecurityManager(安全管理员)和Realm(域)。Subject负责身份认证,包含Principals(身份)和Credentials(凭证);SecurityManager是架构核心,协调内部组件运作;Realm则是连接Shiro与应用数据的桥梁,用于访问用户账户及权限信息。通过学习,您将掌握Shiro的基本原理及其在项目中的应用。
    225 0
    第07课:Spring Boot集成Thymeleaf模板引擎
    第07课:Spring Boot集成Thymeleaf模板引擎
    336 0
    第07课:Spring Boot集成Thymeleaf模板引擎
    |
    3月前
    |
    SpringBoot2.3.1集成Knife4j接口文档
    SpringBoot2.3.1集成Knife4j接口文档
    412 44
    springboot项目集成dolphinscheduler调度器 实现datax数据同步任务
    springboot项目集成dolphinscheduler调度器 实现datax数据同步任务
    289 2
    springboot项目集成dolphinscheduler调度器 可拖拽spark任务管理
    springboot项目集成dolphinscheduler调度器 可拖拽spark任务管理
    115 2
    Springboot集成AI Springboot3 集成阿里云百炼大模型CosyVoice2 实现Ai克隆语音(未持久化存储)
    本项目基于Spring Boot 3.5.3与Java 17,集成阿里云百炼大模型CosyVoice2实现音色克隆与语音合成。内容涵盖项目搭建、音色创建、音频合成、音色管理等功能,适用于希望快速掌握Spring Boot集成语音AI技术的开发者。需提前注册阿里云并获取API Key。
    Shiro简介及SpringBoot集成Shiro(狂神说视频简易版)
    Shiro简介及SpringBoot集成Shiro(狂神说视频简易版)
    235 6
    SpringBoot集成Ehcache缓存使用指南
    以上是SpringBoot集成Ehcache缓存的基本操作指南,帮助你在实际项目中轻松实现缓存功能。当然,Ehcache还有诸多高级特性,通过学习和实践,你可以更好地发挥它的威力。
    413 20
    【Azure Application Insights】为Spring Boot应用集成Application Insight SDK
    本文以Java Spring Boot项目为例,详细说明如何集成Azure Application Insights SDK以收集和展示日志。内容包括三步配置:1) 在`pom.xml`中添加依赖项`applicationinsights-runtime-attach`和`applicationinsights-core`;2) 在main函数中调用`ApplicationInsights.attach()`;3) 配置`applicationinsights.json`文件。同时提供问题排查建议及自定义日志方法示例,帮助用户顺利集成并使用Application Insights服务。
    114 8

    热门文章

    最新文章

    AI助理

    你好,我是AI助理

    可以解答问题、推荐解决方案等

    登录插画

    登录以查看您的控制台资源

    管理云资源
    状态一览
    快捷访问