首页 为springboot的所有路由添加公共路径
文章
取消

为springboot的所有路由添加公共路径

简介

项目uri设计时,正常都会有个公共路径,如”/api/login”、”/api/logout”,这里”/api”就是公共路径。为了避免在每一个controller里添加这个api,可以使用一些技术方案来一次性处理一下。

方案

方案一:自定义DispatcherServlet

Spring 应用程序中负责处理 Web 请求的主要组件是DispatcherServlet。通过自定义此组件,我们可以对请求的路由方式进行相当程度的控制。让我们看一下自定义DispatcherServlet的两种不同方法,这将使我们的所有应用程序端点都可以通过公共 URL 前缀使用。

a: 使用configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 创建package.config.DispatcherServletCustomConfig
@Configuration
public class DispatcherServletCustomConfig {

    @Bean
    public DispatcherServlet dispatcherServlet() {
        return new DispatcherServlet();
    }

    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(dispatcherServlet(), "/api/*");
        registrationBean.setName(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
        return registrationBean;
    }
}
1
2
3
4
5
6
7
8
9
// 在package.controller.HelloController里
// 这样就可以通过/api/hello访问此controller method了
@RestController
public class HelloController {
    @GetMapping("/hello")
    public ResponseEntity<Object> hello() {
        return new ResponseEntity<>("hello", HttpStatus.OK);
    }
}

b: 直接使用springboot的配置文件

1
server.servlet.contextPath = /api

方案的优缺点

虽然可以简单的一次性全部添加/api路径很方便,但是对于一些不想使用/api做公共路径的服务,处理起来就很麻烦了。

方案二:使用注解

a. 直接使用Spring扩展语言

1
2
# 首先直接在springboot配置文件application.properties添加一下内容
apiPrefix = /api
1
2
3
4
5
6
7
8
// 然后注解时添加变量
@RestController
public class HelloController {
    @GetMapping("${apiPrefix}/hello")
    public ResponseEntity<Object> hello() {
        return new ResponseEntity<>("hello", HttpStatus.OK);
    }
}

a. 自定义注解

1
2
3
4
5
6
7
8
9
10
// 创建package.annotation.ApiPrefixController
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
@RequestMapping("/api")
public @interface ApiPrefixController {
    @AliasFor(annotation = Component.class)
    String value() default "";
}
1
2
3
4
5
6
7
8
9
// 在controller使用自定义注解
@ApiPrefixController
@RestController
public class HelloController {
    @GetMapping("/hello")
    public ResponseEntity<Object> hello() {
        return new ResponseEntity<>("hello", HttpStatus.OK);
    }
}

方案的优缺点

相比前面的方案,这个方案定制化程度很高,而且可以细粒度到每个方法上。

方案三:使用服务端路由转发

a. 路由转发

这个转发并不是301/302给客户端,而是直接根据逻辑内部分流到子服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 创建目标控制器,有多个方法,定义多个http入口
@Controller
class DemoEndpointController {
    @GetMapping("/endpoint1")
    @ResponseBody
    public String endpoint1() {
        return "endpoint1";
    }

    @GetMapping("/endpoint2")
    @ResponseBody
    public String endpoint2() {
        return "endpoint2";
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 创建路由类,这里我根据条件跳转到/endpoint1或/endpoint2
@Controller
@RequestMapping("/api/endpoint")
public class ApiPrefixController {

    @GetMapping
    public ModelAndView route(ModelMap model) {
        if(new Random().nextBoolean()) {
            return new ModelAndView("forward:/endpoint1", model);
        } 
        else {
            return new ModelAndView("forward:/endpoint2", model);
        }
    }
}

方案的优缺点

这个方案和前面几种方案不同,它使用/api/endpoint作为uri,这样做的好处就是可以根据http的方法、header的参数等进行路由切换,缺点是我们经常需要/api/login/api/logout在uri上区分好业务功能。

知识共享许可协议 本文由作者按照 CC BY-SA 4.0 进行授权