SpringMvc Swagger2集成失败:${springfox.documentation.swagger.v2.path:/v2/api-docs}

springMvc,springFox 2.6.1 ,swagger-ui:2.6.1,用idea启动后(自动放入tomcat容器里),现象:

F12查看:

http://localhost:8080/agent_applications_war/swagger-resources

此接口返回值不对。首先说明一下,该接口应该返回的是swagger2提供的api地址,但实际却返回了非法字符串${springfox.documentation.swagger.v2.path:/v2/api-docs}。我第一时间在配置文件里加入该配置,但是还是不行,所以,到控制台找到出错的接口:

ApiResourceController (负责提供资源):

这个类自动注入时,容器给他提供了一个SwaggerResourcesProvider:

然后,我的思路是,真实的swaggerApi的接口到底启动没有呢?我直接访问/v2/api-doc测试:

Swagger2Controller是swagger提供的api接口,它通过扫描注解,缓存我们的接口信息,然后给swagger-ui调用:

 

 

开启断点:

所以,初步找到问题了:

SwaggerResourcesProvider初始化错误,url不对,
Swagger2Controller初始化不对,导致它根本没起来。

解决方案:

1,自己写Swagger2Controller接口:MySwagger2Controller,把原来的拷贝过来即可;

2,自己写一个资源提供接口,返回我们MySwagger2Controller的访问路径;

3,自己写一个接口,转发/swagger-resources接口,注意,是只转发它,并不是转发它下面所以的接口。转发到上一步那个方法里。通过filter实现。

代码结构:

代码:

package com.ygkj.agent.server.action.mySwagger;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.ArrayList;
import java.util.List;

import springfox.documentation.annotations.ApiIgnore;
import springfox.documentation.swagger.web.SwaggerResource;

/**
 * MyApiResourceController
 * 提供给swagger-ui调用,告诉它获取api列表数据的url
 * 责任人:  Chuck
 * 修改人: Chuck
 * 创建/修改时间: 2020/5/14  15:49
 * Copyright : 2014-2018 深圳令令科技有限公司-版权所有
 **/

@Controller
@ApiIgnore
@RequestMapping({"/swagger-resources2"})//原来的swagger-resources会被重新分配至这里
public class MyApiResourceController {


    @RequestMapping( method = {RequestMethod.GET})
    @ResponseBody
    ResponseEntity<List<SwaggerResource>> swaggerResources() {

        List<SwaggerResource> result=new ArrayList<>();
        SwaggerResource r1=new SwaggerResource();
        r1.setName("default");

        //重置url,返回我们自己写的swaggerApi列表接口 chuck:2020/05/14
        r1.setLocation("/swagger/v2/api-docs");//核心是这里,此次出现问题,是由于springmvc里注解出现异常,
                                              // 导致api路径出问题,最终导致刷不出api列表
        r1.setSwaggerVersion("2.0");
        result.add(r1);

        return new ResponseEntity(result, HttpStatus.OK);
    }
}
package com.ygkj.agent.server.action.mySwagger;

import com.google.common.base.Optional;
import com.google.common.base.Strings;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponents;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import io.swagger.models.Swagger;
import springfox.documentation.annotations.ApiIgnore;
import springfox.documentation.service.Documentation;
import springfox.documentation.spring.web.DocumentationCache;
import springfox.documentation.spring.web.json.Json;
import springfox.documentation.spring.web.json.JsonSerializer;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper;

/**
 * MySwagger2Controller
 * 这个类,拷贝自swagger2. 功能一致,只是改了访问路径
 * 责任人:  Chuck
 * 修改人: Chuck
 * 创建/修改时间: 2020/5/14  15:32
 * Copyright : 2014-2018 深圳令令科技有限公司-版权所有
 **/

@Controller
@ApiIgnore
@RequestMapping("/swagger")
public class MySwagger2Controller {
    public static final String DEFAULT_URL = "/v2/api-docs";
    private static final String HAL_MEDIA_TYPE = "application/hal+json";
    private String hostNameOverride="DEFAULT";
    @Autowired
    private DocumentationCache documentationCache;
    @Autowired
    private ServiceModelToSwagger2Mapper mapper;
    @Autowired
    private JsonSerializer jsonSerializer;


    @ApiIgnore
    @RequestMapping(
            value = {"/v2/api-docs"},
            method = {RequestMethod.GET},
            produces = {"application/json", "application/hal+json"}
    )
    @ResponseBody
    public ResponseEntity<Json> getDocumentation(@RequestParam(value = "group",required = false) String swaggerGroup, HttpServletRequest servletRequest) {
        String groupName = (String) Optional.fromNullable(swaggerGroup).or("default");
        Documentation documentation = this.documentationCache.documentationByGroup(groupName);
        if (documentation == null) {
            return new ResponseEntity(HttpStatus.NOT_FOUND);
        } else {
            Swagger swagger = this.mapper.mapDocumentation(documentation);
            if (Strings.isNullOrEmpty(swagger.getHost())) {
                UriComponents uriComponents = componentsFrom(servletRequest);
                swagger.basePath(Strings.isNullOrEmpty(uriComponents.getPath()) ? "/" : uriComponents.getPath());
                swagger.host(this.hostName(uriComponents));
            }

            return new ResponseEntity(this.jsonSerializer.toJson(swagger), HttpStatus.OK);
        }
    }

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

