如何在Spring Boot中实现类似Django的路由前缀复用?
在Spring Boot中实现类似Django的路由前缀复用配置
我之前做过Django项目,里面可以创建带前缀的路由集合,再通过include引入其他URL文件来定义端点的剩余部分,示例代码如下:
api_patterns= [ url('foo/', include(foo.urls)), url('bar/', include(bar.urls)), ] urlpatterns = [ url(r'api/', include(api_patterns)), ]
这种方式会生成/api/foo/和/api/bar/端点,每个端点对应不同目录下的独立URL文件,无需重复编写前缀。
现在我在Spring Boot项目里,目前是给每个控制器的@RequestMapping添加前缀,但大量控制器都共用相同的前缀,比如下面的例子:
// Foo controller @Controller @RequestMapping(path = "api/foo") public class FooController { @GetMapping(path = "") // 对应端点 /api/foo } // Bar controller @Controller @RequestMapping(path = "api/bar") public class BarController { @GetMapping(path = "") // 对应端点 /api/bar } // Tar controller by foo @Controller @RequestMapping(path = "api/foo/tar") public class TarController { @GetMapping(path = "") // 对应端点 /api/foo/tar }
这样每个控制器都要重复写api/甚至更长的前缀,我认为这是不良实践,想优化这种重复写法,请问Spring Boot里有没有等价于Django那种路由前缀复用的实现方式?
解决方案
1. 控制器继承实现前缀复用
创建一个基础控制器类,定义公共前缀,同前缀的控制器继承该类,只需要编写剩余路径部分:
// 基础API控制器,定义公共前缀/api @Controller @RequestMapping("api") public class BaseApiController { // 可在此添加公共逻辑,比如权限校验、通用响应处理 } // Foo控制器,仅需编写子前缀foo @Controller @RequestMapping("foo") public class FooController extends BaseApiController { @GetMapping("") // 对应端点 /api/foo public String fooEndpoint() { return "foo"; } } // Bar控制器同理 @Controller @RequestMapping("bar") public class BarController extends BaseApiController { @GetMapping("") // 对应端点 /api/bar public String barEndpoint() { return "bar"; } } // Tar控制器,编写子前缀foo/tar @Controller @RequestMapping("foo/tar") public class TarController extends BaseApiController { @GetMapping("") // 对应端点 /api/foo/tar public String tarEndpoint() { return "tar"; } }
后续如果公共前缀需要修改,只需调整父类的@RequestMapping即可,无需逐个修改控制器。
2. 全局统一前缀配置(适用于所有API)
如果所有接口都需要统一的api/前缀,可通过配置类全局设置,无需在控制器上重复声明:
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 WebMvcConfig implements WebMvcConfigurer { @Override public void configurePathMatch(PathMatchConfigurer configurer) { // 给所有标注@Controller的类添加/api前缀 configurer.addPathPrefix("api", c -> c.isAnnotationPresent(Controller.class)); } }
之后控制器只需编写自身路径:
@Controller @RequestMapping("foo") public class FooController { @GetMapping("") // 对应端点 /api/foo public String fooEndpoint() { return "foo"; } }
3. 按模块分组配置前缀(Spring Boot 2.6+)
如果需要给不同模块的控制器设置不同前缀,可使用@ControllerAdvice按包或类分组配置:
import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.RequestMapping; // 给com.example.api.foo包下的所有控制器添加/api/foo前缀 @ControllerAdvice(basePackages = "com.example.api.foo") @RequestMapping("api/foo") public class FooApiAdvice { }
该包下的控制器只需编写自身路径:
package com.example.api.foo; @Controller public class TarController { @GetMapping("tar") // 对应端点 /api/foo/tar public String tarEndpoint() { return "tar"; } }
这种方式适合按业务模块划分前缀的场景,不同模块的前缀可独立配置。
内容的提问来源于stack exchange,提问作者Arif Jehda-Oh
相关产品推荐
相关产品推荐

