springMVC项目集成swagger2或knife4j(接口带.do或.htm后缀的解决方案)

工作上因为前后端联调的问题,项目经理安排我给项目集成一个swagger工具;这个东西我以前在业余时候也是有玩过的,但是不同的是,我当初是在SpringBoot项目中进行的一个集成,我现在所做的项目是一个SpringMVC的项目,各种配置都是在xml文件中做的,虽然我们同样可以使用@Configuration去做一个配置类,以及各种配置也都可以说是类似;(网上很多配置的文章,我这就不再说明了)

但是有一个问题就是:我的项目对请求接口限制了一下后缀,接口统一得使用.htm的后缀,但是swagger的请求是不带后缀的;我相信很多SpringMVC的项目都是有做这类限制的例如:.do.action等等,这个问题对于集成swagger2还是knife4j都是一样的,网上对于它们集成的文章多的一批,但大多是说集成SpringBoot项目的,罕见的几个SpringMVC项目集成的也没有提到过这个问题;

面对这个问题,我想到了两个解决方案,这里提供给大家:

一、增加过滤器处理URL

这是最直接的一个方案,但是有个风险如果没控制好,可能会对系统原有功能造成影响;

 这是我过滤器的代码:

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Map;

/**
 * URL增加后缀过滤器
 *
 * @author xiejinwei
 * @date 2021/8/5
 */
@Service
public class URLFilter implements Filter {

    private static String PATH = "xxx";

    private static String PORT = "8080";

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        // 获取请求URL
        StringBuffer urlBuffer = httpServletRequest.getRequestURL();
        // 根据默认请求地址拆分请求
        String[] urls = urlBuffer.toString().split(PORT + "/" + PATH + "/" );

