缘起:今天做springboot集成swagger文档的时候。
出现了404问题。

什么集成swagger 这不有手就行?
先加依赖:

        <!--swagger 依赖-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

添加 swagger配置类 SwaggerConfig

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2).
// 指定构建 api 文档的详细信息的方法:
        apiInfo(apiInfo()).apiInfo(apiInfo())
                .select()
// 指定要生成 api 接口的包路径,这里把 controller 作为包路径,生成 controller 中的所有接口
                .apis(RequestHandlerSelectors.basePackage("com.zry.qiniu.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    /**
     * 构建 api 文档的详细信息
     *
     * @return
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
// 设置页面标题
                .title("接口文档")
                .contact(new Contact("基于树莓派的动态图片捕捉系统", "", "1447051936@qq.com"))
                // 设置接口描述
                .description("Api文档: 注意!! Date格式: yyyy-MM-dd HH:mm:ss")
                // 设置版本
                .version("1.0")
                // 构建
                .build();
    }
}

浏览器访问:
在这里插入图片描述
啥404? what?
开始排查:
访问 http://localhost:8081/v2/api-docs 看一下swagger接口是否有数据
在这里插入图片描述
有数据说明配置没有问题。看来是静态资源被拦截了。
咱们就开放它的静态资源。
下面代码:

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    /**
     * 功能描述: 开放静态资源
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
//        "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"
        //重写这个方法,映射静态资源文件
            registry.addResourceHandler("/**")
                    .addResourceLocations("classpath:/resources/")
                    .addResourceLocations("classpath:/static/")
                    .addResourceLocations("classpath:/pages/")
            ;
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
        super.addResourceHandlers(registry);
    }


}

再次访问 还是404? 没有啥变化。。。。
??????????

再次研究排查:
对比之前的项目,我发现我这次的项目中多了个解决跨域问题的代码:

@Configuration
public class WebApiConfig extends WebMvcConfigurationSupport {

@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**")
            .allowedOrigins("*")
            .allowedMethods("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH")
            .allowCredentials(true).maxAge(3600);
}

把这个configuration注释掉就可以了。

原因:

这个自定义的类继承自WebMvcConfigurationSupport,如果你在IDE中搜索这个类的实现类,可以发现spring boot有一个子类EnableWebMvcConfiguration,并且是自动config的.我们知道,如果一个类用户自己在容器中生成了bean,spring boot就不会帮你自动config。所以,问题的原因是我们把spring boot自定义的那个bean覆盖了。

那么我想既然使用跨域又使用swagger该怎么办呢?只需加上下面的代码。

/**
 * @author zry
 * @create 2022-04-09 17:31
 */

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    /**
     * 功能描述: 开放静态资源
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
//        "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"
        //重写这个方法,映射静态资源文件
            registry.addResourceHandler("/**")
                    .addResourceLocations("classpath:/resources/")
                    .addResourceLocations("classpath:/static/")
                    .addResourceLocations("classpath:/pages/")
            ;
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
        super.addResourceHandlers(registry);
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH")
                .allowCredentials(true).maxAge(3600);
    }

}

这样就可以了。

扩展跨域问题解决:

来自:https://cloud.tencent.com/developer/article/1924258

方法1:全局配置

定义配置类,添加@Configuration注解,实现WebMvcConfigurer接口,再重写addCorsMappings方法:
就是上面的代码。

方法2:局部跨域

Controller层在需要跨域的类或者方法上加上@CrossOrigin该注解即可。

@CrossOrigin(origins = "*",maxAge = 3600)
public class UserController {
 final UserService userService;
 
 @GetMapping("/getOne/{id}")
 public User getOne(@PathVariable("id") Integer id) {
  return userService.getById(id);
 }

我们也可以设置更小的粒度,在方法上设置跨域:

@Controller
@RequestMapping("/shop")
public class ShopController {
	    @GetMapping("/")
	    @ResponseBody
	    //更小的解决跨域 设置只能某些地址访问
	    @CrossOrigin(originPatterns = "http://localhost:8080")
	    public Map<String, Object> findAll() {
	        //返回数据
	        return DataSchool.getStudents();
	    }
    }

方法3:定义跨域过滤器

1)编写过滤器

// 跨域过滤器
@Component
public class CORSFilter implements Filter {
 
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
  //*号表示对所有请求都允许跨域访问
        HttpServletResponse res = (HttpServletResponse) response;
        res.addHeader("Access-Control-Allow-Credentials", "true");
        res.addHeader("Access-Control-Allow-Origin", "*");
        res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
        res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");
        if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {
            response.getWriter().println("Success");
            return;
        }
        chain.doFilter(request, response);
    }
 
    @Override
    public void destroy() {
 
    }
 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
 
    }
}

2)注册过滤器

@Configuration
public class CorsConfig {
 
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }
 
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