概述SpringWebMVC包括WebMvc.fn,这是一个轻量级的函数式编程模型,其中函数用于路由和处理请求,参数和返回值被设计成不可变的。它是基于注释的编程模型的替代方案,但在其他方面运行在同一个DispatcherServlet上。在WebMvc.fn中,HTTP请求由HandlerFunction处理:该函数接受ServerRequest并返回ServerResponse。请求和响应对象都是不可变的,为JDK8提供了对HTTP请求和响应的友好访问。HandlerFunction相当于注解编程模型中的@RequestMapping方法体。传入请求通过RouterFunction路由到处理程序函数:该函数接受ServerRequest并返回可选的HandlerFunction(即可选)。当router函数匹配时,返回handler函数;否则为空可选。RouterFunction等同于@RequestMapping注解,但主要区别在于路由函数不仅提供数据,还提供行为。示例:@ConfigurationpublicclassPersonH??andlerConfiguration{@BeanpublicRouterFunctionperson(){returnroute().GET("/person",accept(MediaType.APPLICATION_JSON),request->{returnServerResponse.status(HttpStatus.OK).body("HelloWorld")).build();}}我们需要在@Configuration配置类中将RouterFunction公开为一个Bean对象。GET方法的三个参数:第一个:请求的接口地址。第二种:predicate是限制可以匹配哪些调用,类似于注解接口@RequestMapping参数中的consumer,params等属性。第三个:HandlerFunction,也就是处理器对象。实际的业务方法处理与@RequestMapping的方法体进行对比。HandlerFunction对象ServerRequest和ServerResponse是不可变接口,提供对HTTP请求和响应的JDK8友好访问,包括标头、文字、方法和状态代码。ServerRequestServerRequest提供对HTTP方法、URI、标头和查询参数的访问,而对主体的访问是通过主体方法提供的。下面的例子:@BeanpublicRouterFunctionstudent(){returnroute().GET("/student/{id}",accept(MediaType.APPLICATION_JSON),request->{returnServerResponse.ok().body("name="+request.param("name").get()+",id="+request.pathVariable("id"));}).POST("/student",accept(MediaType.APPLICATION_JSON),request->{returnServerResponse.ok().body(request.body(Student.class));}).build();}GET接口获取查询参数和路径上的参数。POST接口获取正文内容。ServerResponseServerResponse提供对HTTP响应的访问,并且因为它是不可变的,所以可以使用build方法创建它。构建器可用于设置响应状态、添加响应标头或提供文本。在上面的例子中已经看到了如何使用,这里就不举例了。Handler类Processor类在一个文件中单独定义handler类进行相应的处理,类似于传统的@RestController注解,很多接口方法都定义在一个Controller类中。示例:@ConfigurationpublicclassPersonH??andlerConfiguration{@ResourceprivatePersonH??andlerph;@BeanpublicRouterFunctionperson(){returnroute().GET("/person/{id}",accept(MediaType.APPLICATION_JSON),ph::queryPerson).POST("/person",accept(MediaType.APPLICATION_JSON),ph::save).build();}}处理器类(其中可以注入DAO类进行相关的数据库操作)@ComponentpublicclassPersonH??andler{publicServerResponsesave(ServerRequestrequest)throwsException{returnok().body(request.body(Person.class));}publicServerResponsequeryPerson(ServerRequestrequest)throwsException{returnok().body(newPerson(Integer.valueOf(request.pathVariable("id")),"China"));}}校验验证可以使用Spring的验证工具对请求主体应用验证。例如,给定一个自定义的Spring验证器实现。示例:@ComponentpublicclassPersonH??andler{@ResourceprivateValidatorvalidator;publicServerResponsesave(ServerRequestrequest)throwsException{Personperson=request.body(Person.class);Errorserrors=validate(person);if(errors==null){returnok().body(person);}returnok().body(errors.toString());}privateErrorsvalidate(Personperson){Errorserrors=newBeanPropertyBindingResult(person,"person");validator.validate(person,errors);if(errors.hasErrors()){returnerrors;}returnull;}}需要引入依赖:org.springframework.bootspring-boot-starter-validation关于参数校验《Springboot项目中你的参数都在如何验证?这个starter你知道吗?》RouterFunctionrouterFunctions用于将请求路由到相应的HandlerFunction。通常,您不会自己编写路由器函数,而是使用RouterFunctions类上的方法来创建路由器函数。RouterFunctions.route()(无参数)为您提供了一个用于创建路由器函数的流畅生成器,而RouterFunctions.route(RequestPredicate,HandlerFunction)提供了一个用于创建路由器的直接方法。一般来说,推荐使用route()构建,因为它为典型的映射场景提供了一个方便的快捷方式,而不需要难以找到的静态导入。例如,路由器功能构建器提供了方法GET(String,HandlerFunction)来为GET请求创建映射;和POST(String,HandlerFunction)用于POST。除了基于HTTP方法的映射之外,路由构建器还提供了一种在映射到请求时引入额外谓词的方法。对于每个HTTP方法,都有一个以RequestPredicate作为参数的重载变体,通过它可以表达额外的约束。在上面的例子中,我们已经看到在做相应的GET和POST方法时传递的第二个参数。PredicatePredicate我们可以自己写RequestPredicate,但是RequestPredicates类提供了基于请求路径、HTTP方法、内容类型等的通用实现,下面的例子使用Accept来限制可以接收的数据类型。importstaticorg.springframework.web.servlet.function.RequestPredicates.accept;@BeanpublicRouterFunctionhello(){returnroute().GET("/hello",accept(MediaType.APPLICATION_JSON),request->{returnServerResponse.status(HttpStatus.OK).body("HelloWorld");})。build();}也可以通过andororaccept(...).and()||添加多个谓词or()嵌套路由在传统的Controller定义时,可以在类中添加@RequestMapping("/person")注解,统一请求接口的前缀。在功能接口中,我们可以这样设置:@BeanpublicRouterFunctionnestPerson(){returnroute().path("/persons",builder->builder.GET("/{id}",accept(MediaType.APPLICATION_JSON),ph::queryPerson).POST("/save",ph::save)).build();}通过路径定义路由前缀。也可以这样使用:@BeanpublicRouterFunctionnestPerson2(){returnroute().path("/persons2",b1->b1.nest(accept(MediaType.APPLICATION_JSON),b2->b2.GET("/{id}",accept(MediaType.APPLICATION_JSON),ph::queryPerson)).POST("/save",ph::save)).build();}HandlerMapping是函数式接口,因为底层还是使用DispatcherServlet,那么它就会有对应的HandlerMapping和AdapterRouterFunctionMapping:检测Spring配置中的一个或多个RouterFunctionbeans,将它们排序,通过RouterFunction.andOther组合,将请求路由到生成的组合RouterFunction。HandlerFunctionAdapter:一个简单的适配器,让DispatcherHandler调用映射到请求的HandlerFunction。过滤器可以使用路由函数构建器上的before、after或filter方法来过滤处理函数。对于接口注解的方式,我们可以使用@ControllerAdvice、ServletFilter或者两者都实现类似的功能。过滤器将应用于生成器生成的所有路由。这意味着嵌套路由中定义的过滤器不适用于“顶级”路由。示例:@BeanpublicRouterFunctionnestPerson2(){returnroute().path("/persons2",b1->b1.nest(accept(MediaType.APPLICATION_JSON),b2->b2.GET("/{id}",接受(MediaType.APPLICATION_JSON),ph::queryPerson).before(request->ServerRequest.from(request).header("x-pack","123123").build())).POST("/save",ph::save)).after((request,response)->{System.out.println("afterexecution..."+response.statusCode());returnresponse;}).filter((request,next)->{if(request.pathVariable("id").equals("100")){returnServerResponse.ok().body("参数错误");}else{returnext.handle(request);}})。build();}publicServerResponsequeryPerson(ServerRequestrequest)throwsException{System.out.println(request.headers().header("x-pack"));returnok().body(newPerson(Integer.valueOf(request.pathVariable("id")),"China"));}before:添加了自定义的header信息,然后我们在queryPerson中就可以获取到,而before只能应用于当前的嵌套路由。之后:可以应用于所有路由。filter:filter方法使用HandlerFilterFunction:使用ServerRequest和HandlerFunction,返回一个ServerResponse的函数。处理函数参数表示链中的下一个元素。这通常是要路由到的处理程序,但如果应用了多个过滤器,它也可以是另一个过滤器。SwaggerSwagger这个时候是没用的,还是要慎用。