SpringBoot + 指定包下所有控制器 + 添加统一前缀

https://my.oschina.net/u/3101282/blog/3022154

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

个人比较懒,且需求是对指定包下所有的控制器都添加指定的url前缀,因此就产生了该blog。

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

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

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

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

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

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

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

/**
 * 版本控制器
 *
 * @author Hanqi <[email protected]>
 * @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 <[email protected]>
 * @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 <[email protected]>
 * @since 2019/3/13 16:11
 */
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class VersionControlWebMvcConfiguration implements WebMvcRegistrations {
    
    
    @Override
    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
    
    
        return new VersionControlRequestMappingHandlerMapping();
    }
}

猜你喜欢

转载自blog.csdn.net/u014641168/article/details/120827484