Spring Boot 4.0 新特性整合 MyBatis-Plus 完整教程

Spring Boot 4.0 新特性整合 MyBatis-Plus 完整教程

Spring Boot 4.0 整合 MyBatis-Plus 完整教程

注:Spring Boot 4.0 ,本教程基于 Spring Boot 4.0 的预览版和新特性预期进行构建。实际发布时可能会有调整。
Spring Cloud全栈实战:手撸企业级项目,从入门到架构师!

一、Spring Boot 4.0 新特性概述

Spring Cloud全栈实战:手撸企业级项目,从入门到架构师!

1.1 主要新特性

  • Java 21+ 支持:基于虚拟线程的响应式编程增强
  • GraalVM 原生镜像优化:更完善的 AOT 编译支持
  • 响应式编程增强:更好的响应式 MyBatis 支持
  • 模块化改进:更好的 Java Module 支持
  • AI/机器学习集成:内置 AI 功能支持

1.2 构建工具要求

  • JDK 21+
  • Maven 3.9+ 或 Gradle 8.5+
  • GraalVM 23.0+(可选,用于原生编译)

二、项目初始化

Spring Cloud全栈实战:手撸企业级项目,从入门到架构师!

2.1 使用 Spring Initializr

# 使用官方 Initializrcurl https://start.spring.io/starter.zip \ -d type=maven-project \ -d language=java \ -d bootVersion=4.0.0-M1 \ -d baseDir=spring-boot4-mybatisplus \ -d groupId=com.example \ -d artifactId=demo \ -d name=demo \ -d description=Demo+project+for+Spring+Boot+4.0+with+MyBatis-Plus \ -d packageName=com.example.demo \ -d packaging=jar \ -d javaVersion=21\ -d dependencies=web,data-jpa \ -o demo.zip 

2.2 手动创建 pom.xml

<?xml version="1.0" encoding="UTF-8"?><projectxmlns="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 https://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>4.0.0-M1</version><relativePath/></parent><groupId>com.example</groupId><artifactId>springboot4-mybatisplus</artifactId><version>1.0.0</version><name>springboot4-mybatisplus</name><description>Spring Boot 4.0 with MyBatis-Plus</description><properties><java.version>21</java.version><mybatis-plus.version>3.5.5</mybatis-plus.version><graalvm.version>23.0.0</graalvm.version></properties><dependencies><!-- Spring Boot 4.0 核心依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 响应式 Web 支持(新特性) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><!-- MyBatis-Plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus.version}</version></dependency><!-- 数据库驱动 --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><!-- 响应式 MySQL 驱动(新特性) --><dependency><groupId>io.asyncer</groupId><artifactId>r2dbc-mysql</artifactId><scope>runtime</scope></dependency><!-- 响应式 R2DBC --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-r2dbc</artifactId></dependency><!-- Lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- GraalVM 原生镜像支持(新特性) --><dependency><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId></dependency><!-- 测试依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 响应式测试支持 --><dependency><groupId>io.projectreactor</groupId><artifactId>reactor-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><!-- Spring Boot Maven 插件,支持 AOT --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><image><builder>paketobuildpacks/builder-jammy-tiny:latest</builder><env><BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE></env></image></configuration></plugin><!-- GraalVM Native Image 插件 --><plugin><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId><version>${graalvm.version}</version><extensions>true</extensions><executions><execution><id>build-native</id><goals><goal>compile-no-fork</goal></goals><phase>package</phase></execution></executions></plugin></plugins></build><!-- Spring Milestone 仓库 --><repositories><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></repository></repositories></project>

三、配置 MyBatis-Plus

Spring Cloud全栈实战:手撸企业级项目,从入门到架构师!

3.1 应用配置(application.yml)

# Spring Boot 4.0 新配置格式spring:application:name: springboot4-mybatisplus # 数据源配置(虚拟线程优化)datasource:driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/mybatis_plus_demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: root password:123456hikari:# 虚拟线程池配置(Spring Boot 4.0 新特性)thread-factory: org.springframework.boot.jdbc.VirtualThreadExecutor # 响应式数据源(新特性)r2dbc:url: r2dbc:mysql://localhost:3306/mybatis_plus_demo username: root password:123456# AOT 编译配置aot:enabled:truegenerate-code:true# GraalVM 原生镜像配置native:mode: native debug:true# MyBatis-Plus 配置mybatis-plus:configuration:# 自动映射行为auto-mapping-behavior: full # 驼峰命名转换map-underscore-to-camel-case:true# 日志实现log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config:db-config:# 逻辑删除字段名logic-delete-field: deleted # 逻辑删除值logic-delete-value:1# 逻辑未删除值logic-not-delete-value:0# 主键类型id-type: auto # 分页插件配置pagehelper:helper-dialect: mysql reasonable:truesupport-methods-arguments:true# 日志配置logging:level:com.example.demo.mapper: debug org.springframework.r2dbc: debug pattern:console:"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"# 虚拟线程配置(Spring Boot 4.0 新特性)server:tomcat:threads:# 使用虚拟线程use-virtual-threads:true# 响应式服务器配置netty:connection-timeout: 2m 

