实例说明:该实例重写 RequestMappingHandlerMapping 类的部分方法,达到给指定包下的所有控制器(Controller/Handler)设置统一的请求前缀。 这里以在接口前加版本号为例:/uri —>> /v2/uri

自定义前缀控制器处理器

接口,可以实现不同前缀的控制器处理器

  1. /**
  2. * @author zsy
  3. * @Date 2022/7/4 11:52
  4. */
  5. public interface TypeMappingHandler {
  6. /**
  7. * 处理的控制器所处的包名
  8. *
  9. * @return handler package
  10. */
  11. String getPackageName();
  12. /**
  13. * 处理的控制器所处的包名数组
  14. *
  15. * @return handler packages
  16. */
  17. String[] getPackageNames();
  18. /**
  19. * 要添加的前缀
  20. *
  21. * @return prefix
  22. */
  23. String getPrefix();
  24. /**
  25. * 是否匹配
  26. *
  27. * @param handlerType 控制器类型
  28. * @return 控制器类的包名与要处理的包名是否一致
  29. */
  30. boolean isPattern(Class<?> handlerType);
  31. /**
  32. * 修改默认 RequestMappingInfo
  33. *
  34. * @param original springmvc构造的RequestMapping信息
  35. * @return 添加完前缀的RequestMappingInfo(如果包名匹配)
  36. */
  37. RequestMappingInfo combineRequestMappingInfo(RequestMappingInfo original);
  38. }

实现类

  1. @Slf4j
  2. @Component
  3. public class InternalTypeMappingHandler implements TypeMappingHandler {
  4. @Override
  5. public String getPackageName() {
  6. return "com.tyros.v2.controller";
  7. }
  8. @Override
  9. public String[] getPackageNames() {
  10. // 支持多包名
  11. return new String[0];
  12. }
  13. @Override
  14. public String getPrefix() {
  15. return "v2";
  16. }
  17. @Override
  18. public boolean isPattern(Class<?> handlerType) {
  19. boolean flag = false;
  20. if (ArrayUtil.isNotEmpty(getPackageNames()) && Objects.nonNull(handlerType)) {
  21. for (String packageName : getPackageNames()) {
  22. flag = handlerType.getPackage().getName().startsWith(packageName);
  23. if (flag) {
  24. break;
  25. }
  26. }
  27. } else if (Objects.nonNull(handlerType)) {
  28. flag = handlerType.getPackage().getName().startsWith(getPackageName());
  29. }
  30. return flag;
  31. }
  32. @Override
  33. public RequestMappingInfo combineRequestMappingInfo(RequestMappingInfo original) {
  34. RequestMappingInfo target = RequestMappingInfo.paths(getPrefix()).build().combine(original);
  35. if (log.isInfoEnabled()) {
  36. log.info("Build RequestMapping Success, {} -->> {}", original, target);
  37. }
  38. return target;
  39. }
  40. }

实现 RequestMappingHandlerMapping

public class TypeControlRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
    /**
     * 类型控制器
     */
    protected Set<TypeMappingHandler> typeMappingHandlers;
    /**
     * 当前是否拥有类型控制器
     */
    protected boolean hasTypeHandler = false;

    @Override
    public void afterPropertiesSet() {
        // 初始化类型控制器类型集合
        initVersionHandlers();
        super.afterPropertiesSet();
    }

    @Override
    @Nullable
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo info = super.getMappingForMethod(method, handlerType);
        if (Objects.nonNull(info)) {
            for (TypeMappingHandler typeMappingHandler : typeMappingHandlers) {
                if (typeMappingHandler.isPattern(handlerType)) {
                    return typeMappingHandler.combineRequestMappingInfo(info);
                }
            }
        }
        return info;
    }

    /**
     * 初始化版本控制器集合
     */
    protected void initVersionHandlers() {
        typeMappingHandlers = new HashSet<>(obtainApplicationContext().getBeansOfType(TypeMappingHandler.class).values());
        hasTypeHandler = !CollectionUtils.isEmpty(typeMappingHandlers);
    }
}

注册映射处理器

@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class TypeControlWebMvcRegistrations implements WebMvcRegistrations {

    @Override
    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
        return new TypeControlRequestMappingHandlerMapping();
    }
}