    static UriComponents componentsFrom(HttpServletRequest request) {
        ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromServletMapping(request);
        ForwardedHeader forwarded = ForwardedHeader.of(request.getHeader(ForwardedHeader.NAME));
        String proto = StringUtils.hasText(forwarded.getProto()) ? forwarded.getProto() : request.getHeader("X-Forwarded-Proto");
        String forwardedSsl = request.getHeader("X-Forwarded-Ssl");
        if (StringUtils.hasText(proto)) {
            builder.scheme(proto);
        } else if (StringUtils.hasText(forwardedSsl) && forwardedSsl.equalsIgnoreCase("on")) {
            builder.scheme("https");
        }

        String host = forwarded.getHost();
        host = StringUtils.hasText(host) ? host : request.getHeader("X-Forwarded-Host");
        if (!StringUtils.hasText(host)) {
            return builder.build();
        } else {
            String[] hosts = StringUtils.commaDelimitedListToStringArray(host);
            String hostToUse = hosts[0];
            if (hostToUse.contains(":")) {
                String[] hostAndPort = StringUtils.split(hostToUse, ":");
                builder.host(hostAndPort[0]);
                builder.port(Integer.parseInt(hostAndPort[1]));
            } else {
                builder.host(hostToUse);
                builder.port(-1);
            }

            String port = request.getHeader("X-Forwarded-Port");
            if (StringUtils.hasText(port)) {
                builder.port(Integer.parseInt(port));
            }

            return builder.build();
        }
    }

     static class ForwardedHeader {
        public static String NAME = "Forwarded";
        private static final  ForwardedHeader NO_HEADER = new  ForwardedHeader(Collections.emptyMap());
        private final Map<String, String> elements;

        private ForwardedHeader(Map<String, String> elements) {
            this.elements = elements;
        }

        public static  ForwardedHeader of(String source) {
            if (!StringUtils.hasText(source)) {
                return NO_HEADER;
            } else {
                Map<String, String> elements = new HashMap();
                String[] var2 = source.split(";");
                int var3 = var2.length;

                for(int var4 = 0; var4 < var3; ++var4) {
                    String part = var2[var4];
                    String[] keyValue = part.split("=");
                    if (keyValue.length == 2) {
                        elements.put(keyValue[0].trim(), keyValue[1].trim());
                    }
                }

                Assert.notNull(elements, "Forwarded elements must not be null!");
                Assert.isTrue(!elements.isEmpty(), "At least one forwarded element needs to be present!");
                return new  ForwardedHeader(elements);
            }
        }

        public String getProto() {
            return (String)this.elements.get("proto");
        }

        public String getHost() {
            return (String)this.elements.get("host");
        }
    }
}

spring.mvc.xml(拦截器配置,对swagger的请求直接放行):

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <mvc:exclude-mapping path="/v2/**"/>
        <mvc:exclude-mapping path="/swagger-resources/**"/>
        <mvc:exclude-mapping path="/swagger-resources2/**"/>
        <mvc:exclude-mapping path="/swagger/**"/>
        <mvc:exclude-mapping path="/webjars/**"/>
        <mvc:exclude-mapping path="/swagger-ui.html/**"/>
        <mvc:exclude-mapping path="/agent/account/login"/>
        <mvc:exclude-mapping path="/agent/account/verify/code"/>
        <bean class="com.ygkj.agent.server.web.AccessAllowInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

 

 过滤器(通过过滤器,转发出问题的那个接口,把业务转到我们自己写的接口里来):

package com.ygkj.agent.server.web;

/**
 * SwaggerFilter
 * 责任人:  Chuck
 * 修改人: Chuck
 * 创建/修改时间: 2020/5/14  16:06
 * Copyright : 2014-2018 深圳令令科技有限公司-版权所有
 **/

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lombok.extern.slf4j.Slf4j;

@Slf4j
/**
 * SwaggerFilter
 * 整个项目swagger集成失败的原因是:
 * 原框架里的Swagger2Controller 和 ApiResourceController里的SwaggerResourcesProvider
 * 的  @Value("${springfox.documentation.swagger.v2.path:/v2/api-docs}")
 *     private String swagger2Url;
 *    这个注解加载失败。
 * 所以,解决方案是:
 * 1,转发获取swagger2Url的请求,使其调用我们自己的接口
 * 2,自己拷贝swagger的接口列表业务,业务和原来一致,只是访问路径不同
 * 责任人:  Chuck
 * 修改人: Chuck
 * 创建/修改时间: 2020/5/14  16:26
 * @version 1.0.0
 * Copyright : 2014-2017 深圳令令科技有限公司-版权所有
 **/
public class   SwaggerFilter    implements Filter
{

    public void destroy()
    {
    }

    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain filterChain) throws IOException, ServletException
    {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse)response;

        String url=req.getRequestURI();

        log.info("url:{}",url);

        String replace="/swagger-resources2";
        String myApiResourceController=url.replace("/swagger-resources",replace);
        if( url.endsWith("/swagger-resources"))//如果是这个,则把它转发到我们自己写的MyApiResourceController
        {
            res.sendRedirect(myApiResourceController);
        }
        else
            filterChain.doFilter(req, res);
    }

    public void init(FilterConfig arg0) throws ServletException
    {
    }

}

web.xml(通过过滤器,转发出问题的那个接口,把业务转到我们自己写的接口里来):

<filter>
    <filter-name>SwaggerFilter</filter-name>
    <filter-class>com.ygkj.agent.server.web.SwaggerFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>SwaggerFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

 

最终效果,输入:http://localhost:8080/agent_applications_war/swagger-ui.html:

 

感谢老秦提供解决方案的思路,博客地址:

https://blog.csdn.net/qinxian20120

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值