Java:SpringBoot给Controller添加统一路由前缀

网上的文章五花八门,不写SpringBoot的版本号,导致代码拿来主义不好使了。

本文采用的版本

SpringBoot 2.7.7
Java 1.8

 

 

1、默认访问路径

package com.example.demo.controller.api;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class AppIndexController {
    @GetMapping("/index")
    public String index() {
        return "app";
    }
}

访问地址:http://localhost:8080/api/index

2、整个项目增加路由前缀

application.yml

server:
  servlet:
    context-path: /prefix

访问地址:http://localhost:8080/prefix/api/index

注意:该方案会将所有的路由都增加一个前缀

3、通过注解方式增加路由前缀

注解

package com.example.demo.annotation;

import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RestController;

import java.lang.annotation.*;

/**
 * controller层统一使用该注解
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RestController
public @interface ApiRestController {
    /**
     * Alias for {@link Controller#value}.
     */
    @AliasFor(annotation = Controller.class)
    String value() default "";
}

配置

package com.example.demo.config;


import com.example.demo.annotation.ApiRestController;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 配置统一的后台接口访问路径的前缀
 */
@Configuration
public class CustomWebMvcConfig implements WebMvcConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer
                .addPathPrefix("/api", c -> c.isAnnotationPresent(ApiRestController.class));
    }

}

使用注解

package com.example.demo.controller.api;

import com.example.demo.annotation.ApiRestController;
import org.springframework.web.bind.annotation.GetMapping;

@ApiRestController
// @RestController
// @RequestMapping("/api")
public class AppIndexController {
    @GetMapping("/index")
    public String index() {
        return "app";
    }
}

访问地址:http://localhost:8080/api/index

4、按照目录结构/包名添加前缀

没有成功,可能是版本的问题

按照网上的实现方式

// 核心代码
RequestMappingInfo.paths(prefix).build().combine(mappingInfo);

会报错

Neither PathPatterns nor String patterns condition

2023年6月9日补充

感谢评论区的大佬 @孤独和弦 帮助,补充第四种方式

思路:

将原有路由的所有路径取出,手动拼接前缀,再和原有路由配置合并

项目结构

$ tree -I target -I test
.
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           └── demo
        │               ├── Application.java
        │               ├── config
        │               │   ├── AutoPrefixConfiguration.java
        │               │   └── AutoPrefixUrlMapping.java
        │               └── controller
        │                   └── v1
        │                       └── IndexController.java
        └── resources
            ├── application.yml
            ├── static
            └── templates

配置 application.yml

# 需要添加路径前缀的包名
api-package: com.example.demo.controller

AutoPrefixUrlMapping.java

package com.example.demo.config;

import org.springframework.beans.factory.annotation.Value;
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.Objects;

/**
 * 自动补全路由前缀处理类
 */
public class AutoPrefixUrlMapping extends RequestMappingHandlerMapping {

    /**
     * 读取基础包配置
     */
    @Value("${api-package}")
    private String bathApiPackagePath;

    /**
     * 重写方法路由获取
     *
     * @param method
     * @param handlerType
     * @return
     */
    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo mappingInfo = super.getMappingForMethod(method, handlerType);

        if (Objects.nonNull(mappingInfo)) {
            String prefix = this.getPrefix(handlerType);

            if (prefix != null) {
                String[] paths = mappingInfo.getPatternValues()
                        .stream()
                        .map(path -> prefix + path)
                        .toArray(String[]::new);

                return mappingInfo.mutate()
                        .paths(paths)
                        .build();
            }
        }

        return mappingInfo;
    }

    /**
     * 获取方法路由前缀
     *
     * @param handleType
     * @return
     */
    private String getPrefix(Class<?> handleType) {
        String packageName = handleType.getPackage().getName();

        // 如果包含指定的包则返回前缀
        if (packageName.startsWith(this.bathApiPackagePath)) {
            return packageName.substring(this.bathApiPackagePath.length())
                    .replace(".", "/");

        } else {
            return null;
        }
    }

}

AutoPrefixConfiguration.java

package com.example.demo.config;

import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

/**
 * 自动补全路由前缀配置类
 */
@Component
public class AutoPrefixConfiguration implements WebMvcRegistrations {
    @Override
    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
        return new AutoPrefixUrlMapping();
    }
}

控制器

package com.example.demo.controller.v1;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class IndexController {

    @GetMapping("/index")
    public String index() {
        return "Hello";
    }
}

访问路径:http://localhost:8080/v1/api/index

总结

方 式 适用范围
RequestMapping/PostMapping/GetMapping 单个方法 或 单个类(多个方法)
自定义注解 多个控制器(可以不同目录)
目录 / 包名 前缀 多个控制器(同目录)
配置 context-path 全局前缀

包名前缀只能是符合java包名规范的才可以,比如中划线就不行,需要修改代码自定义做映射

参考文章

posted @ 2024-01-01 22:21  CharyGao  阅读(1470)  评论(0编辑  收藏  举报