        // 如果默认请求后还有值,并且请求中不带.说明这是非项目的接口请求
        if (urls.length > 1 && !urls[1].contains(".")) {
            // 获取请求参数
            Map<String, String[]> parameterMap = httpServletRequest.getParameterMap();
            // 给请求URL增加请求后缀
            urlBuffer.append(".htm");
            // 如果有请求参数把请求参数也给拼接上
            if (parameterMap.size() > 0) {
                urlBuffer.append("?");
                for (String key : parameterMap.keySet()) {
                    urlBuffer.append(key).append("=");
                    for (String value : parameterMap.get(key)) {
                        // 不为空的参数对参数进行编码
                        urlBuffer.append(StringUtils.isBlank(value)? "" : URLEncoder.encode(value));
                    }
                    urlBuffer.append("&");
                }
                // 去掉遍历时最后加上的&
                urlBuffer = new StringBuffer(urlBuffer.substring(0, urlBuffer.length() - 1));
            }
            // 根据新的URL重定向转发
            httpServletResponse.sendRedirect(urlBuffer.toString());
            return;
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

有几个点说明一下:

1.PATH和PORT根据自己的项目来设置;

2.这个判断条件主要是因为我的项目有个默认访问地址,就是 “/” 的请求;然后只用 “.” 而不是直接用接口后缀 “.htm” 是为了放行静态资源 “.js”、“.css” 等;

3.之后的对参数进行编码是因为swagger原来的请求的参数就是已经编码了的,但是到了过滤器这里时已经是解码好了,如果直接进行重定向请求会报404,所以在这对参数进行了编码;(亲测,不知道是不是就我的项目会)

4.在这些之后别忘了在自己的web.xml中增加这个过滤器的配置;

5.在这之后可能个别同学的项目还是可能会有请求404的问题,这种时候就要找找自己项目对controller层包扫描的配置了,一般情况下是只会扫描自己项目controller包路径下的类,但是我们还需要把swagger的请求接口所在的包路径放在扫描目录里,一般情况下,大概是“springfox.documentation.swagger2”这个包路径;

在做完这些之后,我这就可以正常使用集成的swagger了,knife4j也是一样;

在我原来的做法中,是把判断范围缩的很小,只要F12看一下,你们也会发现,swagger的主要请求其实就三个:

/swagger-resources/configuration/ui”、“/swagger-resources”、“/v2/api-docs

所以我一开始直接限制了这三个接口进行了URL后缀的增加,但是后续发现如果要进行接口调试的话,它的所有请求都是不带 “.htm” 请求后缀的,所以我后面增大了if中条件的判断范围;如果只是需要查看接口参数,不需要进行调试的同学可以只对上面的三个接口进行后缀的增加操作,这样对项目的影响程度也是会比较小;

二、修改knife4j-vue源码

这个方案看起来很难其实也还好,主要是看你想改到什么程度了,我就只是给请求都加上后缀,其他的都没改动(作为后端开发,我的前端技能还是比较薄弱的,前端大神们可以去用更好的办法去实现);我是把knife4j的源码从GitHub上拉下来改的,swagger的源码我没去看过了,从UI上看的话还是会选择knife4j的吧;

给个GitHub的地址吧:https://github.com/xiaoymin/swagger-bootstrap-ui

看它的README.md中对项目模块的说明还是比较清楚的,当我看到它knife4j-vue的模块名时,我第一想法就是,它做了前后端分离了,前端还是用VUE框架写的(它其实还有一个knife4j-vue-v3的模块,我粗略看它们是一样的);既然它前后端分离了,那我直接抛弃了其他模块,专注改它knife4j-vue的模块;

既然是改请求地址嘛,我第一个想法就是请求拦截,看main.js文件导入了axios,并且有一个response的拦截了,我也就加上request的拦截器,用console.log一直没反应;所以我直接跟着页面渲染创建的顺序一步步走,发现调用初始化信息那几个接口的请求根本没用到axios,而是通过Knife4jAsync.js中自定的SwaggerBootstrapUi.prototype.ajax函数,我在这里增加了一个request拦截器,给请求接口地址增加一个后缀就可以请求到后端了:

SwaggerBootstrapUi.prototype.ajax = function (config, success, error) {
  var ajax = DebugAxios.create();
  ajax.interceptors.response.use(response => {
    var data = response.data;
    return data
  }, error => {
    return Promise.reject(error)
  })

  // 增加request请求拦截器
  ajax.interceptors.request.use(function (config) {
    // url不为空的情况下给它增加一个后缀
    if(config.url !== undefined) {
      config.url = config.url + ".htm";
    }
    return config
  }, function (error) {    return Promise.reject(error)
  })

  ajax.request(config).then(data => {
    success(data);
  }).catch(err => {
    error(err);
  })
}

到这里只是对接口文档的配置信息的获取没问题了,但是到了调试时还是会有问题,看Debug.vue中的发送按钮绑定的事件,进行请求时用的也不是main.js文件中导入了axios,而是使用create新建了一个axios去请求;而且还会根据不同的请求类型去调用不同的函数,每个函数中都会使用create新建axios去请求;

DebugAxios.create()
          .request(requestConfig)
          .then(res => {
            this.debugLoading = false;
            this.handleDebugSuccess(startTime,new Date(), res);
          })
          .catch(err => {
            this.debugLoading = false;
            if (err.response) {
              this.handleDebugError(startTime,new Date(), err.response);
            } else {
              this.$message.error(err.message);
            }
          });

但是这些函数在组装请求参数的时候对URL都会调用一次this.debugCheckUrl(url)检测URL,所以我在这个函数的返回值上加上了我们的请求后缀 “.htm”,这样所有接口不管是什么请求类型,都会给URL加上后缀;

debugCheckUrl(url){
      var checkUrl=url;
      try{
        var reg=new RegExp('.*?(\{.*?\})$',"ig");
        if(reg.test(url)){
          var rr=RegExp.$1;
          checkUrl=url.replace(rr,"");
        }
      }catch(e){
        //ignore
        if(window.console){
          console.error(e);
        }
      }
      return checkUrl + ".htm";
    }

这个方法有几个注意点:

1.如果是就保持这样前后端分离,要记得在后端做跨越的配置,前端项目中的vue.config.jsdevServer.proxy也记得改成自己的后端地址,changeOrigin:true允许跨域也记得开启;

2.对于后端有设置spring.app.web.path的在它的接口调试的页面中的接口地址是默认带上这个path的,所以最好是在main.js里配置上axios.defaults.baseURL=[你后端配置的path],代理换成我这样的,[path]、[IP地址]、[端口]请换成对应项目的;

3.如果不做前后端分离的,直接下面的步骤就免了,直接打包,然后扔回源码中knife4j模块的knife4j-springdoc-ui子模块中,项目集成改过的源码就可以和原来的用法一样了;

devServer: {
    watchOptions:{
      ignored: /node_modules/
    },
    proxy: {
      "/[path]": {
      target: 'http://[IP地址]:[端口]/[path]',
        ws: true,
        changeOrigin: true,
        pathRewrite: {
          '^/[path]' : '/'
        }
      }
    }
  }

 这就是我目前对于这个问题研究出来的解决方案,有不对的地方很欢迎有同学提出来,共同学习、共同进步;有兴趣的同学还可以把knife4j的其他源码都拿来看看,它是开源的项目,包含的解决方案也很多。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringMVC集成Knife4j 2.0.9的步骤如下: 1. 在项目的`pom.xml`文件中添加Knife4j的依赖: ``` <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>2.0.9</version> </dependency> ``` 2. 配置SpringMVC的`WebMvcConfigurer`,并重写`addResourceHandlers`方法,将Knife4j的静态资源目录添加到资源处理器中: ```java @Configuration public class Knife4jConfiguration implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("doc.html") .addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/"); } } ``` 3. 在SpringMVC的配置类中添加`@EnableKnife4j`注解,开启Knife4j的自动配置功能: ```java @Configuration @EnableKnife4j public class MvcConfig { // 配置其他SpringMVC相关的配置 // ... } ``` 4. 在Controller类上使用Knife4j的注解,例如使用`@ApiOperation`注解添加接口文档的描述信息: ```java @RestController @Api(tags = "示例接口") public class SampleController { @ApiOperation("示例接口") @GetMapping("/sample") public String sample() { return "Hello, Knife4j!"; } } ``` 5. 启动项目后,访问`http://localhost:8080/doc.html`可以看到Knife4j接口文档页面,其中包含了通过`@ApiOperation`注解添加的接口信息。 以上就是使用SpringMVC集成Knife4j 2.0.9的简要步骤,通过这样的配置,可以方便地为SpringMVC项目添加接口文档功能。注意,这里的步骤仅适用于Knife4j 2.0.9版本,如果有其他版本的需求,请参考相应版本的官方文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值