响应式R2DBC数据库mybatis

介绍

响应式:Web、网络、IO(存储)、中间件(Redis、MySQL)
应用开发:
● 网络
● 存储:MySQL、Redis
● Web:Webflux
● 前端; 后端:Controller – Service – Dao(r2dbc;mysql)

R2dbc
用法:
1、导入驱动: 导入连接池(r2dbc-pool)、导入驱动(r2dbc-mysql )
2、使用驱动提供的API操作

        <dependency><groupId>io.asyncer</groupId><artifactId>r2dbc-mysql</artifactId><version>1.0.5</version></dependency>

在这里插入图片描述

在这里插入图片描述

daima

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

最外面的pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.10</version></parent><groupId>com.learn</groupId><artifactId>learn-programming</artifactId><version>1.0-SNAPSHOT</version><modules>
<!--        <module>chapter01-stream</module>-->
<!--        <module>chapter02-reactor</module>--><module>learn-webflux</module><module>learn-r2dbc</module>
<!--        <module>chapter05-security</module>--></modules><packaging>pom</packaging><properties>
<!--        <maven.compiler.source>17</maven.compiler.source>-->
<!--        <maven.compiler.source>12</maven.compiler.source>--><maven.compiler.source>1.8</maven.compiler.source>
<!--        <maven.compiler.target>17</maven.compiler.target>-->
<!--        <maven.compiler.target>12</maven.compiler.target>--><maven.compiler.target>1.8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties></project>

r2dbc pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>learn-programming</artifactId><groupId>com.learn</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>learn-r2dbc</artifactId><properties><!--        <maven.compiler.source>17</maven.compiler.source>--><maven.compiler.source>12</maven.compiler.source><!--        <maven.compiler.target>17</maven.compiler.target>--><maven.compiler.target>12</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!-- https://mvnrepository.com/artifact/io.asyncer/r2dbc-mysql --><dependency><groupId>io.asyncer</groupId><artifactId>r2dbc-mysql</artifactId><version>1.0.5</version></dependency><!--        响应式 Spring Data R2dbc--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-r2dbc</artifactId></dependency><!--        响应式Web  --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies></project>

在这里插入图片描述

package com.learn.r2dbc.config.converter;import com.learn.r2dbc.entity.TAuthor;
import com.learn.r2dbc.entity.TBookAuthor;
import io.r2dbc.spi.Row;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;/*** @author lfy* @Description* @create 2023-12-23 22:04** 告诉Spring Data 怎么封装Book对象*/
@ReadingConverter //读取数据库数据的时候,把row转成 TBook
public class BookConverter implements Converter<Row, TBookAuthor> {//1)、@Query 指定了 sql如何发送//2)、自定义 BookConverter 指定了 数据库返回的一 Row 数据,怎么封装成 TBook//3)、配置 R2dbcCustomConversions 组件,让 BookConverter 加入其中生效@Overridepublic TBookAuthor convert(Row source) {if(source == null) return null;//自定义结果集的封装TBookAuthor tBook = new TBookAuthor();tBook.setId(source.get("id", Long.class));tBook.setTitle(source.get("title", String.class));Long author_id = source.get("author_id", Long.class);tBook.setAuthorId(author_id);
//        tBook.setPublishTime(source.get("publish_time", Instant.class));//让 converter兼容更多的表结构处理if (source.getMetadata().contains("name")) {TAuthor tAuthor = new TAuthor();tAuthor.setId(author_id);tAuthor.setName(source.get("name", String.class));tBook.setAuthor(tAuthor);}return tBook;}
}

在这里插入图片描述

package com.learn.r2dbc.config;import com.learn.r2dbc.config.converter.BookConverter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.r2dbc.convert.R2dbcCustomConversions;
import org.springframework.data.r2dbc.dialect.MySqlDialect;
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;/*** @author lfy* @Description* @create 2023-12-23 21:37** 1、写 AuthorRepositories 接口*/
@EnableR2dbcRepositories //开启 R2dbc 仓库功能;jpa
@Configuration
public class R2DbcConfiguration {@Bean //替换容器中原来的@ConditionalOnMissingBeanpublic R2dbcCustomConversions conversions(){//把我们的转换器加入进去; 效果新增了我们的 Converterreturn R2dbcCustomConversions.of(MySqlDialect.INSTANCE,new BookConverter());}
}

