网站开发教学视频教程,家装平面设计主要做什么,网页设计图,电子商务网站推广策划方案★ Spring WebFlux的两种开发方式
1. 采用类似于Spring MVC的注解的方式来开发。此时开发时感觉Spring MVC差异不大#xff0c;但底层依然是反应式API。2. 使用函数式编程来开发★ 使用函数式方式开发Web Flux
使用函数式开发WebFlux时需要开发两个组件#xff1a;
▲ Han…★ Spring WebFlux的两种开发方式
1. 采用类似于Spring MVC的注解的方式来开发。此时开发时感觉Spring MVC差异不大但底层依然是反应式API。2. 使用函数式编程来开发★ 使用函数式方式开发Web Flux
使用函数式开发WebFlux时需要开发两个组件
▲ Handler作用该处理器组件相当于控制器它负责处理客户端的请求、并对客户端生成响应。该Handler组件的每个方法都只带一个ServerRequest参数不是Servlet API——代表客户端请求对象且每个方法的返回值类型都是MonoServerResponse代表作为服务器响应的消息发布者。mono 代表一个消息发布者▲ Router作用该组件通过函数式的编程方式来定义URL与Handler处理方法之间的映射关系。★ WebFlux通过ServerRequest获取请求数据的两种方式
这两种方式并不是可以自由选择的而是根据数据的来源不同需要采用对应的获取策略。- 对于以请求体提交的数据通常会通过formData()表单数据或bodyToFlux()或bodyToMono()RESTful方法来获取由于这种方式都需要通过网络IO读取数据可能会造成阻塞因此它们都采用了订阅-发布的异步方式这三个方法的返回值都是Mono或Flux消息发布者。- 对于URL中的数据包括传统请求参数和路径参数由于它们只要直接解析URL字符串即可读取数据不会造成阻塞因此没有采用订阅-发布的异步方式。直接用pathVariable()或queryParam()方法即可读取数据。★ Handler方法的返回值
Handler作用 该处理器组件相当于控制器它负责处理客户端的请求、并对客户端生成响应。
Handler处理方法的返回值类型是MonoServerResponse
调用ServerResponse的ok()相当于将响应状态码设为200、
contentType()方法返回ServerResponse.BodyBuilder对象。
有了ServerResponse.BodyBuilder对象之后根据响应类型不同
可调用如下两个方法来生成MonoServerResponse作为返回值▲ render(String name, MapString,? model)使用模板引擎来生成响应其中第一个参数代表逻辑视图名第二个参数代表传给模板的model数据。render()方法还有其他重载形式功能类似。▲ body(P publisher, ClassT elementClass)直接设置响应体类生成响应同样用于生成RESTful响应。body()方法还有其他重载形式功能类似。★ 使用Router定义URL与Handler方法的对应关系
Router作用 该组件通过函数式的编程方式来定义URL与Handler处理方法之间的映射关系。 ▲ Router就是容器中RouterFunctions类型的Bean。——通常来说就是使用Configuration修饰的配置类来配置该Bean即可。return RouterFunctions// 定义映射地址和处理器方法之间的对应关系.route(RequestPredicates.POST(/login).and(RequestPredicates.accept(MediaType.TEXT_HTML)), handler::login).andRoute(RequestPredicates.GET(/viewBook/{id}).and(RequestPredicates.accept(MediaType.TEXT_HTML)), handler::viewBook);代码演示
同个请求演示跟 spring mvc 不同的实现方法。
请求的数据是简单的url数据就是前端传来的数据id是写在url 的。
总结通过添加 Handler 类相当于之前的controller 然后创建一个 Router 配置类通过在配置类 配置 Router Bean 这个bean来实现对客户端请求来的URL 与 Handler处理方法之间的映射关系。最终响应回json格式的数据或者 html 页面。
Handler该处理器组件相当于控制器它负责处理客户端的请求、并对客户端生成响应,这个类就是handler组件
现在弄一个 Handler 类用来处理客户端的请求是一个处理数据的类相当于controller
这个方法是生成 RESTful 响应的就是 Json 响应 这个方法是生成 HTML 响应的
Router作用该组件通过函数式的编程方式来定义URL与Handler处理方法之间的映射关系。
配置 Router Bean 负责完成请求 URL 和 Handler 处理方法之间的映射。
设置方法的请求路径是 “/viewBookabc/{id}” 走这个路径就会访问这个 handler::viewBook 方法。 而 handler::viewBooks 是 lambda 中的方法引用 会找到 BookHandler 类中的 viewBook 方法
bean 方法里面的参数是 BookHandler所以可以用 lambda 的方法引用功能 来引用该类的viewBook方法。
负责完成 【请求URL】 和 【Handler处理方法】 之间的映射。
Handler处理方法就是 BookHandler 的 viewBook 方法。
返回响应给html的页面
这个bean在项目启动的时候就会被加载。
调用方法看看流程 访问方法就会走 BookHandler 的 这个方法。
测试结果 完整代码
BookHandler
// Handler该处理器组件相当于控制器它负责处理客户端的请求、并对客户端生成响应,这个类就是handler组件
Component
public class BookHandler
{private BookService bookService;//有参构造器完成依赖注入public BookHandler(BookService bookService){this.bookService bookService;}// Handler该处理器组件相当于控制器它负责处理客户端的请求、并对客户端生成响应,这个类就是handler组件//这个方法是生成 RESTful 响应的public MonoServerResponse viewBook(ServerRequest request){//如果请求参数是通过 URL 字符串即可解析可用 pathVariable()或queryParam()方法获取参数Integer id Integer.parseInt(request.pathVariable(id));Book book bookService.getBook(id);//ok() 表示服务器响应正常MonoServerResponse body ServerResponse.ok()//选择生成 JSON 响应类型.contentType(MediaType.APPLICATION_JSON)//如果要生成 JSON 响应直接用 body 方法//参数1代表数据发布者Publisher参数2指定 Mono 中每个数据项的类型//Mono 的 justOrEmpty 将单个及可能为null的数据包装成 Mono//如果是设计良好的应用就是底层数据库的访问也是用 reactor api // 这样此处从数据库返回的数据就是 Mono 或者 Flux根本不需要包装.body(Mono.justOrEmpty(book), Book.class);return body;}//这个方法是生成 HTML 响应的public MonoServerResponse viewBookHtml(ServerRequest request){//如果请求参数是通过 URL 字符串即可解析可用 pathVariable()或queryParam()方法获取参数Integer id Integer.parseInt(request.pathVariable(id));Book book bookService.getBook(id);//ok() 表示服务器响应正常MonoServerResponse render ServerResponse.ok()//选择生成 HTML 响应类型.contentType(MediaType.TEXT_HTML)//参数1逻辑视图名 参数2相当于 spring mvc 的 model用于向视图页面传输数据.render(viewBook, Map.of(book, book));return render;}
}RouterConfig
package cn.ljh.FunctionalFlux.router;import cn.ljh.FunctionalFlux.handler.BookHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;Configuration //配置类
public class RouterConfig
{//配置 Router Bean 负责完成请求 URL 和 Handler 处理方法之间的映射。Beanpublic RouterFunctionServerResponse routerFunctions(BookHandler handler){//MediaType.APPLICATION_JSON 设置响应类型 handler::viewBooks 是 lambda 中的方法引用RouterFunctionServerResponse route RouterFunctions//这里就映射到 BookHandler 类里面的 viewBook 方法/viewBookabc/{id}这个是我们这边给的访问路径.route(RequestPredicates.GET(/viewBookabc/{id}).and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), handler::viewBook)//这里就映射到 BookHandler 类里面的 viewBookHtml 方法/viewBookHtml/{id}这个是我们这边给的访问路径.andRoute(RequestPredicates.GET(/viewBookHtml/{id}).and(RequestPredicates.accept(MediaType.TEXT_HTML)), handler::viewBookHtml);return route;}
}上面的代码演示请求的数据是简单的url数据就是前端传来的数据id是写在url 的。
这次演示的是前端以 表单 的方式 或 restful 方式提交数据。
演示以 RESTful 方式提交的数据的处理
这边接收前端传来的数据并进行处理相当于controller
这里的bean就是处理 请求url 和 handler处理方法 之间的映射关系
测试结果 成功处理添加书本的方法添加的书本的数据在postman中实现。
演示通过表单页面提交请求
写一个简单的表单页面
前端通过表单页面提交请求
添加 请求 URL 和 Handler 处理方法之间的映射
测试结果
注意发现因为 handler处理方法那里因为使用了map 把源 Mono 转成新的 Mono当时转换的结果没去用它所以出现添加不成功的问题。
如图 如果不需要使用 Mono 转换之后的结果此时就不需要使用 map() 方法 map() 方法就是负责将 源Mono 转换成新的 Mono 如果只是希望用到 Mono 中的数据此时成为消费数据 就是把这条消息消费掉就行因为不需要把 Mono 的结果返回到视图页面所以不需要用map方法进行转换。
测试成功 成功通过表单页面提交请求
前端注意小知识
在 templates 路径下的静态页面是不能直接访问的得通过控制器的处理方法进行转发才能访问到。 或者直接把页面放在静态资源目录static、public才能直接访问。 注意页面得是静态页面不能有动态内容不能是动态页面。 完整代码
domain
处理类BookHandler类似于controller
package cn.ljh.FunctionalFlux.handler;import cn.ljh.FunctionalFlux.domain.Book;
import cn.ljh.FunctionalFlux.service.BookService;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.time.Duration;
import java.util.Collection;
import java.util.Map;// Handler该处理器组件相当于控制器它负责处理客户端的请求、并对客户端生成响应,这个类就是handler组件
Component
public class BookHandler
{private BookService bookService;//有参构造器完成依赖注入public BookHandler(BookService bookService){this.bookService bookService;}// Handler该处理器组件相当于控制器它负责处理客户端的请求、并对客户端生成响应,这个类就是handler组件//这个方法是生成 RESTful 响应的 就是 Json 响应public MonoServerResponse viewBook(ServerRequest request){//如果请求参数是通过 URL 字符串即可解析可用 pathVariable()或queryParam()方法获取参数Integer id Integer.parseInt(request.pathVariable(id));Book book bookService.getBook(id);//ok() 表示服务器响应正常MonoServerResponse body ServerResponse.ok()//选择生成 JSON 响应类型.contentType(MediaType.APPLICATION_JSON)//如果要生成 JSON 响应直接用 body 方法//参数1代表数据发布者Publisher参数2指定 Mono 中每个数据项的类型//Mono 的 justOrEmpty 将单个及可能为null的数据包装成 Mono//如果是设计良好的应用就是底层数据库的访问也是用 reactor api // 这样此处从数据库返回的数据就是 Mono 或者 Flux根本不需要包装.body(Mono.justOrEmpty(book), Book.class);return body;}//这个方法是生成 HTML 响应的public MonoServerResponse viewBookHtml(ServerRequest request){//如果请求参数是通过 URL 字符串即可解析可用 pathVariable()或queryParam()方法获取参数Integer id Integer.parseInt(request.pathVariable(id));Book book bookService.getBook(id);//ok() 表示服务器响应正常MonoServerResponse render ServerResponse.ok()//选择生成 HTML 响应类型.contentType(MediaType.TEXT_HTML)//参数1逻辑视图名 参数2相当于 spring mvc 的 model用于向视图页面传输数据.render(viewBook, Map.of(book, book));return render;}//以 RESTful 方式提交的数据的处理public MonoServerResponse addBook(ServerRequest request){//假设数据来自 RESTful 的 POST 请求此时用 bodyToMono() 或 bodyToFlux() 来获取数据//bodyToFlux()如果请求的数据中包含多个数据就用这个。//bodyToMono()如果请求的数据只有一个数据那就用这个//这两个方法参数指定了 Mono 或 Flux 中数据的类型// 添加一本图书只是一个对象所以用.bodyToMono() // 如果是一个集合就应该使用 .bodyToFlux()MonoBook bookMono request.bodyToMono(Book.class);//map() 负责将 Mono 或者 Flux 中的元素转换成新的 Mono 或 Flux 中的元素MonoBook resultMono bookMono.map(book -{//添加 Book 对象bookService.addBook(book);return book;});MonoServerResponse body ServerResponse.ok()//选择生成 JSON 响应类型.contentType(MediaType.APPLICATION_JSON)//如果要生成 JSON 响应直接用 body 方法//参数1代表数据发布者Publisher参数2指定 Mono 中每个数据项的类型//Mono 的 justOrEmpty 将单个及可能为null的数据包装成 Mono//如果是设计良好的应用就是底层数据库的访问也是用 reactor api // 这样此处从数据库返回的数据就是 Mono 或者 Flux根本不需要包装.body(resultMono, Book.class);return body;}//通过表单页面提交请求public MonoServerResponse addBookHtml(ServerRequest request){//假设数据来自 表单页面 的 POST 请求通过 formData() 获取表单的数据MonoMultiValueMapString, String formData request.formData();/** 如果不需要使用 Mono 转换之后的结果此时就不需要使用 map() 方法* map() 方法就是负责将 源Mono 转换成新的 Mono* 如果只是希望用到 Mono 中的数据此时成为消费数据*/formData.subscribe(map -{String name map.get(name).get(0);String price map.get(price).get(0);String author map.get(author).get(0);Book book new Book(null, name, Double.parseDouble(price), author);bookService.addBook(book);});MonoServerResponse render ServerResponse.ok()//选择生成 JSON 响应类型.contentType(MediaType.TEXT_HTML).render(addBookResult, Map.of(tip, 添加书籍成功));return render;}}配置类RouterConfig添加个bean处理url和handler类中的方法的映射关系
package cn.ljh.FunctionalFlux.router;import cn.ljh.FunctionalFlux.handler.BookHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;Configuration //配置类
public class RouterConfig
{//配置 Router Bean 负责完成请求 URL 和 Handler 处理方法之间的映射。Beanpublic RouterFunctionServerResponse routerFunctions(BookHandler handler){//MediaType.APPLICATION_JSON 设置响应类型 handler::viewBooks 是 lambda 中的方法引用RouterFunctionServerResponse route RouterFunctions//这里就映射到 BookHandler 类里面的 viewBook 方法/viewBookabc/{id}这个是我们这边给的访问路径.route(RequestPredicates.GET(/viewBookabc/{id}).and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), handler::viewBook)//这里就映射到 BookHandler 类里面的 viewBookHtml 方法/viewBookHtml/{id}这个是我们这边给的访问路径.andRoute(RequestPredicates.GET(/viewBookHtml/{id}).and(RequestPredicates.accept(MediaType.TEXT_HTML)), handler::viewBookHtml)//这里就映射到 BookHandler 类里面的 addBook 方法/addBook 这个是我们这边给的访问路径.andRoute(RequestPredicates.POST(/addBook).and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), handler::addBook)//这里就映射到 BookHandler 类里面的 addBookHtml 方法/addBookHtml/{id}这个是我们这边给的访问路径.andRoute(RequestPredicates.POST(/addBookHtml).and(RequestPredicates.accept(MediaType.TEXT_HTML)), handler::addBookHtml);return route;}
}BookService
package cn.ljh.FunctionalFlux.service;import cn.ljh.FunctionalFlux.domain.Book;
import java.util.Collection;public interface BookService
{Book getBook(Integer id);Integer addBook(Book book);CollectionBook getAllBooks();
}BookServiceImpl
package cn.ljh.FunctionalFlux.service.impl;import cn.ljh.FunctionalFlux.domain.Book;
import cn.ljh.FunctionalFlux.service.BookService;
import org.springframework.stereotype.Service;import java.util.*;//添加这个Service注解springboot就可以自动扫描这个Service组件的实现类然后把这个类部署成容器中的bean。
Service
public class BookServiceImpl implements BookService
{//添加一个 Map 集合假设为数据库public static final MapInteger, Book bookDB new LinkedHashMap();//创建一个自增idstatic int nextId 4;//初始化这个数据库static{bookDB.put(1, new Book(1, 火影忍者, 100.0, 岸本));bookDB.put(2, new Book(2, 家庭教师, 110.0, 天野明));bookDB.put(3, new Book(3, 七龙珠Z, 120.0, 鸟山明));}//查看图书Overridepublic Book getBook(Integer id){Book book bookDB.get(id);if (book null){throw new RuntimeException(没有此图书信息);}return book;}//添加图书Overridepublic Integer addBook(Book book){book.setId(nextId);bookDB.put(nextId,book);//返回id先返回在自增。return nextId;}//查看所有的图书Overridepublic CollectionBook getAllBooks(){//获取集合中的所有元素CollectionBook values bookDB.values();return values;}
}添加图书页面addBook.html
!DOCTYPE html
html langen
headmeta charsetUTF-8title添加图书页面/title
/head
body
h2添加图书页面/h2form methodpost action/addBookHtml书名input namename idname typetextbr价格input nameprice idprice typetextbr作者input nameauthor idauthor typetextbrinput typesubmit value提交/input typereset value重设/
/form
/body
/html添加图书结果页面addBookResult.html
!DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8title添加图书结果/title
/head
body
h2添加图书结果/h2
div th:text${tip}
/div
/body
/html根据id查询图书viewBook.html
!DOCTYPE html
html langen xmlns:thhttp://www.thymeleaf.org
headmeta charsetUTF-8title查看图书/title
/head
body
h2查看图书/h2
div th:text${book.name}/div
div th:text${book.price}/div
div th:text${book.author}/div/div
/body
/html