转载  springboot重写RequestMappingHandlerMapping实现为指定包下Controller添加统一URI前缀

分类:spring,java 2022-07-06 14:00    193人阅读   

源码下载地址:https://yy123.ink/codeDetail/15412

需求源自最近公司要求提供一套APP2.0的接口,因为工期比较紧,来不及搭建一套新的项目,因此大家决定在原有的项目上直接提供对应的接口,所有的接口都放在指定的包下,对于这些接口直接通过在url前面添加v2版本标记来实现不同版本接口的访问。

 

整体思路是切入到SpringMvc初始化控制器方法映射的过程中,在spring建立url和指定方法之间的映射关系之后,提供服务之前,重写url。

经过简单的源码阅读,发现了spring对于url和方法映射关系的处理实际上是在RequestMappingHandlerMapping中实现的。

关联控制器和方法之间的url是在getMappingForMethod方法中完成的。

因此实现思路就有了,重写RequestMappingHandlerMappinggetMappingForMethod方法,完成追加url前缀的功能。

有了思路,代码完成就相对来说比较简单了:

自定义版本控制器接口定义

提供两个方法,一个方法是需要添加url前缀的控制器所属的包名称,一个是需要添加的url前缀。

/**
 * 版本控制器
 *
 * @author Hanqi <jpanda@aliyun.com>
 * @since 2019/3/14 9:58
 */
public interface VersionHandler {
    /**
     * 需要处理的控制器所处的包名
     */
    String getPackageName();
 
    /**
     * 需要添加的前缀
     */
    String getPrefix();
 
    /**
     * 是否匹配
     */
    boolean isPattern(Class<?> clazz);
 
    /**
     * 合并RequestMapping信息
     */
    RequestMappingInfo combineRequestMappingInfo(RequestMappingInfo original);
}

具体实现

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
 
@Slf4j
@Component
public class TwoVersionHandler implements VersionHandler {
    @Override
    public String getPackageName() {
        return "com.jpanda.example.controller";
    }
 
    @Override
    public String getPrefix() {
        return "v2";
    }
 
    @Override
    public boolean isPattern(Class<?> clazz) {
        if (null != clazz) {
            return clazz.getPackage().getName().startsWith(getPackageName());
        }
        return false;
    }
 
    @Override
    public RequestMappingInfo combineRequestMappingInfo(RequestMappingInfo original) {
        RequestMappingInfo requestMappingInfo = RequestMappingInfo.paths(getPrefix()).build().combine(original);
        if(log.isInfoEnabled()){
            log.info("will change {} onto {};",original,requestMappingInfo);
        }
        return requestMappingInfo;
    }
 
}

 

实现添加url前缀核心方法的请求映射处理器

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
 
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
 
/**
 * 支持版本管理的RequestMapping注解映射处理器
 *
 * @author Hanqi <jpanda@aliyun.com>
 * @since 2019/3/14 10:03
 */
@Slf4j
public class VersionControlRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
    /**
     * 版本控制器
     */
    protected Set<VersionHandler> versionHandlers;
    /**
     * 当前是否拥有版本控制器
     */
    protected boolean hasVersionHandler = false;
 
    @Override
    public void afterPropertiesSet() {
        // 初始化版本控制器类型集合
        initVersionHandlers();
        super.afterPropertiesSet();
    }
 
    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo info = super.getMappingForMethod(method, handlerType);
        if (info != null) {
            for (VersionHandler versionHandler : versionHandlers) {
                if (versionHandler.isPattern(handlerType)) {
                    return versionHandler.combineRequestMappingInfo(info);
                }
            }
        }
        return info;
    }
 
    /**
     * 初始化版本控制器集合
     */
    protected void initVersionHandlers() {
        versionHandlers = new HashSet<>(obtainApplicationContext().getBeansOfType(VersionHandler.class).values());
        hasVersionHandler = !CollectionUtils.isEmpty(versionHandlers);
    }
}

注册使用自定义的请求映射处理器

import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
 
/**
 * 配置使用自定义版本url处理器
 *
 * @author Hanqi <jpanda@aliyun.com>
 * @since 2019/3/13 16:11
 */
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class VersionControlWebMvcConfiguration implements WebMvcRegistrations {
    @Override
    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
        return new VersionControlRequestMappingHandlerMapping();
    }
}
 

 

支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者

服务器费用不足...

动态table表格小部件

js擦鞋效果

CSS写的灯笼动态效果

玉石翡翠直销商网站HTML模板

祖玛弹珠js小游戏代码

蓝色的网络建站公司HTML页面

Hover悬停按钮阴影box-shadow

用Bootstrap实现mansory网格瀑布流布局插件

生物实验室和科学研究网站模板下载

科技公司网站中文HTML模板

jquery slick轮播切换例子

6种时尚的营销多用途网页模板

动态的即将到来建设中HTML5模板

红色大气商业咨询业务公司主页模板

CSS3+DIV很酷的渐变波浪网页特效

3种样式环境保护网站绿色HTML5模板

CSS SVG开关按钮切换网页白天和夜晚

两队vs比赛照片显示效果

高端黄色工业和建筑集团HTML模板

Nodejs实现的后台管理模板下载

服务器费用不足...
 工具推荐 更多»