新闻详情

新闻详情

首页 / 资讯中心 / 详情

SpringBoot Test实战:从单元测试到集成测试的完整指南

发布时间:2026/9/9 19:54:50来源:尧图网络
SpringBoot Test实战:从单元测试到集成测试的完整指南
SpringBoot Test一直是个神奇的话题你在社区里搜一下能看到两类极端的帖子一类是测试覆盖率达到90%的团队怎么搭建测试体系另一类是救命SpringBootTest又启动失败了。这两类帖子之间隔着的是大量只有真正踩过坑才懂的经验。这篇文章就是想把SpringBoot Test这个主题彻底讲透。从最基础的测试分层思路到核心注解的实际用法和版本差异再到一套可以直接抄作业的完整实操流程以及我整理的高频问题排查手册。不管是刚接触SpringBoot测试的新手还是想把自己的测试代码写得更规范的老手这篇文章都能给你一些参考。1. 测试到底该怎么分层为什么别一上来就SpringBootTest1.1 先想清楚一个问题测试是为了什么很多人在SpringBoot项目里写测试心态是领导要求覆盖率于是把测试当成任务应付每个Service方法都写一个SpringBootTest包起来的测试类跑一次要十几秒改个测试数据依赖一堆前置条件。这种测试写多了不但没有增强信心反而成了CI里的定时炸弹动不动就红红了你还没时间去修最后干脆把测试跳过。我在实际项目中得到的体会是测试不是为了覆盖率数字而是为了让你在改代码的时候敢动手。重构一个方法、升级一个依赖、改一个SQL跑一遍相关测试三分钟内告诉你有没有改挂这就是测试最大的价值。所以测试的分层和选型第一原则应该是快和稳。1.2 测试分层的核心思路单元测试、切片测试、集成测试SpringBoot官方文档其实已经把测试分层的思路讲得很清楚了就是三个层次单元测试只测一个类或一个方法不启动Spring容器其他依赖全部Mock掉。执行速度毫秒级。切片测试Slice Test启动Spring容器的一小部分比如只加载Controller层或者只加载Repository层用WebMvcTest、DataJpaTest这类注解搞定。启动速度几秒级。集成测试完整启动Spring容器用真实数据库、Redis、消息队列等外部依赖。执行速度从几秒到几十秒不等但最接近真实运行环境。这三层测试的使用比例理论上应该是金字塔形单元测试最多集成测试最少。但在真实项目里我发现很多团队的测试比例是倒过来的这通常是因为大家太依赖SpringBootTest把单元测试当集成测试来写时间全耗在启动容器上了。1.3 为什么SpringBoot单元测试最佳实战成了高频搜索词从最近的热搜词来看SpringBoot 单元测试最佳实战和springboot test的搜索量一直不低。这背后反映出两个问题一是测试确实是SpringBoot项目的硬需求几乎每个项目都要写二是很多人写出来的测试不够实战要么测试方法命名不清不楚要么断言写得跟没写一样要么测试之间互相依赖跑一个全挂。真正好的单元测试应该具备三个特征独立、快速、有明确的断言目标。每个测试方法只测一个行为不依赖测试执行顺序不依赖外部环境断言的是结果对不对而不是代码跑没跑通。2. SpringBoot Test核心注解盘点功能、代价和版本陷阱2.1 SpringBootTest到底做了什么SpringBootTest是集成测试的入口注解它的核心作用是启动完整的Spring应用上下文。它会去扫描配置类、加载application.yml、创建所有Bean、执行自动装配逻辑整个流程跟你把应用跑起来几乎一模一样。这个注解有几个关键参数需要重点看一下参数可选值作用webEnvironmentMOCK、RANDOM_PORT、DEFINED_PORT、NONE决定测试环境的Web服务器类型properties形如keyvalue的字符串数组临时指定配置属性覆盖配置文件classes配置类Class数组指定加载哪些配置类控制上下文范围默认的webEnvironment MOCK会创建一个模拟的Servlet环境不启动真实的Tomcat配合MockMvc可以模拟HTTP请求。如果你需要测试真实的HTTP调用比如测RestTemplate或WebClient的远程调用就需要用RANDOM_PORT让它随机选一个可用端口真实启动服务。很多人忽略的一点是SpringBootTest启动的上下文是会被缓存的。也就是说同一个测试类里多个测试方法共用同一个上下文多个测试类如果配置相同也会复用同一个上下文。这个机制在Spring Test Framework里叫ApplicationContext缓存合理利用它是优化测试速度的关键。2.2 切片测试不需要完整容器的时候别硬撑SpringBootTest的代价是完整的自动装配和Bean创建如果你的电脑配置一般跑一个完整测试类可能要等几十秒。更麻烦的是完整上下文意味着所有外部依赖都要健康数据库要能连上Redis要能连上任何一个down掉整个测试类就废了。切片测试就是为了解决这种窘境。它的思路是我只测这一层其他层我都不关心切片注解擅长测试的对象自动加载的内容WebMvcTestController层、拦截器、ControllerAdviceSpring MVC相关组件不会加载Service和RepositoryDataJpaTestRepository层、JPA映射、SQLJPA/Hibernate相关组件默认用内嵌数据库JsonTestJSON序列化与反序列化Jackson等JSON转换器RestClientTestRestTemplate/WebClient的Mock调用RestTemplateBuilder和MockRestServiceServer我特别推荐在项目里多用切片测试。写Controller层测试就用WebMvcTest把Service层Mock掉这样不用连接数据库速度飞快。写Repository层测试就用DataJpaTest它会自动用内嵌数据库如H2只加载JPA相关配置十几秒就能跑完。2.3 MockBean和MockitoBeanSpring Boot 3.4之后的重大变化聊到测试MockBean是绕不开的注解。它的作用很简单把容器里的某个Bean替换成Mockito的Mock对象让你可以不依赖真实实现来测试上层逻辑。但如果你用的是Spring Boot 3.4及以上版本需要特别注意MockBean被标记为废弃了官方推荐使用MockitoBean对应的SpyBean也被SpyBean注意是新的org.springframework.test.context.bean.override.mockito.MockitoBean替代。原因是在3.4版本里引入了一套新的Bean override机制更加灵活、性能更好。如果你的项目还在用3.3或更低版本那继续用MockBean没问题。但如果你的Spring Boot版本已经升到3.4以上启动时候会看到警告日志建议尽早迁移到MockitoBean因为后续版本大概率会移除旧的实现。2.4 配置文件加载顺序和ActiveProfiles的配合SpringBoot测试里经常遇到的一个场景是测试环境要用独立的数据库或配置不能动开发环境的配置。这时候ActiveProfiles(test)就是标配。它背后的逻辑是Spring的Profile机制配置文件里的spring.profiles.active决定默认激活哪个Profile而ActiveProfiles注解可以在测试启动时覆盖这个值让测试走独立的配置。需要注意的坑是配置的加载优先级。在SpringBoot里配置来源的优先级从高到低大概是命令行参数、Java系统属性、环境变量、application-{profile}.yml、application.yml。测试里的TestPropertySource注解优先级高于application.yml但低于SpringBootTest(properties ...)。如果你想在某个测试类里临时覆盖配置最省事的方式是用properties参数比如SpringBootTest(properties spring.datasource.urljdbc:h2:mem:testdb)效果立竿见影也不会污染其他测试。3. 实操过程从依赖到一套完整的可运行测试3.1 环境准备引入必要的测试依赖开始之前先看下SpringBoot项目里基础测试依赖应该怎么加。如果你用的是Spring Initializr创建的项目spring-boot-starter-test通常已经加好了这个依赖里内置了JUnit 5、Mockito、AssertJ、Hamcrest、JSONAssert等一系列测试库足够应付绝大多数场景。dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency如果你的测试要操作真实数据库一般还会引入Testcontainers相关依赖。Testcontainers用Docker容器启动真实的MySQL、PostgreSQL、Redis等中间件测试结束自动销毁容器不会在本地留脏数据。dependency groupIdorg.testcontainers/groupId artifactIdjunit-jupiter/artifactId scopetest/scope /dependency dependency groupIdorg.testcontainers/groupId artifactIdmysql/artifactId scopetest/scope /dependency如果你比较保守只想用内存数据库H2来跑Repository测试那加一个com.h2database:h2依赖就够了。H2的优势是轻量、无需额外环境劣势是它跟真实MySQL/PostgreSQL在某些SQL语法上不完全一致可能出现测试跑得好好的上线却报SQL错误的情况。所以我建议Repository层面的集成测试尽量用Testcontainers具体怎么选后面会展开。3.2 编写第一个Service层单元测试假设你有一个UserService依赖UserRepository和一个PasswordEncoder要写单元测试。核心思路是只测UserService的逻辑其他依赖全部Mock掉。代码如下class UserServiceTest { Mock private UserRepository userRepository; Mock private PasswordEncoder passwordEncoder; InjectMocks private UserService userService; BeforeEach void setUp() { MockitoAnnotations.openMocks(this); } Test void createUser_shouldReturnSavedUser_whenUsernameNotExist() { // 准备 String username alice; String rawPassword 123456; when(userRepository.existsByUsername(username)).thenReturn(false); when(passwordEncoder.encode(rawPassword)).thenReturn(encrypted-password); when(userRepository.save(any(User.class))).thenAnswer(invocation - invocation.getArgument(0)); // 执行 User result userService.createUser(username, rawPassword); // 断言 assertThat(result).isNotNull(); assertThat(result.getUsername()).isEqualTo(username); verify(userRepository, times(1)).save(any(User.class)); } Test void createUser_shouldThrowException_whenUsernameAlreadyExist() { String username alice; when(userRepository.existsByUsername(username)).thenReturn(true); assertThatThrownBy(() - userService.createUser(username, 123456)) .isInstanceOf(BusinessException.class) .hasMessageContaining(already exists); } }这段代码里有几个细节值得讲一下。第一InjectMocks会帮你把Mock创建的对象注入到UserService的构造器或字段中。如果UserService用的是构造器注入那就更加简单清晰这也是我推荐的方式。第二thenAnswer(invocation - invocation.getArgument(0))这个写法很常用。当你不关心save方法的具体返回值但又需要它返回一个有效的对象时直接返回入参是最方便的做法。第三断言的时候用verify来验证依赖的调用次数。这个习惯很多人没有但测试的本质是验证行为只要方法返回了正确结果还不够还要确认你Mock的依赖真的被正确调用了。比如创建用户场景如果业务代码漏掉了save调用返回值依然是null断言就能发现但有些时候业务代码多调了一次save返回值一样不复用verify就查不出来。3.3 Controller层测试用WebMvcTest和MockMvc模拟请求Controller层的测试重点是验证接口的URL映射、参数校验、返回值结构和状态码。这一层不需要启动完整容器用WebMvcTest加MockMvc就够了。WebMvcTest(UserController.class) class UserControllerTest { Autowired private MockMvc mockMvc; MockitoBean private UserService userService; Test void getUser_shouldReturnUserDto_whenUserExists() throws Exception { Long userId 1L; UserResponseDto dto new UserResponseDto(userId, alice); when(userService.getUserById(userId)).thenReturn(dto); mockMvc.perform(get(/api/users/{id}, userId)) .andExpect(status().isOk()) .andExpect(jsonPath($.username).value(alice)) .andExpect(jsonPath($.id).value(1)); } Test void createUser_shouldReturn400_whenUsernameBlank() throws Exception { String requestBody { username: , password: 123456 } ; mockMvc.perform(post(/api/users) .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andExpect(status().isBadRequest()); } }这里用到了MockitoBean如果你用的是Spring Boot 3.4以下就写MockBean把UserService直接替换成Mock这样Controller测试就不会走到真实Service逻辑不连数据库很快。几个容易踩的坑说一下。WebMvcTest默认会加载所有ControllerAdvice、Filter、WebMvcConfigurer。如果项目里有全局异常处理器它会生效比如校验参数失败时返回400这个行为就在异常处理器里控制测试时要留意是否符合预期。如果项目里有Spring SecurityWebMvcTest会加载安全配置。很多项目里Controller方法都有权限校验测试的时候需要对MockMvc做安全设置或者把安全配置排除掉。最简单的做法是在测试类上加AutoConfigureMockMvc(addFilters false)跳过过滤器。jsonPath的用法要熟悉这是AssertJ之外另一个常用的断言库。$.username代表JSON根路径下的username字段取值后跟期望值对比。3.4 Repository层测试DataJpaTest和Testcontainers的取舍Repository层测试主要验证SQL是否正确、返回的实体字段映射是否正确。这里有两种主流方案。方案一DataJpaTest加H2内存数据库。启动速度最快不需要额外环境。适合简单的CRUD场景。DataJpaTest class UserRepositoryTest { Autowired private UserRepository userRepository; Test void findByUsername_shouldReturnUser_whenUserExists() { User user new User(); user.setUsername(alice); user.setPassword(encrypted); userRepository.save(user); OptionalUser result userRepository.findByUsername(alice); assertThat(result).isPresent(); assertThat(result.get().getUsername()).isEqualTo(alice); } }方案二DataJpaTest加Testcontainers。如果一个项目里的SQL逻辑复杂用到了MySQL特有的函数、JSON字段、全文索引H2很可能跟MySQL行为不一致这时候就必须用Testcontainers跑真实的MySQL容器。DataJpaTest Testcontainers AutoConfigureTestDatabase(replace AutoConfigureTestDatabase.Replace.NONE) class UserRepositoryTest { Container static MySQLContainer? mysql new MySQLContainer(mysql:8.0) .withDatabaseName(testdb) .withUsername(test) .withPassword(test); DynamicPropertySource static void configureProperties(DynamicPropertyRegistry registry) { registry.add(spring.datasource.url, mysql::getJdbcUrl); registry.add(spring.datasource.username, mysql::getUsername); registry.add(spring.datasource.password, mysql::getPassword); } Autowired private UserRepository userRepository; // 测试方法 }这里有几个关键点。AutoConfigureTestDatabase(replace NONE)非常关键。默认情况下DataJpaTest会尝试用内嵌数据库替换数据源如果不加这一行Testcontainers启动的MySQL容器配置会被覆盖掉白启动了。DynamicPropertySource是在Spring容器启动前动态注册配置属性的机制这里把容器的JDBC信息动态注入到spring.datasource.*配置中。用Testcontainers跑真实数据库测试速度肯定比H2慢但换来的是跟生产环境一致的SQL行为。我的建议是简单的CRUD和关联查询用H2就够复杂的SQL、原生查询、数据库特性相关的测试用Testcontainers。3.5 完整的集成测试SpringBootTest Testcontainers MockMvc如果你需要把Controller层、Service层、Repository层全部串起来测一个完整的业务链路那就要上SpringBootTest了。比如用户注册的流程从接收HTTP请求开始到参数校验、业务逻辑、数据落库、返回响应全链路都要测一遍。SpringBootTest(webEnvironment SpringBootTest.WebEnvironment.RANDOM_PORT) Testcontainers class UserIntegrationTest { Container static MySQLContainer? mysql new MySQLContainer(mysql:8.0) .withDatabaseName(testdb) .withUsername(test) .withPassword(test); DynamicPropertySource static void configureProperties(DynamicPropertyRegistry registry) { registry.add(spring.datasource.url, mysql::getJdbcUrl); registry.add(spring.datasource.username, mysql::getUsername); registry.add(spring.datasource.password, mysql::getPassword); } LocalServerPort private int port; Autowired private TestRestTemplate restTemplate; Test void registerUser_shouldPersistAndReturnCreated() { String url http://localhost: port /api/users; UserCreateRequest request new UserCreateRequest(alice, 123456); ResponseEntityUserResponseDto response restTemplate.postForEntity( url, request, UserResponseDto.class); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED); assertThat(response.getBody()).isNotNull(); assertThat(response.getBody().getUsername()).isEqualTo(alice); // 再查一次数据库确认数据真的落库了 String queryUrl http://localhost: port /api/users/ response.getBody().getId(); ResponseEntityUserResponseDto queryResponse restTemplate.getForEntity(queryUrl, UserResponseDto.class); assertThat(queryResponse.getBody().getUsername()).isEqualTo(alice); } }RANDOM_PORT配合TestRestTemplate是集成测试里非常舒服的组合。TestRestTemplate会自动带上测试环境的相关配置用法跟RestTemplate几乎一样但更贴近SpringBoot集成的写法。集成测试写起来爽但要注意别滥用。如果你每个测试类都用完整的SpringBootTest几十个测试类加起来CI时间会非常可观。我的建议是核心链路写集成测试其他逻辑用单元测试和切片测试覆盖。3.6 测试命名规范和断言技巧最后分享几个测试代码的规范建议这部分对团队协作的价值可能超过技术本身。测试方法命名我推荐使用方法名_场景_预期结果的格式比如createUser_shouldReturnSavedUser_whenUsernameNotExist。这种命名读起来跟英语句子一样测试失败的时候看方法名就知道哪里出了问题不用再去翻代码。断言方面优先使用AssertJ的流式断言而不是JUnit自带的assertEquals那一套。AssertJ的链式API可读性更强还能做集合字段的精确断言。assertThat(result) .extracting(User::getUsername, User::getStatus) .containsExactly(alice, UserStatus.ACTIVE); assertThat(userList) .hasSize(3) .extracting(User::getUsername) .containsExactly(alice, bob, carol);一个测试方法只测一个行为不要在一个方法里堆十几个断言。如果某个行为需要多种断言来验证那就说明这个行为本身太复杂该考虑把逻辑拆出来。4. 常见问题与排查技巧实录4.1 数据库连接失败H2替换了MySQL数据源怎么办这是DataJpaTest最常见的坑之一。你配置的是MySQL连接串但DataJpaTest默认会用内嵌数据库H2把数据源替换掉然后启动时报错Failed to replace DataSource with an embedded database。解决方式很明确加一行配置AutoConfigureTestDatabase(replace AutoConfigureTestDatabase.Replace.NONE)这行的意思是不要替换我的数据源。如果你确实想用内存数据库但项目里用的是MySQL语法那H2需要开启MySQL兼容模式在application-test.yml里设置连接串jdbc:h2:mem:testdb;MODEMySQL;DATABASE_TO_LOWERTRUE。4.2 MockBean注入不生效有时候你在测试类上加了MockBean但运行时发现被Mock的Bean还是实际逻辑或者干脆报NoSuchBeanDefinitionException。这通常是因为你Mock的类没有被Spring容器管理。排查思路从三个角度走第一确认目标Bean是否真的在容器里比如你Mock的是UserService那UserService必须是在Service或Component注解下注册过的第二确认切面是否生效如果项目用了AOP切面切在Service层上MockBean替换的是目标对象但切面代理可能还保留着对原有目标对象的引用第三如果你用的是Spring Boot 3.4以下版本检查是不是误用了MockitoBean这个注解在这些版本里还不存在会直接编译报错。4.3 测试方法之间数据互相污染这是Repository测试和集成测试里特别容易遇到的问题。第一个测试方法往数据库插了一条记录第二个测试方法查询时发现数据比预期多于是断言失败。解决方案是Transactional。在测试方法或测试类上加TransactionalSpring会在每个测试方法结束后自动回滚事务不会真的落库。DataJpaTest本身就是事务性的所以不需要额外加。但SpringBootTest默认不是事务性的需要自己加SpringBootTest Transactional class UserIntegrationTest { // 每个测试方法结束后自动回滚 }注意加Transactional的测试回滚是默认行为。如果你某个测试方法确实需要验证数据落库后能被查询到或者需要外部的另一个服务读到这条数据比如异步消息队列就不适合加事务。这时候应该用Testcontainers或者每轮测试前清库的策略。4.4 测试启动时Redis、消息队列连不上SpringBoot项目里基本都用了Redis一些项目还接入了MQ。SpringBootTest启动时会自动创建这些Bean如果本地的Redis没启动测试直接报连接超时。有两种处理方式。第一种Mock掉外部依赖相关的Bean。比如你测试用户注册链路里面用到了Redis缓存用户Session那直接MockitoBean掉RedisTemplate或StringRedisTemplate让Redis这部分逻辑走Mock不真的去连Redis。第二种用SpringBootTest(properties ...)禁用相关自动配置。比如SpringBootTest(properties { spring.redis.port6379, spring.autoconfigure.excludeorg.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration })这种方式适合你不关心Redis逻辑的测试。但如果你要测的链路本身依赖Redis的核心能力那还是要启动Testcontainers的Redis容器这个跟MySQL的用法一样GenericContainer指定redis:7-alpine镜像即可。4.5 IDEA和Maven环境下配置文件差异导致的测试失败从热搜词里能看到idea maven发布时的prod test配置文件这个问题不少人都遇到过。现象通常是本地IDEA里跑测试一切正常但是在Maven命令行执行mvn test时就报错或者反之。根源在于IDEA和Maven设置spring.profiles.active的方式不一样。IDEA里你可以在Run Configuration的Environment variables或者VM options里指定-Dspring.profiles.activetest但Maven的mvn test不会自动读取这个设置它只会读取application.yml和application-{profile}.yml。所以最稳妥的做法是不要依赖IDE或者命令行来指定Profile而是在测试代码里显式声明ActiveProfiles(test)这样无论是IDEA还是Maven执行都会统一激活test环境配置。如果遇到IDEA里能跑、Maven里跑不了的情况优先检查是不是项目里用了src/test/resources下的配置但Maven没有把它打进测试Classpath这类问题可以查看target/test-classes目录确认。4.6 测试跑得慢上下文缓存和并行执行的优化策略测试太慢是团队推行测试文化的巨大阻力。一次构建十分钟谁都不想等。优化测试速度核心思路有三个方向。第一个方向尽量多用单元测试和切片测试。DataJpaTest、WebMvcTest都比SpringBootTest快一个数量级。能用Mock解决的问题就不要启动完整容器。第二个方向善用SpringTest的上下文缓存机制。Spring会缓存ApplicationContext相同配置的测试类复用同一个上下文。为了让缓存命中率更高尽量不要在不同测试类里通过SpringBootTest(properties ...)写不同的配置每个不同的配置都会生成一个独立的上下文缓存就失效了。第三个方向开启JUnit的并行测试。JUnit 5支持并行执行配置一下junit-platform.propertiesjunit.jupiter.execution.parallel.enabledtrue junit.jupiter.execution.parallel.mode.defaultconcurrent junit.jupiter.execution.parallel.mode.classes.defaultconcurrent但要注意并行执行测试时多个测试类共享数据库会产生数据竞争。对于依赖数据库的测试类还是建议保持串行或者用Testcontainers隔离。最后再分享一个小技巧我在项目里踩过的最大一个坑是把spring-boot-starter-test里的依赖用exclusion排除掉了。当时是为了解决一个依赖冲突结果把AssertJ排掉了导致一大片测试的assertThat全部编译报错。排查了半天才发现是依赖被排除导致的。所以如果你在测试里遇到离奇的编译错误先别急着改代码看一眼mvn dependency:tree确认一下SpringBoot测试相关的依赖是不是完整。尤其是JUnit 5、Mockito、AssertJ这三个核心库缺一不可。另外一个容易被忽略的依赖是spring-boot-test-autoconfigure切片测试注解都依赖它如果你在项目里手动整理过依赖一定要保证它没有被误删。测试这个东西写的时候确实比写业务代码费劲但它给你带来的安全感和自信是线上出问题时才发现没测试可跑的懊恼所无法比拟的。希望你也能在自己的项目里把测试跑起来跑得又快又稳。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

ToolJet 接入 Google BigQuery 数据源全指南:服务账号认证、连接配置与九大数据操作实战 2026/9/9 20:30:55

ToolJet 接入 Google BigQuery 数据源全指南:服务账号认证、连接配置与九大数据操作实战

ToolJet 接入 Google BigQuery 数据源全指南:服务账号认证、连接配置与九大数据操作实战 【免费下载链接】ToolJet Open-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workf…

阅读更多 →
SpringAI-Advisor实战:自定义Advisor机制与DeepSeek content为空排查 2026/9/9 20:30:55

SpringAI-Advisor实战:自定义Advisor机制与DeepSeek content为空排查

说实话,第一次看到“SpringAI-Advisor”这个项目名,我第一反应是:又是一个把Spring AI包了一层、塞了几个工具类的示例工程。但真正把源码拉下来、跑通链路之后,我发现自己低估了它——Advisor在Spring AI里扮演的角色&#xff0c…

阅读更多 →
服务端状态与数据获取库技术选型对比:React Query vs SWR vs Apollo Client vs RTK Query vs React Router 2026/9/9 20:30:55

服务端状态与数据获取库技术选型对比:React Query vs SWR vs Apollo Client vs RTK Query vs React Router

服务端状态与数据获取库技术选型对比:React Query vs SWR vs Apollo Client vs RTK Query vs React Router 【免费下载链接】query 🤖 Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Qu…

阅读更多 →
中小企业低成本SEO实操指南:从关键词到内容优化的完整打法 2026/9/9 20:30:55

中小企业低成本SEO实操指南:从关键词到内容优化的完整打法

做SEO这行十年,被中小企业老板问得最多的一句话是:“我预算不多,能不能不花大价钱也能把网站做上来?”我的回答通常是:能,但前提是你得把力气用在刀刃上。大公司烧钱买词、堆资源、养团队,那是他…

阅读更多 →
从 Changelog 读懂 expo-app-integrity:Expo 应用完整性校验模块的版本演进与实现剖析 2026/9/9 20:30:55

从 Changelog 读懂 expo-app-integrity:Expo 应用完整性校验模块的版本演进与实现剖析

从 Changelog 读懂 expo-app-integrity:Expo 应用完整性校验模块的版本演进与实现剖析 【免费下载链接】expo An open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web. 项目地址: https://gitcode.com/G…

阅读更多 →
Istio 示例镜像构建指南:读懂 samples/builder 的 docker buildx bake 流水线 2026/9/9 20:27:55

Istio 示例镜像构建指南:读懂 samples/builder 的 docker buildx bake 流水线

Istio 示例镜像构建指南:读懂 samples/builder 的 docker buildx bake 流水线 【免费下载链接】istio Connect, secure, control, and observe services. 项目地址: https://gitcode.com/GitHub_Trending/is/istio Istio 仓库的许多示例(bookinfo…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