@RestController 和 RouterFunction 的区别
@RestController和RouterFunction是Spring WebFlux框架中用于构建响应式Web应用程序的两种不同的方式。
-
@RestController:
- @RestController是基于注解的方式,用于定义RESTful风格的控制器类。
- 通过在方法上使用注解(如@GetMapping、@PostMapping等),可以将HTTP请求映射到相应的处理方法上。
- @RestController适用于传统的基于注解的MVC模式,它提供了简单直观的方式来处理HTTP请求和生成响应。
-
RouterFunction:
- RouterFunction是函数式编程的方式,用于定义路由和处理函数之间的映射关系。
- 它将HTTP请求的路由规则与处理函数进行绑定,使得请求能够被正确地路由到相应的处理函数进行处理。
- RouterFunction适用于响应式编程模型,它提供了更灵活的方式来定义路由规则,并支持异步非阻塞的处理方式。
使用方法:
-
@RestController的使用方法:
- 创建一个带有@RestController注解的控制器类。
- 在方法上使用合适的注解(如@GetMapping、@PostMapping等)来定义请求映射。
- 在方法体内编写处理逻辑,并返回相应的数据或视图。
-
RouterFunction的使用方法:
- 创建一个RouterFunction对象。
- 使用路由函数(如route、GET、POST等)定义路由规则和处理函数之间的映射关系。
- 在处理函数中编写异步非阻塞的处理逻辑,并返回相应的数据或视图。
@RestController和RouterFunction是两种不同的编程模型,选择使用哪种方式取决于具体的需求和开发风格。
@RestController 和 RouterFunction 的使用
@RestController示例:
@RestController
@RequestMapping("/example")
public class ExampleController {
@GetMapping
public String getExample() {}
@PostMapping
public String createExample() {}
@PutMapping("/{id}")
public String updateExample(@PathVariable String id) {}
@DeleteMapping("/{id}")
public String deleteExample(@PathVariable String id) {}
}
RouterFunction示例:
首先准备一个测试方法类
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;
/**
* @Author Admin
* @Date 2023/9/5 21:20
* @Description ExampleHandler
**/
@Component
public class ExampleHandler {
public ServerResponse getExample(ServerRequest request) {
// 获取参数信息
String id = request.pathVariable("id");
// 处理获取示例的逻辑
return ServerResponse.ok().body("GET-查询请求, 参数信息:["+id+"]: Get example");
}
public ServerResponse createExample(ServerRequest request) {
// 处理创建示例的逻辑
return ServerResponse.ok().body("POST-创建请求: Create example");
}
public ServerResponse updateExample(ServerRequest request) {
// 获取参数信息
MultiValueMap<String, String> params = request.params();
// 处理更新示例的逻辑
return ServerResponse.ok()
.body("UPDATE-修改请求, 参数信息:[" + params.toSingleValueMap() + "]: Update example");
}
public ServerResponse deleteExample(ServerRequest request) {
// 接收参数
String delId = request.pathVariable("delId");
// 处理删除示例的逻辑
return ServerResponse.ok().body("Delete-删除请求, 参数信息:[" + delId + "]: Delete example");
}
public ServerResponse getInfo(ServerRequest request) {
// 处理获取示例的逻辑
return ServerResponse.ok().body("GET-查询请求: Get getInfo");
}
}
(1)编写方式一:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.function.RequestPredicates;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.RouterFunctions;
import org.springframework.web.servlet.function.ServerResponse;
import static org.springframework.web.servlet.function.RequestPredicates.GET;
/**
* @Author Admin
* @Description RouterFunction的使用
**/
@Configuration
public class TestController {
@Bean
public RouterFunction<ServerResponse> routeExampleHandler(ExampleHandler exampleHandler) {
RouterFunctions.Builder route = RouterFunctions.route();
route = route.GET("/example/{id}", exampleHandler::getExample);
route = route.POST("/example", exampleHandler::createExample);
route = route.PUT("/example/update", exampleHandler::updateExample);
route = route.DELETE("/example/{delId}", exampleHandler::deleteExample);
return route.build();
}
}
请求及响应
- GET请求:
- POST请求:
- PUT请求:
- DELETE请求:
以上是RouterFunction函数请求增删改查的四种请求方式,也可以换成链式写法:
@Bean
public RouterFunction<ServerResponse> routeExampleHandler(ExampleHandler exampleHandler) {
return RouterFunctions.route()
.GET("/example", exampleHandler::getExample)
.POST("/example", exampleHandler::createExample)
.PUT("/example/update", exampleHandler::updateExample)
.DELETE("/example/{delId}", exampleHandler::deleteExample)
.build();
}
路由嵌套,RouterFunctions中nest方法
RouterFunction。它可以将一组相关的路由规则进行分组,并将它们作为一个整体应用到主路由上。RouterFunctions.nest的使用示例如下:
@Bean
public RouterFunction<ServerResponse> mainRouterFunction(ExampleHandler exampleHandler) {
return RouterFunctions.route()
.path("/api", builder -> builder
.nest(RequestPredicates.path("/example"), nestedBuilder -> nestedBuilder
.GET("/{id}", exampleHandler::getExample)
.POST("", exampleHandler::createExample)
)
.GET("/info", exampleHandler::getInfo)
)
.build();
}
在上面的示例中,我们定义了一个mainRouterFunction
方法,返回类型为RouterFunction<ServerResponse>
。在该方法内,我们使用RouterFunctions.route()
创建主路由构建器,并使用.path()
方法来定义路径匹配规则。
在.path("/api", builder -> builder ...)
中,我们将一组相关的路由规则分组到/api
路径下。然后,在嵌套的.nest(RequestPredicates.path("/example"), nestedBuilder -> nestedBuilder ...)
中,我们将另一组路由规则分组到/api/example
路径下。
通过使用RouterFunctions.nest
,我们可以更好地组织和管理路由规则,使代码结构更清晰,并提高可读性和可维护性。
直接使用RouterFunctions构建一个请求
@Bean
public RouterFunction<ServerResponse> mainRouterFunction(ExampleHandler exampleHandler) {
return RouterFunctions.route(GET("/api/example/{uid}"),
request -> {
Long uid = Long.valueOf(request.pathVariable("uid"));
return ServerResponse.ok().body("路径 /api/example 参数信息: " + uid);
}
);
}
API文档 RouterFunction<T extends ServerResponse>
accept(RouterFunctions.Visitor visitor)
接受给定的访问者。
and(RouterFunction<T> other)
返回一个组合路由函数,该函数首先调用该函数,然后在该路由没有结果的情况下调用另一个函数(相同响应类型T)。
andNest(RequestPredicate predicate, RouterFunction<T> routerFunction)
如果路由不匹配且给定的请求谓词适用,则返回一个组成的路由函数,该函数会路由到给定的路由器函数。
andOther(RouterFunction<?> other)
返回一个组成的路由函数,该函数首先调用此函数,如果此路由没有结果,则调用另一个函数(不同响应类型)。
andRoute(RequestPredicate predicate, HandlerFunction<T> handlerFunction)
如果路由不匹配且给定的请求谓词适用,则返回一个组成的路由函数,该函数会路由到给定的处理函数。
filter(HandlerFilterFunction<T,S> filterFunction)
使用给定的过滤函数过滤此函数路由的所有处理函数。
route(ServerRequest request)
返回与给定请求匹配的处理函数。
withAttribute(String name, Object value)
返回一个带有给定属性的新路由函数。
withAttributes(Consumer<Map<String,Object>> attributesConsumer)
返回一个新的路由函数,并使用给定的消费者操作属性。
API文档链接 RouterFunction<T extends ServerResponse>
RouterFunction 实现原理:
1、路由器函数注册:通过 RouterFunctions 类的静态方法创建 RouterFunction 对象,并使用路由器函数将请求映射到处理程序函数上。
2、请求匹配:当收到一个 HTTP 请求时,Spring WebFlux 框架会根据请求的 URL、HTTP 方法等信息进行匹配。
3、处理程序函数执行:一旦找到与请求匹配的路由器函数,框架会调用相应的处理程序函数来处理请求。处理程序函数可以是一个 Lambda 表达式、方法引用或其他函数式编程方式定义的函数。
4、响应生成:处理程序函数执行完成后,会生成一个响应对象,包含要返回给客户端的数据和相关的 HTTP 状态码、头部信息等。
5、响应发送:最后,框架将生成的响应发送给客户端。