2026/4/18 9:33:16
网站建设
项目流程
青海省住房和城乡建设厅的官方网站,国内做视频的网站有哪些,互联网网站基础,网站建设的一般步骤包括哪些Spring Boot 4.0 MyBatis-Plus 实战响应式编程的能力实战
Spring Cloud全栈实战#xff1a;手撸企业级项目#xff0c;从入门到架构师#xff01;
目前 MyBatis-Plus 官方还不完全支持响应式编程#xff0c;但我们可以结合 R2DBC 和 MyBatis-Plus 的部分特性来实现。这里…Spring Boot 4.0 MyBatis-Plus 实战响应式编程的能力实战Spring Cloud全栈实战手撸企业级项目从入门到架构师目前 MyBatis-Plus 官方还不完全支持响应式编程但我们可以结合 R2DBC 和 MyBatis-Plus 的部分特性来实现。这里提供两种方案方案一使用 MyBatis-Plus 增强 R2DBC (推荐)Spring Cloud全栈实战手撸企业级项目从入门到架构师1. 项目依赖dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-webflux/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-r2dbc/artifactId/dependencydependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.5.3.1/version!-- 注意只使用其工具类不启用SQL执行 --/dependency!-- 数据库驱动 --dependencygroupIdio.asyncer/groupIdartifactIdr2dbc-mysql/artifactIdversion1.0.2/version/dependency!-- 或 PostgreSQL --!-- dependency groupIdorg.postgresql/groupId artifactIdr2dbc-postgresql/artifactId scoperuntime/scope /dependency --2. 配置类importcom.baomidou.mybatisplus.annotation.DbType;importcom.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;importcom.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.data.r2dbc.config.EnableR2dbcAuditing;ConfigurationEnableR2dbcAuditingpublicclassR2dbcMybatisConfig{/** * 只使用 MyBatis-Plus 的分页插件 */BeanpublicMybatisPlusInterceptormybatisPlusInterceptor(){MybatisPlusInterceptorinterceptornewMybatisPlusInterceptor();interceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.MYSQL));returninterceptor;}}3. 实体类 (使用 MyBatis-Plus 注解)Spring Cloud全栈实战手撸企业级项目从入门到架构师importcom.baomidou.mybatisplus.annotation.*;importlombok.Data;importorg.springframework.data.annotation.CreatedDate;importorg.springframework.data.annotation.LastModifiedDate;importorg.springframework.data.relational.core.mapping.Table;importjava.time.LocalDateTime;DataTable(users)publicclassUser{TableId(typeIdType.AUTO)privateLongid;TableField(username)privateStringusername;TableField(email)privateStringemail;TableField(password)privateStringpassword;TableField(age)privateIntegerage;TableLogicTableField(deleted)privateIntegerdeleted0;TableField(valueversion,fillFieldFill.INSERT)VersionprivateIntegerversion1;CreatedDateTableField(create_time)privateLocalDateTimecreateTime;LastModifiedDateTableField(update_time)privateLocalDateTimeupdateTime;// 响应式编程友好的构造方法publicstaticMonoUserof(Stringusername,Stringemail){UserusernewUser();user.setUsername(username);user.setEmail(email);returnMono.just(user);}}4. Repository 接口 (R2DBC)importorg.springframework.data.r2dbc.repository.R2dbcRepository;importorg.springframework.data.r2dbc.repository.Query;importorg.springframework.stereotype.Repository;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;RepositorypublicinterfaceUserR2dbcRepositoryextendsR2dbcRepositoryUser,Long{MonoUserfindByUsername(Stringusername);MonoUserfindByEmail(Stringemail);FluxUserfindByAgeGreaterThan(Integerage);Query(SELECT * FROM users WHERE username LIKE :keyword OR email LIKE :keyword)FluxUsersearchUsers(Stringkeyword);Query(UPDATE users SET age :age WHERE id :id)MonoIntegerupdateAgeById(Longid,Integerage);}5. Service 层 (结合 MyBatis-Plus 工具)importcom.baomidou.mybatisplus.core.conditions.query.QueryWrapper;importcom.baomidou.mybatisplus.extension.plugins.pagination.Page;importlombok.RequiredArgsConstructor;importorg.springframework.data.domain.Pageable;importorg.springframework.r2dbc.core.DatabaseClient;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;importreactor.core.scheduler.Schedulers;importjava.time.Duration;importjava.util.Map;ServiceRequiredArgsConstructorpublicclassReactiveUserService{privatefinalUserR2dbcRepositoryuserRepository;privatefinalDatabaseClientdatabaseClient;publicMonoUsercreateUser(Useruser){returnuserRepository.save(user);}publicMonoUsergetUserById(Longid){returnuserRepository.findById(id).switchIfEmpty(Mono.error(newRuntimeException(User not found)));}publicFluxUsergetAllUsers(){returnuserRepository.findAll().delayElements(Duration.ofMillis(100))// 模拟流处理.subscribeOn(Schedulers.boundedElastic());}publicMonoUserupdateUser(Longid,Useruser){returnuserRepository.findById(id).flatMap(existing-{existing.setUsername(user.getUsername());existing.setEmail(user.getEmail());existing.setAge(user.getAge());returnuserRepository.save(existing);});}TransactionalpublicMonoVoiddeleteUser(Longid){returnuserRepository.deleteById(id).then(Mono.fromRunnable(()-System.out.println(User deleted: id)));}/** * 使用 MyBatis-Plus 的 QueryWrapper 构建查询条件 * 然后转换为 R2DBC 查询 */publicFluxUserqueryUsers(MapString,Objectparams){// 使用 MyBatis-Plus 的 QueryWrapper 构建条件QueryWrapperUserqueryWrappernewQueryWrapper();if(params.containsKey(username)){queryWrapper.like(username,params.get(username));}if(params.containsKey(email)){queryWrapper.like(email,params.get(email));}if(params.containsKey(minAge)){queryWrapper.ge(age,params.get(minAge));}if(params.containsKey(maxAge)){queryWrapper.le(age,params.get(maxAge));}queryWrapper.orderByDesc(create_time);// 将 QueryWrapper 转换为 SQLStringsqlbuildQueryWrapperSql(queryWrapper);// 执行响应式查询returndatabaseClient.sql(sql).fetch().all().map(row-{UserusernewUser();user.setId((Long)row.get(id));user.setUsername((String)row.get(username));user.setEmail((String)row.get(email));user.setAge((Integer)row.get(age));returnuser;});}/** * 响应式分页查询 */publicMonoPageUsergetUsersPage(Pageablepageable){// 使用 MyBatis-Plus 的 Page 对象PageUsermybatisPagenewPage(pageable.getPageNumber(),pageable.getPageSize());// 计算总数MonoLongcountMonodatabaseClient.sql(SELECT COUNT(*) FROM users).map(row-row.get(0,Long.class)).one();// 查询数据FluxUserusersFluxdatabaseClient.sql(SELECT * FROM users ORDER BY create_time DESC LIMIT :limit OFFSET :offset).bind(limit,pageable.getPageSize()).bind(offset,pageable.getOffset()).fetch().all().map(this::mapRowToUser);returnMono.zip(countMono,usersFlux.collectList()).map(tuple-{mybatisPage.setTotal(tuple.getT1());mybatisPage.setRecords(tuple.getT2());returnmybatisPage;});}privateStringbuildQueryWrapperSql(QueryWrapperUserqueryWrapper){// 简化示例实际需要更复杂的转换returnSELECT * FROM users WHERE queryWrapper.getTargetSql();}privateUsermapRowToUser(MapString,Objectrow){UserusernewUser();user.setId((Long)row.get(id));user.setUsername((String)row.get(username));user.setEmail((String)row.get(email));user.setAge((Integer)row.get(age));returnuser;}/** * 批量保存 */publicFluxUsersaveAll(FluxUserusers){returnuserRepository.saveAll(users).onErrorContinue((error,user)-System.err.println(Error saving user: error.getMessage()));}/** * 流式查询 */publicFluxUserstreamUsers(){returndatabaseClient.sql(SELECT * FROM users).fetch().all().delayElements(Duration.ofMillis(50))// 控制流速度.map(this::mapRowToUser);}}6. Controller 层Spring Cloud全栈实战手撸企业级项目从入门到架构师importcom.baomidou.mybatisplus.extension.plugins.pagination.Page;importlombok.RequiredArgsConstructor;importorg.springframework.data.domain.PageRequest;importorg.springframework.http.HttpStatus;importorg.springframework.http.MediaType;importorg.springframework.http.ResponseEntity;importorg.springframework.web.bind.annotation.*;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;importjavax.validation.Valid;importjava.time.Duration;importjava.util.Map;RestControllerRequestMapping(/api/reactive/users)RequiredArgsConstructorpublicclassReactiveUserController{privatefinalReactiveUserServiceuserService;PostMappingResponseStatus(HttpStatus.CREATED)publicMonoResponseEntityUsercreate(ValidRequestBodyUseruser){returnuserService.createUser(user).map(saved-ResponseEntity.status(HttpStatus.CREATED).body(saved)).onErrorResume(e-Mono.just(ResponseEntity.badRequest().build()));}GetMapping(/{id})publicMonoResponseEntityUsergetById(PathVariableLongid){returnuserService.getUserById(id).map(ResponseEntity::ok).defaultIfEmpty(ResponseEntity.notFound().build());}GetMappingpublicFluxUsergetAll(){returnuserService.getAllUsers();}GetMapping(/search)publicFluxUsersearch(RequestParamMapString,Objectparams){returnuserService.queryUsers(params);}GetMapping(/page)publicMonoPageUsergetPage(RequestParam(defaultValue0)intpage,RequestParam(defaultValue10)intsize){PageRequestpageRequestPageRequest.of(page,size);returnuserService.getUsersPage(pageRequest);}PutMapping(/{id})publicMonoResponseEntityUserupdate(PathVariableLongid,ValidRequestBodyUseruser){returnuserService.updateUser(id,user).map(ResponseEntity::ok).defaultIfEmpty(ResponseEntity.notFound().build());}DeleteMapping(/{id})publicMonoResponseEntityVoiddelete(PathVariableLongid){returnuserService.deleteUser(id).then(Mono.just(ResponseEntity.noContent().Voidbuild())).defaultIfEmpty(ResponseEntity.notFound().build());}/** * Server-Sent Events (SSE) 流式接口 */GetMapping(value/stream,producesMediaType.TEXT_EVENT_STREAM_VALUE)publicFluxUserstream(){returnuserService.streamUsers();}/** * WebFlux WebSocket 支持 */MessageMapping(users.chat)publicFluxUserMessageuserChat(FluxUserMessagemessages){returnmessages.doOnNext(message-System.out.println(Received: message.getContent())).map(message-newUserMessage(Server: message.getContent())).delayElements(Duration.ofSeconds(1));}/** * 批量操作 */PostMapping(/batch)publicFluxUserbatchCreate(RequestBodyFluxUserusers){returnuserService.saveAll(users);}}7. 自定义响应式 RepositorySpring Cloud全栈实战手撸企业级项目从入门到架构师importcom.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;importorg.springframework.data.r2dbc.repository.R2dbcRepository;importorg.springframework.data.repository.reactive.ReactiveCrudRepository;importorg.springframework.r2dbc.core.DatabaseClient;importorg.springframework.stereotype.Repository;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;RepositorypublicinterfaceCustomReactiveRepository{/** * 使用 MyBatis-Plus 的 Lambda 查询 */FluxUserfindUsersByCondition(LambdaQueryWrapperUserwrapper);/** * 响应式分页查询 */MonoPageUserfindPage(PageUserpage,LambdaQueryWrapperUserwrapper);}8. 响应式事务配置importorg.springframework.context.annotation.Configuration;importorg.springframework.transaction.ReactiveTransactionManager;importorg.springframework.transaction.reactive.TransactionalOperator;ConfigurationpublicclassReactiveTransactionConfig{BeanpublicTransactionalOperatortransactionalOperator(ReactiveTransactionManagertransactionManager){returnTransactionalOperator.create(transactionManager);}}方案二使用 MyBatis-Plus 响应式扩展 (第三方)有一些第三方项目正在尝试为 MyBatis-Plus 添加响应式支持Spring Cloud全栈实战手撸企业级项目从入门到架构师1. 添加依赖!-- 第三方响应式扩展 --dependencygroupIdcom.github.yulichang/groupIdartifactIdmybatis-plus-join/artifactIdversion1.4.6/version/dependency2. 自定义响应式 Mapperimportorg.apache.ibatis.annotations.SelectProvider;importorg.springframework.data.repository.reactive.ReactiveCrudRepository;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;publicinterfaceReactiveBaseMapperT{MonoIntegerinsertReactive(Tentity);MonoIntegerupdateByIdReactive(Tentity);MonoTselectByIdReactive(Serializableid);FluxTselectListReactive(WrapperTqueryWrapper);MonoIntegerdeleteByIdReactive(Serializableid);}重要提示MyBatis-Plus 官方还不完全支持响应式上述方案是结合 R2DBC 和 MyBatis-Plus 的工具类真正的响应式编程需要使用 R2DBC 或 MongoDB Reactive如果需要复杂 SQL 查询可以使用 DatabaseClient 或 R2DBC Entity Callbacks生产环境建议使用成熟的响应式数据库驱动完整配置 application.ymlSpring Cloud全栈实战手撸企业级项目从入门到架构师spring:r2dbc:url:r2dbc:mysql://localhost:3306/reactive_dbusername:rootpassword:passwordpool:initial-size:5max-size:20max-idle-time:30mwebflux:base-path:/apistatic-path-pattern:/static/**codec:max-in-memory-size:10MBlogging:level:org.springframework.r2dbc:DEBUGio.r2dbc:DEBUG这种架构结合了 MyBatis-Plus 的便利性和 R2DBC 的响应式能力适合需要复杂查询的场景。