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

分类:spring,java    461人阅读    IT小君  2022-07-06 14:00

源码下载地址: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();
    }
}
 

 

服务器费用不足...

UFO适合404页面的jQuery特效

滚动下拉图片切斜HTML5特效

Vue轻量级后台管理系统基础框架模板--精

时尚的社交网站前端界面HTML模板 - Cirkle

区块链数字货币管理系统网页模板 - Cryptio

一个alert网页小部件

JS+CSS3卡通汽车行驶特效

bootstrap风格后台界面管理系统模板 - Voler

程序员向妹子表白专用代码

JavaScript模拟网页星际旅行特效

时尚和轻量设计Bootstrap4管理系统模板 - Sunny

Vue 3、Vite和TailwindCss开发的管理面板

物品租赁买卖业务平台HTML5模板 - Doremi

建筑工程机械设备租赁网站HTML模板 - Antek

Hotspot Map - 强大的图片热点注释和提示工具

HTML5大气导航栏鼠标悬停特效

黑客帝国文字雨矩阵动画特效

bootstrap框架web UI工具包后台模板 - MegaDin

给乌龟喂食卡通HTML5特效

CSS3机械工业风齿轮转动特效

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