在这里插入图片描述

package com.learn.r2dbc.controller;import com.learn.r2dbc.entity.TAuthor;
import com.learn.r2dbc.entity.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;/*** @author lfy* @Description* @create 2023-12-23 20:58*/@RestController
public class AuthorController {@GetMapping("/author")public Flux<TAuthor> getAllAuthor(){return null;}@GetMapping("/hello")public String hello() {return "Hello, WebFlux !";}@GetMapping("/user")public Mono<User> getUser() {User user = new User();user.setName("犬小哈");user.setDesc("欢迎关注我的公众号: 小哈学Java");return Mono.just(user);}}

在这里插入图片描述

package com.learn.r2dbc.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.relational.core.mapping.Table;import java.util.List;/*** @author lfy* @Description* @create 2023-12-23 20:35*/@Table("t_author")
@NoArgsConstructor
@AllArgsConstructor
@Data
public class TAuthor {@Idprivate Long id;private String name;//1-N如何封装@Transient //临时字段,并不是数据库表中的一个字段
//    @Field(exist=false)private List<TBook> books;
}

在这里插入图片描述

package com.learn.r2dbc.entity;import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;import java.time.Instant;
import java.util.Date;/*** @author lfy* @Description* @create 2023-12-23 21:52*/
@Table("t_book")
@Data
public class TBook {@Idprivate Long id;private String title;private Long authorId;
//    private Instant publishTime; //响应式中日期的映射用 Instant 或者 LocalXxx//    private TAuthor author; //每本书有唯一作者;}

在这里插入图片描述

package com.learn.r2dbc.entity;import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;/*** @author lfy* @Description* @create 2023-12-24 20:17*/
@Table("t_book")
@Data
public class TBookAuthor {@Idprivate Long id;private String title;private Long authorId;
//    private Instant publishTime; //响应式中日期的映射用 Instant 或者 LocalXxxprivate TAuthor author; //每本书有唯一作者;
}

在这里插入图片描述

package com.learn.r2dbc.entity;import lombok.Data;/*** @author cg* @ClassName User* @date 2024-07-08 10:09*/@Data
public class User {/*** 姓名*/private String name;/*** 描述*/private String desc;
}

在这里插入图片描述

package com.learn.r2dbc.repositories;import com.learn.r2dbc.entity.TAuthor;
import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.r2dbc.repository.R2dbcRepository;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;import java.util.Collection;/*** @author lfy* @Description* @create 2023-12-23 21:38*/
@Repository
public interface AuthorRepositories extends R2dbcRepository<TAuthor,Long> {//默认继承了一堆CRUD方法; 像mybatis-plus//QBC: Query By Criteria//QBE: Query By Example//成为一个起名工程师  where id In () and name like ?//仅限单表复杂条件查询Flux<TAuthor> findAllByIdInAndNameLike(Collection<Long> id, String name);//多表复杂查询@Query("select * from t_author") //自定义query注解,指定sql语句Flux<TAuthor> findHaha();// 1-1:关联// 1-N:关联//场景:// 1、一个图书有唯一作者; 1-1// 2、一个作者可以有很多图书: 1-N}

在这里插入图片描述

package com.learn.r2dbc.repositories;import com.learn.r2dbc.entity.TBookAuthor;
import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.r2dbc.repository.R2dbcRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Mono;/*** @author lfy* @Description* @create 2023-12-23 21:54*/
@Repository
public interface BookAuthorRepostory extends R2dbcRepository<TBookAuthor,Long> {// 1-1关联关系; 查出这本图书以及它的作者@Query("select b.*,t.name as name from t_book b" +" LEFT JOIN t_author t on b.author_id = t.id " +" WHERE b.id = :bookId")Mono<TBookAuthor> hahaBook(@Param("bookId")Long bookId);}

在这里插入图片描述

package com.learn.r2dbc.repositories;import com.learn.r2dbc.entity.TBook;
import org.springframework.data.r2dbc.repository.R2dbcRepository;
import org.springframework.stereotype.Repository;/*** @author lfy* @Description* @create 2023-12-23 21:54*/
@Repository
public interface BookRepostory extends R2dbcRepository<TBook,Long> {//    // 1-1关联关系; 查出这本图书以及它的作者
//    @Query("select b.*,t.name as name from t_book b" +
//            " LEFT JOIN t_author t on b.author_id = t.id " +
//            " WHERE b.id = :bookId")
//    Mono<TBook> hahaBook(@Param("bookId")Long bookId);}

在这里插入图片描述

package com.learn.r2dbc;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** @author lfy* @Description* @create 2023-12-23 20:59*** SpringBoot 对r2dbc的自动配置* 1、R2dbcAutoConfiguration:   主要配置连接工厂、连接池** 2、R2dbcDataAutoConfiguration: 主要给用户提供了 R2dbcEntityTemplate 可以进行CRUD操作*      R2dbcEntityTemplate: 操作数据库的响应式客户端;提供CruD api ; RedisTemplate XxxTemplate*      数据类型映射关系、转换器、自定义R2dbcCustomConversions 转换器组件*      数据类型转换:int,Integer;  varchar,String;  datetime,Instant**** 3、R2dbcRepositoriesAutoConfiguration: 开启Spring Data声明式接口方式的CRUD;*      mybatis-plus: 提供了 BaseMapper,IService;自带了CRUD功能;*      Spring Data:  提供了基础的CRUD接口,不用写任何实现的情况下,可以直接具有CRUD功能;*** 4、R2dbcTransactionManagerAutoConfiguration: 事务管理**/@SpringBootApplication
public class R2DBCMainApplication {public static void main(String[] args) {SpringApplication.run(R2DBCMainApplication.class,args);}
}

在这里插入图片描述

spring:r2dbc:password: 123
#    password: 123456username: user123url: r2dbc:mysql://localhost:3306/test?serverZoneId=Asia/Shanghainame: test
logging:level:org.springframework.r2dbc: debug

在这里插入图片描述

package com.learn.r2dbc;import com.learn.r2dbc.entity.TAuthor;
import com.learn.r2dbc.entity.TBook;
import com.learn.r2dbc.repositories.AuthorRepositories;
import com.learn.r2dbc.repositories.BookAuthorRepostory;
import com.learn.r2dbc.repositories.BookRepostory;
import io.asyncer.r2dbc.mysql.MySqlConnectionConfiguration;
import io.asyncer.r2dbc.mysql.MySqlConnectionFactory;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.r2dbc.convert.R2dbcCustomConversions;
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.data.relational.core.query.Query;
import org.springframework.r2dbc.core.DatabaseClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;@SpringBootTest
/*** @author lfy* @Description* @create 2023-12-23 20:16*/
public class R2DBCTest {//最佳实践:  提升生产效率的做法//1、Spring Data R2DBC,基础的CRUD用 R2dbcRepository 提供好了//2、自定义复杂的SQL(单表): @Query;//3、多表查询复杂结果集: DatabaseClient 自定义SQL及结果封装;//Spring Data 提供的两个核心底层组件@Autowired  // join查询不好做; 单表查询用R2dbcEntityTemplate r2dbcEntityTemplate; //CRUD API; 更多API操作示例: https://docs.spring.io/spring-data/relational/reference/r2dbc/entity-persistence.html@Autowired  //贴近底层,join操作好做; 复杂查询好用DatabaseClient databaseClient; //数据库客户端@AutowiredAuthorRepositories authorRepositories;@AutowiredBookRepostory bookRepostory;@AutowiredBookAuthorRepostory bookAuthorRepostory;@AutowiredR2dbcCustomConversions r2dbcCustomConversions;@Testvoid oneToN() throws IOException {//        databaseClient.sql("select a.id aid,a.name,b.* from t_author a  " +
//                "left join t_book b on a.id = b.author_id " +
//                "order by a.id")
//                .fetch()
//                .all(row -> {
//
//                })// 1~6// 1:false 2:false 3:false 4: true 8:true 5:false 6:false 7:false 8:true 9:false 10:false// [1,2,3]// [4,8]// [5,6,7]// [8]// [9,10]// bufferUntilChanged:// 如果下一个判定值比起上一个发生了变化就开一个新buffer保存,如果没有变化就保存到原buffer中//        Flux.just(1,2,3,4,8,5,6,7,8,9,10)
//                .bufferUntilChanged(integer -> integer%4==0 )
//                .subscribe(list-> System.out.println("list = " + list));; //自带分组Flux<TAuthor> flux = databaseClient.sql("select a.id aid,a.name,b.* from t_author a  " +"left join t_book b on a.id = b.author_id " +"order by a.id").fetch().all().bufferUntilChanged(rowMap -> Long.parseLong(rowMap.get("aid").toString())).map(list -> {TAuthor tAuthor = new TAuthor();Map<String, Object> map = list.get(0);tAuthor.setId(Long.parseLong(map.get("aid").toString()));tAuthor.setName(map.get("name").toString());//查到的所有图书List<TBook> tBooks = list.stream().map(ele -> {TBook tBook = new TBook();tBook.setId(Long.parseLong(ele.get("id").toString()));tBook.setAuthorId(Long.parseLong(ele.get("author_id").toString()));tBook.setTitle(ele.get("title").toString());return tBook;}).collect(Collectors.toList());tAuthor.setBooks(tBooks);return tAuthor;});//Long 数字缓存 -127 - 127;// 对象比较需要自己写好equals方法flux.subscribe(tAuthor -> System.out.println("tAuthor = " + tAuthor));System.in.read();}@Testvoid author() throws IOException {authorRepositories.findById(1L).subscribe(tAuthor -> System.out.println("tAuthor = " + tAuthor));System.in.read();}@Testvoid book() throws IOException {
//        bookRepostory.findAll()
//                .subscribe(tBook -> System.out.println("tBook = " + tBook));//        bookRepostory.findBookAndAuthor(1L)
//                .map(book-> {
//                    Long authorId = book.getAuthorId();
//                    TAuthor block = authorRepositories.findById(authorId).block();
//                    book.setAuthor(block);
//                    return book;
//                });//1-1: 第一种方式:  自定义转换器封装
//        bookRepostory.hahaBook(1L)
//                .subscribe(tBook -> System.out.println("tBook = " + tBook));//自定义转换器  Converter<Row, TBook> : 把数据库的row转成 TBook; 所有TBook的结果封装都用这个//工作时机: Spring Data 发现方法签名只要是返回 TBook。 利用自定义转换器进行工作//对以前的CRUD产生影响; 错误:Column name 'name' does not exist//解决办法://  1)、新VO+新的Repository+自定义类型转化器//  2)、自定义类型转化器 多写判断。兼容更多表类型System.out.println("bookRepostory.findById(1L).block() = "+ bookRepostory.findById(1L).block());System.out.println("================");System.out.println("bookAuthorRepostory.hahaBook(1L).block() = " + bookAuthorRepostory.hahaBook(1L).block());//1-1:第二种方式
//        databaseClient.sql("select b.*,t.name as name from t_book b " +
//                        "LEFT JOIN t_author t on b.author_id = t.id " +
//                        "WHERE b.id = ?")
//                .bind(0, 1L)
//                .fetch()
//                .all()
//                .map(row-> {
//                    String id = row.get("id").toString();
//                    String title = row.get("title").toString();
//                    String author_id = row.get("author_id").toString();
//                    String name = row.get("name").toString();
//                    TBook tBook = new TBook();
//
//                    tBook.setId(Long.parseLong(id));
//                    tBook.setTitle(title);
//
//                    TAuthor tAuthor = new TAuthor();
//                    tAuthor.setName(name);
//                    tAuthor.setId(Long.parseLong(author_id));
//
//                    tBook.setAuthor(tAuthor);
//
//                    return tBook;
//                })
//                .subscribe(tBook -> System.out.println("tBook = " + tBook));// buffer api: 实现一对N;//两种办法://1、一次查询出来,封装好//2、两次查询// 1-N: 一个作者;可以查询到很多图书System.in.read();}//简单查询: 人家直接提供好接口//复杂条件查询://    1、QBE API//    2、自定义方法//    3、自定义SQL@Testvoid authorRepositories() throws IOException {
//        authorRepositories.findAll()
//                .subscribe(tAuthor -> System.out.println("tAuthor = " + tAuthor));//statement// [SELECT t_author.id, t_author.name FROM t_author WHERE t_author.id IN (?, ?)// AND (t_author.name LIKE ?)]//方法起名
//        authorRepositories.findAllByIdInAndNameLike(
//                Arrays.asList(1L,2L),
//                "张%"
//        ).subscribe(tAuthor -> System.out.println("tAuthor = " + tAuthor));//自定义@Query注解authorRepositories.findHaha().subscribe(tAuthor -> System.out.println("tAuthor = " + tAuthor));System.in.read();}@Testvoid databaseClient() throws IOException {// 底层操作databaseClient.sql("select * from t_author")
//                .bind(0,2L).fetch() //抓取数据.all()//返回所有.map(map -> {  //map == bean  属性=值System.out.println("map = " + map);String id = map.get("id").toString();String name = map.get("name").toString();return new TAuthor(Long.parseLong(id), name, null);}).subscribe(tAuthor -> System.out.println("tAuthor = " + tAuthor));System.in.read();}@Testvoid r2dbcEntityTemplate() throws IOException {// Query By Criteria: QBC//1、Criteria构造查询条件  where id=1 and name=张三Criteria criteria = Criteria.empty().and("id").is(1L).and("name").is("张三");//2、封装为 Query 对象Query query = Query.query(criteria);r2dbcEntityTemplate.select(query, TAuthor.class).subscribe(tAuthor -> System.out.println("tAuthor = " + tAuthor));System.in.read();}//思想:// 1、有了r2dbc,我们的应用在数据库层面天然支持高并发、高吞吐量。// 2、并不能提升开发效率@Testvoid connection() throws IOException {// r2dbc基于全异步、响应式、消息驱动// jdbc:mysql://localhost:3306/test// r2dbc:mysql://localhost:3306/test//0、MySQL配置MySqlConnectionConfiguration configuration = MySqlConnectionConfiguration.builder().host("localhost").port(3306).username("root").password("123456").database("test").build();//1、获取连接工厂MySqlConnectionFactory connectionFactory = MySqlConnectionFactory.from(configuration);//2、获取到连接,发送sql// JDBC: Statement: 封装sql的//3、数据发布者Mono.from(connectionFactory.create()).flatMapMany(connection ->connection.createStatement("select * from t_author where id=?id and name=?name").bind("id", 1L) //具名参数.bind("name", "张三").execute()).flatMap(result -> {return result.map(readable -> {Long id = readable.get("id", Long.class);String name = readable.get("name", String.class);return new TAuthor(id, name, null);});}).subscribe(tAuthor -> System.out.println("tAuthor = " + tAuthor));//背压; 不用返回所有东西,基于请求量返回;System.in.read();}
}

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>learn-programming</artifactId><groupId>com.learn</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>learn-webflux</artifactId><properties><!--        <maven.compiler.source>17</maven.compiler.source>-->
<!--        <maven.compiler.source>12</maven.compiler.source>--><maven.compiler.source>1.8</maven.compiler.source><!--        <maven.compiler.target>17</maven.compiler.target>-->
<!--        <maven.compiler.target>12</maven.compiler.target>--><maven.compiler.target>1.8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency></dependencies></project>

在这里插入图片描述

package com.learn.webflux.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.CorsRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;/*** @author lfy* @Description* @create 2023-12-01 22:16*/
@Configuration
public class MyWebConfiguration {//配置底层@Beanpublic WebFluxConfigurer webFluxConfigurer(){return new WebFluxConfigurer() {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedHeaders("*").allowedMethods("*").allowedOrigins("localhost");}};}
}

在这里插入图片描述

package com.learn.webflux.controller;import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.reactive.result.view.Rendering;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebSession;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.time.Duration;/*** @author lfy* @Description* @create 2023-12-01 20:52*/
@ResponseBody@Controller
public class HelloController {//WebFlux: 向下兼容原来SpringMVC的大多数注解和API;@GetMapping("/hello")public String hello(@RequestParam(value = "key",required = false,defaultValue = "哈哈") String key,ServerWebExchange exchange,WebSession webSession,HttpMethod method,HttpEntity<String> entity,@RequestBody String s,FilePart file){//        file.transferTo() //零拷贝技术;ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();String name = method.name();Object aaa = webSession.getAttribute("aaa");webSession.getAttributes().put("aa","nn");return "Hello World!!! key="+key;}// Rendering:一种视图对象。@GetMapping("/bai")public Rendering render(){
//        Rendering.redirectTo("/aaa"); //重定向到当前项目根路径下的 aaareturn   Rendering.redirectTo("http://www.baidu.com").build();}//现在推荐的方式//1、返回单个数据Mono: Mono<Order>、User、String、Map//2、返回多个数据Flux: Flux<Order>//3、配合Flux,完成SSE: Server Send Event; 服务端事件推送@GetMapping("/haha")public Mono<String> haha(){//        ResponseEntity.status(305)
//                .header("aaa","bbb")
//                .contentType(MediaType.APPLICATION_CBOR)
//                .body("aaaa")
//                .return Mono.just(0).map(i-> 10/i).map(i->"哈哈-"+i);}@GetMapping("/hehe")public Flux<String> hehe(){return Flux.just("hehe1","hehe2");}//text/event-stream//SSE测试; chatgpt都在用; 服务端推送@GetMapping(value = "/sse",produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<ServerSentEvent<String>> sse(){return Flux.range(1,10).map(i-> {//构建一个SSE对象return    ServerSentEvent.builder("ha-" + i).id(i + "").comment("hei-" + i).event("haha").build();}).delayElements(Duration.ofMillis(500));}//SpringMVC 以前怎么用,基本可以无缝切换。// 底层:需要自己开始编写响应式代码}

在这里插入图片描述

package com.learn.webflux.exception;import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;/*** @author lfy* @Description* @create 2023-12-01 21:40*/
//全局异常处理@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(ArithmeticException.class)public String error(ArithmeticException exception){System.out.println("发生了数学运算异常"+exception);//返回这些进行错误处理;
//        ProblemDetail:
//        ErrorResponse :return "炸了,哈哈...";}
}

在这里插入图片描述

package com.learn.webflux.filter;import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;/*** @author lfy* @Description* @create 2023-12-01 22:18*/
@Component
public class MyWebFilter implements WebFilter {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();System.out.println("请求处理放行到目标方法之前...");Mono<Void> filter = chain.filter(exchange); //放行//流一旦经过某个操作就会变成新流Mono<Void> voidMono = filter.doOnError(err -> {System.out.println("目标方法异常以后...");}) // 目标方法发生异常后做事.doFinally(signalType -> {System.out.println("目标方法执行以后...");});// 目标方法执行之后//上面执行不花时间。return voidMono; //看清楚返回的是谁 !!!}
}

在这里插入图片描述

package com.learn.webflux;import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import reactor.core.publisher.Mono;
import reactor.netty.http.server.HttpServer;import java.io.IOException;
import java.net.URI;/*** @author lfy* @Description* @create 2023-12-01 20:31*/
public class FluxMainApplication {public static void main(String[] args) throws IOException {//快速自己编写一个能处理请求的服务器//1、创建一个能处理Http请求的处理器。 参数:请求、响应; 返回值:Mono<Void>:代表处理完成的信号HttpHandler handler = (ServerHttpRequest request,ServerHttpResponse response)->{URI uri = request.getURI();System.out.println(Thread.currentThread()+"请求进来:"+uri);//编写请求处理的业务,给浏览器写一个内容 URL + "Hello~!"
//            response.getHeaders(); //获取响应头
//            response.getCookies(); //获取Cookie
//            response.getStatusCode(); //获取响应状态码;
//            response.bufferFactory(); //buffer工厂
//            response.writeWith() //把xxx写出去
//            response.setComplete(); //响应结束//数据的发布者:Mono<DataBuffer>、Flux<DataBuffer>//创建 响应数据的 DataBufferDataBufferFactory factory = response.bufferFactory();//数据BufferDataBuffer buffer = factory.wrap(new String(uri.toString() + " ==> Hello!").getBytes());// 需要一个 DataBuffer 的发布者return response.writeWith(Mono.just(buffer));};//2、启动一个服务器,监听8080端口,接受数据,拿到数据交给 HttpHandler 进行请求处理ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);//3、启动Netty服务器HttpServer.create().host("localhost").port(8080).handle(adapter) //用指定的处理器处理请求.bindNow(); //现在就绑定System.out.println("服务器启动完成....监听8080,接受请求");System.in.read();System.out.println("服务器停止....");}
}

在这里插入图片描述

package com.learn.webflux;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** @author lfy* @Description* @create 2023-12-01 20:52*///@EnableWebFlux // 注解: 开启WebFlux自定义; 禁用WebFLux的默认效果,完全自定义// WebFluxAutoConfiguration 的自动配置会生效//@EnableWebFlux //所有WebFluxAutoConfiguration 配置默认效果全部失效
@SpringBootApplication
public class WebFluxMainApplication {public static void main(String[] args) {SpringApplication.run(WebFluxMainApplication.class,args);}
}

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>哈哈</h1><div id="app" style="width: 500px;height: 300px;background-color: gainsboro"></div><script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>const http = axios.create({baseURL: 'http://localhost:8080/',timeout: 10000000,responseType: 'stream',onDownloadProgress: function (progressEvent) {// 处理原生进度事件// console.log("progressEvent->",progressEvent.event.currentTarget.responseText);document.getElementById("app").innerHTML =progressEvent.event.currentTarget.responseText// responseText 就是sse的完整数据},});http.get('/sse').then(function (response) {// 处理成功情况console.log(response);}).catch(function (error) {// 处理错误情况console.log(error);}).finally(function () {// 总是会执行});
</script></body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/43263.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++ STL】模拟实现 vector

标题&#xff1a;【C STL】模拟实现 vector 水墨不写bug &#xff08;图片来源于网络&#xff09; 正文开始&#xff1a; STL中的vector是一个动态数组&#xff0c;支持随机访问&#xff0c;可以根据需要来扩展数组空间。 本项目将实现vector的部分常用功能&#xff0c;以增强…

阿里云 Ubuntu 开启允许 ssh 密码方式登录

以前用的 centos&#xff0c;重置系统为 ubuntu 后在ssh 远程连接时遇到了点问题&#xff1a; 在阿里云控制台重置实例密码后无法使用密码进行 SSH 连接登录 原因&#xff1a;阿里云 Ubuntu 默认禁用密码登录方式 解决办法&#xff1a; 先使用其他用户登录到服务器 这里进来…

国产操作系统安装配置auditd审计工具 _ 统信 _ 麒麟 _ 中科方德

原文链接&#xff1a;国产操作系统安装配置auditd审计工具 | 统信 | 麒麟 | 中科方德 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇在国产桌面操作系统上部署auditd审计工具的文章。auditd是Linux审计系统的核心守护进程&#xff0c;用于记录系统安全相关的事件和…

Python自动化测试系列[v1.0.0][自动化测试报告]

BeautifulReport测试报告 获取BeautifulReport模块 BeautifulReport 源码Clone地址为 BeautifulReport &#xff0c;其中BeautifulReport.py和其template是我们需要的 BeautifulReport 如下代码是BeautifulReport.py的源码&#xff0c;其中几个注释的地方需要注意&#xff…

排序算法(算法篇)

算法之排序算法 排序算法 概念&#xff1a; 我们在的排序工作能在主存中完成的&#xff0c;我们就叫这种算法叫做内部排序不能在主存中完成而必须在磁盘或磁带上完成的排序算法叫做外部排序 冒泡排序 概念&#xff1a; 冒泡排序是一个很简单的排序算法&#xff0c;冒泡排…

【python】PyQt5可视化开发,鼠标键盘实现联动界面交互逻辑与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

一个简单的 Vue 组件例子

https://andi.cn/page/621509.html

YOLOv10改进 | Conv篇 | 利用DualConv二次创新C2f提出一种轻量化结构(轻量化创新)

一、本文介绍 本文给大家带来的改进机制是利用DualConv改进C2f提出一种轻量化的C2f&#xff0c;DualConv是一种创新的卷积网络结构&#xff0c;旨在构建轻量级的深度神经网络。它通过结合33和11的卷积核处理相同的输入特征映射通道&#xff0c;优化了信息处理和特征提取。Dual…

java 参数传递(尤其注意参数是对象的情况)

8大基本数据类型为 值传递 类和数组为 引用传递&#xff0c;传递的是地址 但是要注意虽然类是引用传递&#xff0c;但是要注意&#xff0c;调用方法是新开一个栈 因此如果进行p null或者 Person p new Person()等语句&#xff0c;要格外注意&#xff1a; 如果主函数再次输出…

基于场景的 Java Spring Boot 热门面试问题

随着 Spring Boot 继续主导 Java 生态系统&#xff0c;对熟悉这个强大框架的熟练开发人员的需求正在上升。如果您正在准备 Spring Boot 面试&#xff0c;尤其是作为一名经验丰富的专业人士&#xff0c;那么专注于测试您的实践知识和解决问题能力的基于场景的问题至关重要。本文…

音频demo:将PCM数据与alaw、mulaw、g711数据的相互转换

1、README 前言 (截图来源&#xff1a;https://blog.csdn.net/u014470361/article/details/88837776) 我的理解&#xff1a; 首先需要知道的是u-law/a-law是用于脉冲编码的压缩/解压缩算法。而G.711是指在8KHz采样率&#xff08;单声道&#xff09;中&#xff0c;使用的u-law或…

LLM- 注意力机制

一&#xff1a;什么是注意力机制&#xff0c;以及产生背景&#xff1f; &#xff08;1&#xff09;&#xff1a;RNN模型[RNN模型]的缺点&#xff1a;下图是例如RNN模型解决机器翻译的例子&#xff0c;从这个例子可以看到Encoder最后一个向量&#xff08;eos&#xff09;送给了…

B端全局导航:左侧还是顶部?不是随随便便,有依据在。

一、什么是全局导航 B端系统的全局导航是指在B端系统中的主要导航菜单&#xff0c;它通常位于系统的顶部或左侧&#xff0c;提供了系统中各个模块和功能的入口。全局导航菜单可以帮助用户快速找到和访问系统中的各个功能模块&#xff0c;提高系统的可用性和用户体验。 全局导航…

Kubernetes平台迁移

Kubernetes&&平台迁移 信息收集 信息收集

计算机的错误计算(二十五)

摘要 介绍&#xff08;不&#xff09;停机问题。给了一个算式&#xff0c;当计算机的输出为0时&#xff0c;一般需要提高计算精度继续计算&#xff0c;一直到获得非0值或有效数字。但是&#xff0c;由于事先不清楚算式的准确值是否为0或不为0&#xff0c;因此往往陷入两难境地…

【Java15】继承

继承是面向对象三大特征之一&#xff0c;也是软件代码服用的重要手段。 Java只允许单继承&#xff0c;即每个子类只有一个直接父类。 C中的多继承被Java舍弃了&#xff0c;原因是多继承一方面难以准确表述类之间的关系&#xff0c;另一方面很容易造成代码错误。总结起来就两个…

双系统ubuntu20.04扩容

windows端 打开磁盘管理器&#xff0c;选择需要的盘点击压缩卷 点击未分配的盘&#xff0c;新建简单卷&#xff0c;一致点击下一步即可&#xff0c;记住分配的大小容量 ubuntu端 lsblk 查看所有的磁盘&#xff0c;可以看到新增为nvme0n1p4、nvme1n1p2 win分配的格式为NTFS&a…

【Excel】 批量跳转图片

目录标题 1. CtrlA全选图片 → 右键 → 大小和属性2. 取消 锁定纵横比 → 跳转高度宽度 → 关闭窗口3. 最后一图拉到最后一单元格 → Alt吸附边框![](https://i-blog.csdnimg.cn/direct/d56ac1f41af54d54bb8c68339b558dd1.png)4. CtrlA全选图片 → 对齐 → 左对齐 → 纵向分布!…

全网最适合入门的面向对象编程教程:11 类和对象的Python实现-子类调用父类方法-模拟串口传感器和主机

全网最适合入门的面向对象编程教程&#xff1a;11 类和对象的 Python 实现-子类调用父类方法-模拟串口传感器和主机 摘要&#xff1a; 本节课&#xff0c;我们主要讲解了在 Python 类的继承中子类如何进行初始化、调用父类的属性和方法&#xff0c;同时讲解了模拟串口传感器和…

OpenHarmony 入门——单元测试UnitTest快速入门

引言 OpenHarmony 的单元测试&#xff08;UnitTest&#xff09;是一个关键的软件开发过程&#xff0c;它确保代码的各个部分能够按预期工作&#xff0c;OpenHarmony的测试框架中提供了很多种的单元测试&#xff0c;今天简单介绍下UnitTest 类型的TDD测试。 OpenHarmony 的TDD …