3.2 MyBatis-Plus 配置类

Spring Cloud全栈实战:手撸企业级项目,从入门到架构师!

packagecom.example.demo.config;importcom.baomidou.mybatisplus.annotation.DbType;importcom.baomidou.mybatisplus.core.handlers.MetaObjectHandler;importcom.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;importcom.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;importcom.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;importcom.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;importorg.apache.ibatis.reflection.MetaObject;importorg.mybatis.spring.annotation.MapperScan;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.transaction.annotation.EnableTransactionManagement;importjava.time.LocalDateTime;/** * MyBatis-Plus 配置类 * 使用 Spring Boot 4.0 新特性:虚拟线程兼容性配置 */@Configuration@EnableTransactionManagement@MapperScan("com.example.demo.mapper")publicclassMyBatisPlusConfig{/** * MyBatis-Plus 拦截器配置 * 支持分页、乐观锁、防全表更新与删除 */@BeanpublicMybatisPlusInterceptormybatisPlusInterceptor(){MybatisPlusInterceptor interceptor =newMybatisPlusInterceptor();// 分页插件 interceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.MYSQL));// 乐观锁插件 interceptor.addInnerInterceptor(newOptimisticLockerInnerInterceptor());// 防止全表更新与删除 interceptor.addInnerInterceptor(newBlockAttackInnerInterceptor());return interceptor;}/** * 元数据处理器 - 自动填充字段 */@BeanpublicMetaObjectHandlermetaObjectHandler(){returnnewMetaObjectHandler(){@OverridepublicvoidinsertFill(MetaObject metaObject){// 使用虚拟线程安全的日期时间this.strictInsertFill(metaObject,"createTime",LocalDateTime.class,LocalDateTime.now());this.strictInsertFill(metaObject,"updateTime",LocalDateTime.class,LocalDateTime.now());this.strictInsertFill(metaObject,"version",Integer.class,1);}@OverridepublicvoidupdateFill(MetaObject metaObject){this.strictUpdateFill(metaObject,"updateTime",LocalDateTime.class,LocalDateTime.now());}};}}

四、实体类与 Mapper

4.1 基础实体类

packagecom.example.demo.entity;importcom.baomidou.mybatisplus.annotation.*;importlombok.Data;importlombok.experimental.Accessors;importjava.io.Serializable;importjava.time.LocalDateTime;/** * 基础实体类 * 使用 Java 21 Record 模式(预览特性) */@Data@Accessors(chain =true)publicclassBaseEntityimplementsSerializable{/** * 主键ID - 使用虚拟线程安全的ID生成策略 */@TableId(type =IdType.ASSIGN_ID)privateLong id;/** * 创建时间 */@TableField(fill =FieldFill.INSERT)privateLocalDateTime createTime;/** * 更新时间 */@TableField(fill =FieldFill.INSERT_UPDATE)privateLocalDateTime updateTime;/** * 创建人 */@TableField(fill =FieldFill.INSERT)privateString createBy;/** * 更新人 */@TableField(fill =FieldFill.INSERT_UPDATE)privateString updateBy;/** * 乐观锁版本号 */@Version@TableField(fill =FieldFill.INSERT)privateInteger version;/** * 逻辑删除标志 */@TableLogic@TableField(fill =FieldFill.INSERT)privateInteger deleted;}

4.2 用户实体类

Spring Cloud全栈实战:手撸企业级项目,从入门到架构师!

packagecom.example.demo.entity;importcom.baomidou.mybatisplus.annotation.TableField;importcom.baomidou.mybatisplus.annotation.TableName;importlombok.Data;importlombok.EqualsAndHashCode;importlombok.experimental.Accessors;/** * 用户实体类 * 使用 Spring Boot 4.0 新特性:虚拟线程安全的序列化 */@Data@EqualsAndHashCode(callSuper =true)@Accessors(chain =true)@TableName("sys_user")publicclassUserextendsBaseEntity{/** * 用户名 */privateString username;/** * 密码 */privateString password;/** * 邮箱 */privateString email;/** * 手机号 */privateString phone;/** * 状态:0-禁用,1-启用 */privateInteger status;/** * 虚拟线程安全的额外字段 * 使用 transient 避免序列化问题 */@TableField(exist =false)privatetransientString virtualThreadInfo;}

4.3 Mapper 接口

packagecom.example.demo.mapper;importcom.baomidou.mybatisplus.core.mapper.BaseMapper;importcom.example.demo.entity.User;importorg.apache.ibatis.annotations.Mapper;importorg.apache.ibatis.annotations.Select;importorg.springframework.data.repository.query.Param;importorg.springframework.r2dbc.core.DatabaseClient;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;/** * 用户 Mapper * 支持响应式查询(Spring Boot 4.0 新特性) */@MapperpublicinterfaceUserMapperextendsBaseMapper<User>{/** * 传统阻塞式查询 */@Select("SELECT * FROM sys_user WHERE username = #{username}")UserselectByUsername(@Param("username")String username);/** * 响应式查询 - 返回单个结果 * 使用虚拟线程安全的方式 */@Select("SELECT * FROM sys_user WHERE id = #{id}")defaultMono<User>selectReactiveById(Long id,DatabaseClient databaseClient){return databaseClient.sql("SELECT * FROM sys_user WHERE id = :id").bind("id", id).map((row, metadata)->{User user =newUser(); user.setId(row.get("id",Long.class)); user.setUsername(row.get("username",String.class)); user.setEmail(row.get("email",String.class)); user.setStatus(row.get("status",Integer.class));return user;}).one();}/** * 响应式查询 - 返回多个结果 */@Select("SELECT * FROM sys_user WHERE status = #{status}")defaultFlux<User>selectReactiveByStatus(Integer status,DatabaseClient databaseClient){return databaseClient.sql("SELECT * FROM sys_user WHERE status = :status").bind("status", status).map((row, metadata)->{User user =newUser(); user.setId(row.get("id",Long.class)); user.setUsername(row.get("username",String.class)); user.setEmail(row.get("email",String.class)); user.setStatus(row.get("status",Integer.class));return user;}).all();}}

五、Service 层实现

Spring Cloud全栈实战:手撸企业级项目,从入门到架构师!

5.1 接口定义

packagecom.example.demo.service;importcom.baomidou.mybatisplus.extension.service.IService;importcom.example.demo.entity.User;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;importjava.util.concurrent.CompletableFuture;/** * 用户服务接口 * 支持响应式和虚拟线程 */publicinterfaceUserServiceextendsIService<User>{/** * 虚拟线程方式查询用户 * Spring Boot 4.0 新特性 */CompletableFuture<User>findUserByUsernameVirtualThread(String username);/** * 响应式查询用户 */Mono<User>findUserByIdReactive(Long id);/** * 响应式查询用户列表 */Flux<User>findUsersByStatusReactive(Integer status);/** * 使用结构化并发(Java 21 新特性) */UserfindUserWithStructuredConcurrency(Long id);}

5.2 服务实现

packagecom.example.demo.service.impl;importcom.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;importcom.baomidou.mybatisplus.extension.service.impl.ServiceImpl;importcom.example.demo.entity.User;importcom.example.demo.mapper.UserMapper;importcom.example.demo.service.UserService;importlombok.RequiredArgsConstructor;importlombok.extern.slf4j.Slf4j;importorg.springframework.r2dbc.core.DatabaseClient;importorg.springframework.stereotype.Service;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;importjava.util.concurrent.CompletableFuture;importjava.util.concurrent.StructuredTaskScope;importjava.util.concurrent.TimeUnit;/** * 用户服务实现 * 使用 Spring Boot 4.0 新特性:虚拟线程和响应式编程 */@Slf4j@Service@RequiredArgsConstructorpublicclassUserServiceImplextendsServiceImpl<UserMapper,User>implementsUserService{privatefinalUserMapper userMapper;privatefinalDatabaseClient databaseClient;@OverridepublicCompletableFuture<User>findUserByUsernameVirtualThread(String username){returnCompletableFuture.supplyAsync(()->{// 在虚拟线程中执行try{// 模拟耗时操作Thread.sleep(100);}catch(InterruptedException e){Thread.currentThread().interrupt();}return userMapper.selectOne(newLambdaQueryWrapper<User>().eq(User::getUsername, username));},Thread.ofVirtual().factory());}@OverridepublicMono<User>findUserByIdReactive(Long id){return userMapper.selectReactiveById(id, databaseClient).doOnNext(user -> log.info("Found user reactively: {}", user.getUsername()));}@OverridepublicFlux<User>findUsersByStatusReactive(Integer status){return userMapper.selectReactiveByStatus(status, databaseClient).doOnNext(user -> log.info("Streaming user: {}", user.getUsername()));}@OverridepublicUserfindUserWithStructuredConcurrency(Long id){// Java 21 结构化并发try(var scope =newStructuredTaskScope.ShutdownOnFailure()){var userFuture = scope.fork(()-> userMapper.selectById(id));var userDetailsFuture = scope.fork(()->// 模拟获取用户详情"User Details for ID: "+ id ); scope.join(); scope.throwIfFailed();User user = userFuture.get();if(user !=null){ user.setVirtualThreadInfo(userDetailsFuture.get());}return user;}catch(InterruptedException e){Thread.currentThread().interrupt();thrownewRuntimeException("Task interrupted", e);}catch(Exception e){thrownewRuntimeException("Failed to fetch user", e);}}/** * 批量保存用户 - 使用虚拟线程优化 */publicvoidsaveUsersWithVirtualThreads(List<User> users){try(var scope =newStructuredTaskScope.ShutdownOnFailure()){List<StructuredTaskScope.Subtask<User>> tasks = users.stream().map(user -> scope.fork(()->{// 每个用户保存操作在独立的虚拟线程中执行save(user);return user;})).toList(); scope.join(); scope.throwIfFailed();// 处理结果 tasks.forEach(task -> log.info("Saved user: {}", task.get().getUsername()));}catch(InterruptedException e){Thread.currentThread().interrupt();thrownewRuntimeException("Save interrupted", e);}catch(Exception e){thrownewRuntimeException("Failed to save users", e);}}}

六、Controller 层

Spring Cloud全栈实战:手撸企业级项目,从入门到架构师!

6.1 传统 REST Controller

packagecom.example.demo.controller;importcom.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;importcom.baomidou.mybatisplus.core.metadata.IPage;importcom.baomidou.mybatisplus.extension.plugins.pagination.Page;importcom.example.demo.entity.User;importcom.example.demo.service.UserService;importlombok.RequiredArgsConstructor;importlombok.extern.slf4j.Slf4j;importorg.springframework.http.ResponseEntity;importorg.springframework.web.bind.annotation.*;importjava.util.List;importjava.util.concurrent.CompletableFuture;importjava.util.concurrent.ExecutionException;/** * 用户控制器 * 支持虚拟线程和传统阻塞模式 */@Slf4j@RestController@RequestMapping("/api/v1/users")@RequiredArgsConstructorpublicclassUserController{privatefinalUserService userService;/** * 创建用户 */@PostMappingpublicResponseEntity<User>create(@RequestBodyUser user){boolean saved = userService.save(user);return saved ?ResponseEntity.ok(user):ResponseEntity.badRequest().build();}/** * 分页查询用户 * 使用虚拟线程优化 */@GetMapping("/page")publicResponseEntity<IPage<User>>page(@RequestParam(defaultValue ="1")Integer current,@RequestParam(defaultValue ="10")Integer size){Page<User> page =newPage<>(current, size);IPage<User> result = userService.page(page);returnResponseEntity.ok(result);}/** * 使用虚拟线程查询用户 * Spring Boot 4.0 新特性 */@GetMapping("/virtual/{username}")publicResponseEntity<User>findByUsernameVirtual(@PathVariableString username)throwsExecutionException,InterruptedException{CompletableFuture<User> future = userService.findUserByUsernameVirtualThread(username);returnResponseEntity.ok(future.get());}/** * 使用结构化并发查询用户 * Java 21 新特性 */@GetMapping("/structured/{id}")publicResponseEntity<User>findWithStructuredConcurrency(@PathVariableLong id){User user = userService.findUserWithStructuredConcurrency(id);returnResponseEntity.ok(user);}/** * 批量创建用户 - 使用虚拟线程 */@PostMapping("/batch/virtual")publicResponseEntity<Void>createBatchVirtual(@RequestBodyList<User> users){// 在新线程中执行批量操作Thread.ofVirtual().start(()->{ userService.saveUsersWithVirtualThreads(users);});returnResponseEntity.accepted().build();}}

6.2 响应式 Controller

packagecom.example.demo.controller;importcom.example.demo.entity.User;importcom.example.demo.service.UserService;importlombok.RequiredArgsConstructor;importlombok.extern.slf4j.Slf4j;importorg.springframework.http.MediaType;importorg.springframework.web.bind.annotation.*;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;importjava.time.Duration;/** * 响应式用户控制器 * Spring Boot 4.0 响应式增强 */@Slf4j@RestController@RequestMapping("/api/v2/users")@RequiredArgsConstructorpublicclassUserReactiveController{privatefinalUserService userService;/** * 响应式查询单个用户 */@GetMapping("/reactive/{id}")publicMono<ResponseEntity<User>>findByIdReactive(@PathVariableLong id){return userService.findUserByIdReactive(id).map(ResponseEntity::ok).defaultIfEmpty(ResponseEntity.notFound().build());}/** * 响应式查询用户列表 */@GetMapping(value ="/reactive/stream", produces =MediaType.TEXT_EVENT_STREAM_VALUE)publicFlux<User>streamByStatus(@RequestParamInteger status){return userService.findUsersByStatusReactive(status).delayElements(Duration.ofMillis(100))// 模拟流式处理.doOnNext(user -> log.info("Streaming user: {}", user.getUsername()));}/** * SSE 流式传输 */@GetMapping(value ="/sse", produces =MediaType.TEXT_EVENT_STREAM_VALUE)publicFlux<String>userEvents(){returnFlux.interval(Duration.ofSeconds(1)).map(sequence ->String.format("User Event %d at %s", sequence,java.time.LocalTime.now()));}}

七、响应式 Repository

Spring Cloud全栈实战:手撸企业级项目,从入门到架构师!

packagecom.example.demo.repository;importcom.example.demo.entity.User;importorg.springframework.data.r2dbc.repository.R2dbcRepository;importorg.springframework.data.r2dbc.repository.Query;importorg.springframework.stereotype.Repository;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;/** * 响应式用户仓库 * Spring Boot 4.0 响应式数据访问 */@RepositorypublicinterfaceUserReactiveRepositoryextendsR2dbcRepository<User,Long>{/** * 根据用户名查询 */@Query("SELECT * FROM sys_user WHERE username = :username")Mono<User>findByUsername(String username);/** * 根据状态查询 */@Query("SELECT * FROM sys_user WHERE status = :status")Flux<User>findByStatus(Integer status);/** * 分页查询 */@Query("SELECT * FROM sys_user ORDER BY create_time DESC LIMIT :limit OFFSET :offset")Flux<User>findAllWithPagination(int limit,int offset);}

八、全局异常处理

packagecom.example.demo.handler;importcom.baomidou.mybatisplus.core.exceptions.MybatisPlusException;importlombok.extern.slf4j.Slf4j;importorg.springframework.http.HttpStatus;importorg.springframework.http.ResponseEntity;importorg.springframework.web.bind.annotation.ExceptionHandler;importorg.springframework.web.bind.annotation.RestControllerAdvice;importorg.springframework.web.bind.support.WebExchangeBindException;importreactor.core.publisher.Mono;importjava.util.HashMap;importjava.util.Map;/** * 全局异常处理器 * 支持响应式异常处理 */@Slf4j@RestControllerAdvicepublicclassGlobalExceptionHandler{/** * 处理 MyBatis-Plus 异常 */@ExceptionHandler(MybatisPlusException.class)publicResponseEntity<Map<String,Object>>handleMybatisPlusException(MybatisPlusException e){ log.error("MyBatis-Plus Exception: {}", e.getMessage(), e);Map<String,Object> response =newHashMap<>(); response.put("code",HttpStatus.INTERNAL_SERVER_ERROR.value()); response.put("message","数据库操作失败"); response.put("detail", e.getMessage()); response.put("timestamp",System.currentTimeMillis());returnResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);}/** * 处理虚拟线程中断异常 */@ExceptionHandler(InterruptedException.class)publicResponseEntity<Map<String,Object>>handleInterruptedException(InterruptedException e){ log.warn("Virtual thread interrupted: {}", e.getMessage());Map<String,Object> response =newHashMap<>(); response.put("code",HttpStatus.SERVICE_UNAVAILABLE.value()); response.put("message","请求被中断"); response.put("timestamp",System.currentTimeMillis());Thread.currentThread().interrupt();// 恢复中断状态returnResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(response);}/** * 响应式异常处理 */@ExceptionHandler(WebExchangeBindException.class)publicMono<ResponseEntity<Map<String,Object>>>handleBindException(WebExchangeBindException e){returnMono.fromCallable(()->{Map<String,Object> response =newHashMap<>(); response.put("code",HttpStatus.BAD_REQUEST.value()); response.put("message","参数验证失败");Map<String,String> errors =newHashMap<>(); e.getFieldErrors().forEach(error -> errors.put(error.getField(), error.getDefaultMessage())); response.put("errors", errors); response.put("timestamp",System.currentTimeMillis());returnResponseEntity.badRequest().body(response);});}}

九、虚拟线程配置

Spring Cloud全栈实战:手撸企业级项目,从入门到架构师!

packagecom.example.demo.config;importorg.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;importorg.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.core.task.AsyncTaskExecutor;importorg.springframework.core.task.support.TaskExecutorAdapter;importorg.springframework.scheduling.annotation.EnableAsync;importjava.util.concurrent.Executors;/** * 虚拟线程配置 * Spring Boot 4.0 核心新特性 */@Configuration@EnableAsyncpublicclassVirtualThreadConfig{/** * 配置 Tomcat 使用虚拟线程 */@BeanpublicTomcatProtocolHandlerCustomizer<?>protocolHandlerVirtualThreadExecutorCustomizer(){return protocolHandler -> protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());}/** * 配置 Spring 异步任务执行器使用虚拟线程 */@Bean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)publicAsyncTaskExecutorasyncTaskExecutor(){returnnewTaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor());}/** * 配置虚拟线程池用于数据库操作 */@Beanpublicjava.util.concurrent.ExecutorServicedatabaseExecutor(){returnExecutors.newThreadPerTaskExecutor(Thread.ofVirtual().name("db-virtual-thread-",0).factory());}}

十、AOT 和原生镜像支持

10.1 创建 AOT 处理类

packagecom.example.demo.aot;importorg.springframework.aot.hint.RuntimeHints;importorg.springframework.aot.hint.RuntimeHintsRegistrar;importorg.springframework.context.annotation.Configuration;importorg.springframework.context.annotation.ImportRuntimeHints;/** * AOT 运行时提示注册 * Spring Boot 4.0 原生镜像支持 */@Configuration@ImportRuntimeHints(AotRuntimeHints.MybatisPlusRuntimeHints.class)publicclassAotRuntimeHints{staticclassMybatisPlusRuntimeHintsimplementsRuntimeHintsRegistrar{@OverridepublicvoidregisterHints(RuntimeHints hints,ClassLoader classLoader){// 注册反射 hints.reflection().registerType(com.baomidou.mybatisplus.core.mapper.BaseMapper.class, hint -> hint.withMembers(org.springframework.aot.hint.MemberCategory.INVOKE_PUBLIC_METHODS ));// 注册资源 hints.resources().registerPattern("mapper/*.xml"); hints.resources().registerPattern("mybatis-config.xml");// 注册序列化 hints.serialization().registerType(com.example.demo.entity.User.class);// 注册代理 hints.proxies().registerJdkProxy(org.apache.ibatis.binding.MapperProxy.class);}}}

10.2 native-image.properties

Args = --enable-url-protocols=http,https \ -H:+ReportExceptionStackTraces \ -H:+ReportUnsupportedElementsAtRuntime \ --initialize-at-build-time=com.mysql.cj \ --initialize-at-run-time=io.netty.handler.codec.http.HttpObjectEncoder \ -H:IncludeResourceBundles=com.mysql.cj.LocalizedErrorMessages 

十一、测试类

Spring Cloud全栈实战:手撸企业级项目,从入门到架构师!

packagecom.example.demo;importcom.example.demo.entity.User;importcom.example.demo.service.UserService;importlombok.extern.slf4j.Slf4j;importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importreactor.core.publisher.Mono;importreactor.test.StepVerifier;importjava.util.concurrent.CompletableFuture;importjava.util.concurrent.ExecutionException;importjava.util.concurrent.TimeUnit;importjava.util.concurrent.TimeoutException;importstaticorg.assertj.core.api.Assertions.assertThat;/** * 集成测试 * 测试虚拟线程和响应式功能 */@Slf4j@SpringBootTestclassSpringBoot4MybatisPlusApplicationTests{@AutowiredprivateUserService userService;/** * 测试虚拟线程查询 */@TestvoidtestVirtualThreadQuery()throwsExecutionException,InterruptedException,TimeoutException{// 准备测试数据User user =newUser().setUsername("test_virtual").setEmail("[email protected]").setStatus(1); userService.save(user);// 使用虚拟线程查询CompletableFuture<User> future = userService.findUserByUsernameVirtualThread("test_virtual");User result = future.get(5,TimeUnit.SECONDS);assertThat(result).isNotNull();assertThat(result.getUsername()).isEqualTo("test_virtual"); log.info("Virtual thread test passed, user ID: {}", result.getId());}/** * 测试响应式查询 */@TestvoidtestReactiveQuery(){// 准备测试数据User user =newUser().setUsername("test_reactive").setEmail("[email protected]").setStatus(1); userService.save(user);// 使用响应式查询Mono<User> userMono = userService.findUserByIdReactive(user.getId());StepVerifier.create(userMono).assertNext(foundUser ->{assertThat(foundUser).isNotNull();assertThat(foundUser.getUsername()).isEqualTo("test_reactive");}).verifyComplete(); log.info("Reactive query test passed");}/** * 测试结构化并发 */@TestvoidtestStructuredConcurrency(){// 准备测试数据User user =newUser().setUsername("test_structured").setEmail("[email protected]").setStatus(1); userService.save(user);// 使用结构化并发查询User result = userService.findUserWithStructuredConcurrency(user.getId());assertThat(result).isNotNull();assertThat(result.getUsername()).isEqualTo("test_structured");assertThat(result.getVirtualThreadInfo()).contains("User Details"); log.info("Structured concurrency test passed");}/** * 测试批量虚拟线程操作 */@TestvoidtestBatchVirtualThreads(){// 准备测试数据List<User> users =newArrayList<>();for(int i =0; i <10; i++){ users.add(newUser().setUsername("batch_user_"+ i).setEmail("batch"+ i +"@example.com").setStatus(1));}// 使用虚拟线程批量保存 userService.saveUsersWithVirtualThreads(users);// 验证保存结果List<User> savedUsers = userService.list(newLambdaQueryWrapper<User>().likeRight(User::getUsername,"batch_user_"));assertThat(savedUsers).hasSize(10); log.info("Batch virtual threads test passed, saved {} users", savedUsers.size());}}

十二、性能监控

Spring Cloud全栈实战:手撸企业级项目,从入门到架构师!

packagecom.example.demo.monitor;importio.micrometer.core.instrument.MeterRegistry;importlombok.RequiredArgsConstructor;importlombok.extern.slf4j.Slf4j;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.springframework.stereotype.Component;importorg.springframework.util.StopWatch;importjava.util.concurrent.atomic.AtomicInteger;/** * 虚拟线程性能监控 * Spring Boot 4.0 监控增强 */@Slf4j@Aspect@Component@RequiredArgsConstructorpublicclassVirtualThreadMonitor{privatefinalMeterRegistry meterRegistry;privatefinalAtomicInteger activeVirtualThreads =newAtomicInteger(0);/** * 监控虚拟线程使用 */@Around("@annotation(com.example.demo.annotation.VirtualThreadMonitor)")publicObjectmonitorVirtualThread(ProceedingJoinPoint joinPoint)throwsThrowable{StopWatch stopWatch =newStopWatch();int currentThreads = activeVirtualThreads.incrementAndGet();try{ stopWatch.start();Object result = joinPoint.proceed(); stopWatch.stop();// 记录指标 meterRegistry.timer("virtual.thread.execution.time").record(stopWatch.getTotalTimeNanos(),java.util.concurrent.TimeUnit.NANOSECONDS); meterRegistry.gauge("virtual.thread.active.count", activeVirtualThreads); log.info("Virtual thread executed: method={}, time={}ms, activeThreads={}", joinPoint.getSignature().getName(), stopWatch.getTotalTimeMillis(), currentThreads);return result;}finally{ activeVirtualThreads.decrementAndGet();}}}

十三、启动类

Spring Cloud全栈实战:手撸企业级项目,从入门到架构师!

packagecom.example.demo;importlombok.extern.slf4j.Slf4j;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.boot.context.event.ApplicationReadyEvent;importorg.springframework.context.event.EventListener;@Slf4j@SpringBootApplicationpublicclassSpringBoot4MybatisPlusApplication{publicstaticvoidmain(String[] args){// 启用 AOT 优化System.setProperty("spring.aot.enabled","true");SpringApplication.run(SpringBoot4MybatisPlusApplication.class, args);}@EventListener(ApplicationReadyEvent.class)publicvoidonApplicationReady(){ log.info("========================================="); log.info("Spring Boot 4.0 with MyBatis-Plus Started"); log.info("Java Version: {}",System.getProperty("java.version")); log.info("Virtual Threads Available: {}",Thread.ofVirtual()!=null?"Yes":"No"); log.info("Available Processors: {}",Runtime.getRuntime().availableProcessors()); log.info("=========================================");}}

十四、部署和优化

Spring Cloud全栈实战:手撸企业级项目,从入门到架构师!

14.1 Dockerfile(支持原生镜像)

# 构建阶段 FROM ghcr.io/graalvm/native-image:java21 AS builder WORKDIR /app COPY target/*.jar app.jar RUN native-image -jar app.jar --no-fallback -H:Name=app-native # 运行阶段 FROM alpine:latest RUN apk add --no-cache libstdc++ WORKDIR /app COPY --from=builder /app/app-native /app/app EXPOSE 8080 ENTRYPOINT ["/app/app"] 

14.2 Docker Compose

version:'3.8'services:app:build: . ports:-"8080:8080"environment:- SPRING_PROFILES_ACTIVE=prod - JAVA_OPTS=-XX:+UseZGC -Xmx512m depends_on:- mysql deploy:resources:limits:memory: 512M mysql:image: mysql:8.0environment:MYSQL_ROOT_PASSWORD:123456MYSQL_DATABASE: mybatis_plus_demo ports:-"3306:3306"volumes:- mysql_data:/var/lib/mysql command:---default-authentication-plugin=mysql_native_password ---character-set-server=utf8mb4 ---collation-server=utf8mb4_unicode_ci volumes:mysql_data:

十五、总结

Spring Cloud全栈实战:手撸企业级项目,从入门到架构师!

15.1 关键特性使用

  1. 虚拟线程:通过 Thread.ofVirtual() 和虚拟线程池优化并发性能
  2. 响应式编程:结合 MyBatis-Plus 和 R2DBC 实现非阻塞数据访问
  3. 结构化并发:使用 Java 21 的结构化并发 API
  4. AOT 编译:支持 GraalVM 原生镜像,提升启动速度
  5. 模块化:更好的 Java Module 支持

15.2 性能优化建议

  1. 对于 I/O 密集型操作,使用虚拟线程
  2. 对于高并发场景,使用响应式编程
  3. 使用 GraalVM 原生镜像减少内存占用和启动时间
  4. 合理配置连接池和线程池参数

15.3 整合事项

  1. Spring Boot 4.0 目前是预览版,API 可能会有变化
  2. 虚拟线程对阻塞操作敏感,避免在虚拟线程中执行长时间 CPU 操作
  3. 原生镜像编译需要处理反射和动态代理的注册
  4. 生产环境建议充分测试响应式和虚拟线程的稳定性

我的这个教程展示了如何利用 Spring Boot 4.0 的新特性(虚拟线程、响应式编程、AOT 编译等)来整合 MyBatis-Plus,构建高性能的现代 Java 应用程序。

Read more

Flash Table实测:JAI赋能低代码开发,重塑企业级应用构建范式

Flash Table实测:JAI赋能低代码开发,重塑企业级应用构建范式

目录 * 🔍 引言 * 1.1 什么是Flash Table * 1.2 低代码平台的进化与FlashTable的革新 * ✨FlashTable背景:为什么需要新一代低代码平台? * 2.1 传统开发的痛点 * 2.2 低代码平台的局限 * 2.3 FlashTable的差异化定位 * 💻 FlashTable安装:Docker部署&Jar包部署 * 3.1 基础环境要求 * 3.2 Docker部署(推荐方案) * 3.3 Jar包部署(无Docker环境) * 3.4 常见问题 * 📚FlashTable功能深度评测:从案例看真实能力 * 4.1 数据孤岛?FlashTable 自动化匹配字段 * 4.2 FlashTable复杂表单的开发挑战 * 4.3

By Ne0inhk

零成本搭建飞书机器人:手把手教你用Webhook实现高效消息推送

1. 为什么你需要一个飞书机器人? 在日常工作中,我们经常需要处理各种通知需求。比如系统报警、任务提醒、审批结果通知等等。传统的解决方案包括短信、邮件或者第三方推送平台,但这些方式要么成本高,要么实时性差。飞书机器人提供了一种零成本、高效率的替代方案。 我去年负责的一个ERP系统升级项目就遇到了这个问题。当时我们需要在关键业务流程节点给不同部门的同事发送实时通知。如果使用短信,按照每天200条计算,一个月就要花费上千元。后来我们改用飞书机器人,不仅完全免费,还能实现更丰富的消息格式和精准的@提醒功能。 飞书机器人本质上是一个自动化程序,它通过Webhook技术接收外部系统的消息,并转发到指定的飞书群聊中。这种机制特别适合企业内部系统与飞书之间的集成,比如: * 运维报警通知 * 审批流程提醒 * 业务系统状态更新 * 日报/周报自动推送 * 数据监控预警 2. 5分钟快速创建你的第一个机器人 创建飞书机器人非常简单,不需要任何开发经验。下面我以电脑端操作为例,手把手带你完成整个过程。 首先打开飞书客户端,进入你想要添加机器人的群聊。点击右上角的"..."菜单,

By Ne0inhk
WebGIS + 无人机 + AI:下一代智能巡检系统?

WebGIS + 无人机 + AI:下一代智能巡检系统?

WebGIS 遇上无人机,再叠加 AI 能力,巡检不再只是“看画面”,而是变成“智能决策系统”。 一、为什么 WebGIS + 无人机 + AI 是趋势? 在传统巡检场景中: * 电力巡检 → 人工拍照 * 工地巡查 → 人工记录 * 农业监测 → 靠经验判断 * 安防巡逻 → 事后回放 问题: * 数据无法实时分析 * 缺乏空间关联 * 没有智能预警能力 * 无法形成可视化决策系统 而结合: * WebGIS(三维可视化) * 无人机(数据采集) * AI(智能识别与分析) 我们可以构建: 一个真正的“空天地一体化智能巡检系统” 二、整体技术架构设计 1、系统分层架构 ┌──────────────────────────────┐ │ 前端可视化层 │ │ Cesium + Three.js + WebGL │ └──────────────┬───────────────┘ │ ┌──────────────▼───────────────┐ │ 业务中台层 │ │ AI推理

By Ne0inhk
WorkBuddy 使用指南:从零开始配置 QQ 机器人,解锁桌面智能体新玩法

WorkBuddy 使用指南:从零开始配置 QQ 机器人,解锁桌面智能体新玩法

文章目录 * 前言 * 下载 WorkBuddy * 认识 WorkBuddy * 插件类型 * 配置 QQ 机器人 * 登录 QQ 开放平台并注册激活账号 * 配置超级管理员、主体及认证信息 * 创建 QQ 机器人 * 获取 AppID 和 AppSecret * 从 Claw 中获取 Webhook * 在 QQ 开发平台配置回调地址 * 开始使用 WorkBuddy Claw * 总结 前言 在大家还在沉迷于如何搭建 OpenClaw 的时候,腾讯竟然悄悄公测了 WorkBuddy。这是一款面向全角色的桌面智能体,下达指令即可自动生成文档、表格、图表及 PPT 等可视化成果,能够自主规划并交付多模态复杂任务结果,支持多 Agents 并行工作,极致提效,

By Ne0inhk