1. 文件上传
1.1 页面表单
<form role="form" action="/upload" method="post" enctype="multipart/form-data"> <div class="form-group"> <label for="exampleInputEmail1">邮箱</label> <input type="email" class="form-control" name="email" id="exampleInputEmail1" placeholder="Enter email"> </div> <div class="form-group"> <label for="exampleInputPassword1">名字</label> <input type="password" class="form-control" name="username" id="exampleInputPassword1" placeholder="Password"> </div> <div class="form-group"> <label for="exampleInputFile">壁纸</label> <input type="file" id="exampleInputFile" name="wallpaperInputFile"> </div> <div class="form-group"> <label for="exampleInputFile">批量照片</label> <!-- multiple 代表该 file 属性可以支持多文件上传 --> <input type="file" name="photos" multiple> </div> <div class="checkbox"> <label> <input type="checkbox"> Check me out </label> </div> <button type="submit" class="btn btn-primary">提交</button> </form>
1.2 文件上传代码
@PostMapping(value = "/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public String upload( @RequestPart("wallpaperInputFile") MultipartFile wallpaperInputFile, @RequestPart("photos") MultipartFile[] photos) throws IOException { if (!wallpaperInputFile.isEmpty()){ String originalFilename = wallpaperInputFile.getOriginalFilename(); wallpaperInputFile.transferTo(new File("F:\\"+originalFilename)); } if ((photos.length > 0)) { for (MultipartFile photo : photos) { if (!photo.isEmpty()) { String originalFilename = photo.getOriginalFilename(); photo.transferTo(new File("F:\\"+originalFilename)); } } } return "index"; }
1.3 注意事项
1.3.1 文件上传大小限量
当提示文件大小过大时,可以修改 spring.servlet.max-file-size 和 max-request-file-size 属性来解决这个问题
# -------------- SpringBoot - properties ---------------- # 文件最大大小 spring.servlet.multipart.max-file-size=10MB # 请求最大大小 spring.servlet.multipart.max-request-size=100MB
1.3.2 content-Type
文件上传需要指定 content-type 值为:multipart/form-data
因此,无论在控制器还是表单都必须设置好对应的类型
/** * ----------------控制器----------- * * consumes 使用内容类型 = MediaType.MULTIPART_FORM_DATA_VALUE -- "multipart/form-data" * MULTIPART_FORM_DATA_VALUE 常量就是 multipart/form-data * 该属性限定了接收的内容类型 */ @PostMapping(value = "/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
<!-- enctype="multipart/form-data" enctype 属性可以设置 content-type 的值 这里直接指定为 multipart/form-data** --> <form role="form" action="/upload" method="post" enctype="multipart/form-data"></form>
1.4 文件上传(自动配置)原理
文件上传自动配置类 - MultipartAutoConfiguration-MultiaprtProperties
- 自动配置好了 StandardServletMultipartResolver【文件上传解析器】
- 原理步骤:
- 请求进来使用文件上传解析器(isMultipart)判断并封装(resolveMultipart返回MultipartHttpServletRequest)文件上传请求
- 参数解析器来解析请求中的文件内容,封装成 MultipartFile
- 将request中文件信息封装为一个Map
2. 异常处理
2.1 错误处理
2.1.1 默认规则
- 默认情况下,Spring Boot 提供
/error处理所有错误的映射 - 对于机器客户端,它将生成JSON响应,其中包含错误,HTTP状态和异常消息的详细信息,对于浏览器客户端,响应一个”whiteLabel“错误视图,以HTML格式呈现相同的数据
- 要对其进行自定义,添加
View解析为error - 要完全替换默认行为,可以实现
ErrorController并注册该类型的Bean定义,或添加ErrorAttributes类型的组件以使用现有机制但替换其内容 - error/下的4xx,5xx页面会被自动解析
2.1.2 定制错误处理逻辑
- 自定义错误页面
- error/4xx.html error/5xx.html;有精确的错误状态码页面就匹配精确,没有就找 4xx.html ;如果都没有就触发空白页
- @ControllerAdvice+@ExceptionHandler 处理全局异常
- @ResponseStatus+自定义异常
- 底层是ResponseStatusExceptionResolver,把responsestatus注解的信息组装成ModelAndView返回;底层调用 .sendError(statusCode, resolverReason);
- Spring底层的异常,如:参数类型转换异常;DefaultHandlerExceptionResolver处理框架底层的异常
- response.sendError(HttpServletResponse.SC_BAD_REQEUST, ex.getMessage)
- 自定义需要实现 HandlerExceptionResolver 处理异常,可以作为默认的全局异常处理规则
- ErrorViewResolver实现自定义处理异常
- response.sedError;error请求就会转给controller
- 异常没有任何方法能处理。tomcat底层 response.sendError。error请求转给controller
- basicErrorController 要去的页面地址是 ErrorViewResolver
2.1.3 异常处理原理
- ErrorMvcAutoAConfiguraion 自动配置异常处理规则
- 容器中的组件:类型DefaultErrorAttributes-> id
errorAttributes
- DefaultErrorAttributes:定义错误页面中可以包含哪些数据
- 容器中的组件:类型 BasicErrorController -> id basicErrorController
- 处理默认 /error 路径的请求:页面响应 new ModelAndView(“error”,model)
- 容器中有组件View -> id是error;(响应默认错误页)
- 容器中放组件 BeanNameViewResolver(视图解析器);按照返回的视图名作为组件的id去容器中找View对象
- 容器中的组件:类型 DefaultErrorViewResolver -> id conventionErrorViewResolver
- 如果发生错误,会以HTTP的状态码作为视图页地址(viewName),找到真正大页面
- error/stuts.viewName(404、5xx).html
如果想要返回页面;就会找error视图 StaticView。(默认是白页)
2.1.4 异常处理步骤流程
- 执行目标方法,目标方法运行期间有任何异常都会被 cath,而且标注当前请求结束;并且用 dispatchExeption
- 进入视图解析流程(页面渲染)
- mv = processHandlerException处理 handler 方法异常,处理完成返回 ModelAndView;
- 遍历所有 handlerExceptionResolvers,看谁能处理当前异常【处理器异常解析器】
- 系统默认的异常解析器;
- DefaultErrorAttributes
- HandlerExeptionResolverComposite
- ExceptionHandlerExeptionResolver
- ResponseStatusExeptionResolver
- DefaultHanderExeptionResolver
- DefaultErrorAttuibute 先来处理异常,把异常信息保存到request域,并且返回null;
- 默认没有任何方法能处理异常,所以异常会被抛出
- 如果没有任何方法能处理,最终底层就会发生 /error 请求
- 解析错误视图;遍历所有的 ErrorViewResolver 看谁能解析
- 默认的 DefaultErrorViewResolver 作用是把响应状态码作为错误页的地址,error/500.html
- 模板引擎最终响应这个页面 error/500.html
3. 原生组件注入(Servlet、Filter、Listener)
3.1 使用 Servlet API
@ServletComponentScan(“com.renex.admin”):指定原生Servlet组件都放在哪里
@WebServlet(urlPatterns = “/my”):直接响应,没有Spring的拦截器
@WebFilter(urlPatterns = {“/my”}):拦截指定路径下的所有请求
@WebListener:声明的类是一个 监听类
3.2 使用 RegistrationBean
使用 ServletRegistrationBean、FilterRegistrationBean和ServletListenerRegistrationBean
@Configuration public class MyRegistConfig { @Bean public ServletRegistrationBean myServlet(){ MyServlet myServlet = new MyServlet(); return new ServletRegistrationBean(myServlet,"/my"); } @Bean public FilterRegistrationBean myFilter(){ MyFilter myFilter = new MyFilter(); // 方式一: // return new FilterRegistrationBean(myFilter,myServlet());// 拦截myServlet()返回的全部路径 // 方式二: FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter); filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/my01")); return filterRegistrationBean; } @Bean public ServletListenerRegistrationBean myListener(){ MyListener myListener = new MyListener(); return new ServletListenerRegistrationBean(myListener); } }
3.3 DispatchServlet 注入原理
3.3.1 DispatchServlet 如何注册进容器?
- 容器中自动配置了 DisptacherServlet 属性并绑定到 WebMvcProperties;
对应的配置文件的配置项spring.mvc - 通过 ServletRegistrationBean 把 DisptacherServlet 配置进来
默认映射的是 / 路径
多个servlet都能处理到同一层路径,精确优先原则
4. 嵌入式 Web 容器
4.1 切换嵌入式Servlet容器
- 默认支持的 webServer
- Tomcat,Jetty 或 Undertow
- ServletWebServerApplicationContext 容器启动寻找 ServletWEbServerFactory 并引导创建服务器
- 切换服务器
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!-- 排除默认的 Tomcat 服务器 --> <exclusions> <groupId>org.springframework.boot</groupId> <artifactid>spring-boot-starter-tomcat</artifactid> </exclusions> </dependency> <dependency> <!-- 设置 undertow 服务器场景包 --> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency>
- 原理:
- SprigBoot 应用启动,发现当前是 Web 应用。web场景包-导入 tomcat
- web 应用会创建一个 web 版的 ioc 容器(ServletWebServerApplicationContext)
- 在 ioc 启动时,寻找 servletServerFactory(Servlet 的 web 服务器工厂 -> Servlet 的 web 服务器 )
- SpringBoot 底层默认有很多的 WebServer 工厂
- 底层直接会有一个自动配置类:ServletWebServerFactoryAutoConfiguraion
- ServletWebServerFactoryAutoConfiguraion 导入了 ServletWebServerFactoryConfiguration(配置类)
- ServletWebServerFactoryConfigration 配置类根据动态判断系统中到底导入了哪个 Web 服务器的包(默认 Tomcat),容器中就有 TomcatServletWebServerFactory
- TomcatServletWebServerFactory 创建出 Tomcat 服务器并启动;
- TomcatWebServer 的构造器,它拥有初始化方法initialize
- 内嵌服务器就是手动把启动服务器的代码调用(tomcat 核心 jar 包存在)
4.2 定制 Servlet 容器
- 实现 WebServerFactoryCustomizer
- 修改配置文件 server.xxx
- 直接自定义 CongfigurableServletWebServerFactory
xxxxxxCustomizer:定制化器,可以该变 xxxxxx 的默认规则
5. 定制化原理
5.1 定制化的常见方式
- 修改配置文件
- xxxxxCustomizer
- 编写自定义的配置类 xxConfiguratin + @Bean 替换、增加容器中的默认组件;视图解析器
- web应用 实现 WebMvcConfigurer 即可定制化 web 功能 +
@Bean 给容器中再扩展一些组件
@Configuration public class AdminWebConfig impements WebMvcConfigurer
@EnableWebMvc+ @WebMvcConfigurer —— @Bean 可以全面接管 SpringMVC,所有规则全部自己重写配置;实现定制和扩展功能原理:
- WebMvcAutoConfiguration 默认的 SpringMVC 的自动配置功能类。包括实现,静态资源、欢迎页…功能
- 一旦使用 @EnableWebMvc 会 @Import(DelegatingWebMvcConfiguration.class)
- DelegationWebMvcConfiguration的作用:只保证 SpringMVC 最基本的使用
- 把所有系统中的 WebMvcConfigurer 拿来。所有功能的定制都是这些 类 合起来一起生效
- 自动配置了一些非常底层的组件。RequestMappingHandlerMapping。这些组件依赖的组件都是从容器中获取
- WebMvcAutoConfiguration 里面的配置要能生效必须
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class) - @EnableWebMvc 导致了 WebMvcAutoConfiguration 没有生效
因为一旦声明了@EnableWebMvc,由于该注解会自动引入DelegatingWebMvcConfiguration.class,它会将 WebMvcAutoConfiguration 删除,所以导致了 WebMvcAutoConfiguration 没有生效
- ······
5.2 原理分析套路
场景starter - xxxxAutoConfiguration - 导入xxx组件 - 绑定xxxProperties - 绑定配置文件项
6. 数据访问
6.1 SQL
6.1.1 数据源的自动配置
6.1.1.1 导入JDBC 场景
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency>
没有数据库驱动?官方不知道我们接下来要操作的数据库
数据库版本和驱动版本对应,SpringBoot 默认会有驱动版本仲裁
导入驱动:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.30</version> </dependency> <!-- 想要修改版本 1. 直接引入具体版本(maven的就近依赖原则) 2. 重写声明版本(maven的属性的就近优先原则) --> <properties> <java.version>11</java.version> <mysql.version>8.0.30</mysql.version> </properties>
6.1.1.2 分析自动配置
6.1.1.2.1 自动配置的类
- DataSourceAutoConfiguration:数据源的自动配置
- 修改数据源相关的配置:spring.datasource
- 数据库连接池的配置,是自己容器中没有DataSource才自动配置的
- 底层默认配置好的连接池是:HikariDataSource
@Configuration( proxyBeanMethods = false ) @Conditional({DataSourceAutoConfiguration.PooledDataSourceCondition.class}) @ConditionalOnMissingBean({DataSource.class, XADataSource.class}) @Import({Hikari.class, Tomcat.class, Dbcp2.class, Generic.class, DataSourceJmxConfiguration.class}) protected static class PooledDataSourceConfiguration { protected PooledDataSourceConfiguration() { } }
- DataSourceTransctionManagerAutoConfiguration:事务管理器的自动配置
- JdbcTemplateAutoConfiguration:JdbcTemplate的自动配置,可以对数据库进行crud
- 可以修改整个配置项 @ConfigurationProperties(prefix = “spring.jdbc”) 来修改jdbcTemplate
- JndiDataSourceAutoConfiguration:Jndi的自动配置
- XADataSourceAutoConfiguration:分布式事务相关的
6.1.1.3 修改配置项
spring: datasource: url: jdbc:mysql://localhost:3306/test_1?serverTimezone=UTC username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver
# 超时处理;此处意思:当查询时间超过 3 秒视为查询超时 spring: jdbc: template: query-timeout: 3 #单位秒
6.1.1.4 测试
@Slf4j @SpringBootTest class SpringbootWebAdminApplicationTests { @Autowired JdbcTemplate jdbcTemplate; @Test void contextLoads() { Long aLong = jdbcTemplate.queryForObject("select count(*) from person", long.class); log.info("记录总数"+aLong); } }
6.1.2 使用 Druid 数据源
6.1.2.1 Druid 官方 github 地址
整合第三方技术的两种方式
- 自定义
- 找 starter
6.1.2.2 自定义方式
6.1.2.2.1 创建数据源
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.11</version> </dependency>
6.1.3 整合 MyBatis 操作
SpringBoot官方的Starter:spring-boot-starter-*
第三方的:*-spring-boot-starter
6.1.3.1 配置模式:
6.1.3.1.1 引入配置文件
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version> </dependency>
6.1.3.1.2 配置模式
- 全局配置文件
- SqlSessionFactory:会自动配置
- SqlSession:自动配置了 SqlSessionTemplate 组合了 SqlSession
- Mapper:只要写的操作myBatis的接口标注了@Mapper就会备自动扫描进来
可以修改配置文件中 mybatis 的配置文件
# 配置 mybatis 规则 mybatis: config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mybatis/mapper/*.xml # Mapper接口 -> 绑定xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.renex.admin.mapper.PersonMapper"> <select id="getPerson" resultType="com.renex.admin.pojo.Person"> select * from person where id = #{id} </select> </mapper>
注意事项:
# 配置 mybatis 规则 mybatis: # config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mybatis/mapper/*.xml # 开启驼峰命名转换 configuration: # 指定全局配置文件中的相关配置项 map-underscore-to-camel-case: true
可以不写全局配置文件,所有全局配置文件都放在configuration配置项中即可
使用了 properties(yaml) 就不能使用 xml 配置文件,两者选一个
6.1.3.1.3 步骤:
- 导入 mybatis 官方 starter
- 编写 mapper 接口。必须标注 @Mapper 注解
- 编写 sql 映射文件并绑定mapper接口
- 在 application.yaml 中指定 Mapper 配置文件的位置,以及指定全局配置文件的信息(建议:直接配置在mybatis.configuration)
6.1.3.2 注解模式:
与原生mybatis使用并无两样
6.1.3.3 混合模式:
在一个服务类中可以使用注解也可以使用配置模式
7. 单元测试
7.1 JUnit5
SpringBoot 2.2.0 版本开始引入 JUnit5 作为单元测试默认库
作为最小的版本 JUnit 框架,JUnit5 与之前的版本的 Junit 框架有很大的不同。由三个不同的子项目的不同模块组成
Junit 5 = JUnit Platform + Junit Jupiter + Junit Vintage
Junit Platform:Junit Platform 是在 JVM 上启动测试框架的基础,不仅支持 Junit 自制的测试引擎,其他测试引擎也都可以接入。
Junit Jupiter:Junit Jupiter 提供了 JUnit5 的新的编程模型,是Junit5新特性的核心。内部 包含了一个测试引擎,用于在Junit Platform 上运行
Junit Vintage:由于 Junit 已经发展多年,为了照顾老的项目,Junit Vintage 提供了兼容Junit4.x,Junit3.x的测试引擎
SpringBoot2.4 以上移除了默认对 Vintage 的依赖。如果需要兼容 junit4 需要自行引入(不能使用Junit4的功能)
如果需要继续兼容 Junit4 需要自行引入 vintage
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> <scope>test</scope> </dependency>
现在版本:
@SpringBootTest class Boot05WebAdminApplicationTestsO{ @Test void contentLoads(){ } }
以前:
@SpringBootTest + @RunWith(SpringTest.class)
SpringBoot 整合 Junit 以后:
- 编写测试方法:@Test 标注(注意需要使用Junit5版本的)
- Junit类具有Spring的功能,@Autowired、比如 @Transactional 标注测试方法,测试完成后自动回滚
7.2 JUnit5 常用注解
Junit5 的注解与JUnit4的注解有所变化。详细更新或注解介绍:JUnit 5 User Guide
| 注解名称: | 详情用法: |
| @Test | 表示方法是测试方法。但是与Junit4的@Test不同。它的职责非常单一不能声明任何属性,拓展的测试将会由Jupiter提供测试 |
| @ParmeterizedTest | 表示方法是参数化测试 |
| @RepeatedTest | 表示方法可以重复执行 |
| @DispalyName | 为测试类或者测试方法设置展示名称 |
| @BeforeEach | 表示在每个单元测试之前执行 |
| @AfterEach | 表示在每个单元测试之后执行 |
| @BeforeAll | 表示在所有单元测试之前执行 |
| @AfterAll | 表示在所有单元测试之后执行 |
| @Tag | 表示单元测试类别,类似于JUnit4中的@Categories |
| @Disabled | 表示测试类或测试方法不知想,类似于JUnit4中的@Ignore |
| @Timeout | 表示测试方法运行如果超过了指定时间将会返回错误 |
| @ExtendWith | 为测试类或测试方法提供扩展类引用。集合了 SpringBoot 可以使用 @SpringBootTest 进行代替,但是会启动 SpringBoot 的容器功能 |
7.3 断言(assertions)
断言(assertions)是测试方法中的核心部分,用来对测试需要满足的条件进行验证。这些断言方法都是 org.junit.jupiter.api.Assertions 的静态方法。JUnit5 内置的断言可以分成如下几个类别:
检查业务逻辑返回的数据是否合理
所有的测试运行结束以后,会有一个详细的测试报告;
7.3.1 简单断言
用来对单个值进行简单的验证,如:
| 方法 | 说明 |
| assertEquals | 判断两个对象或两个原始类型是否相等 |
| assertNotEquals | 判断两个对象或两个原始类型是否不相等 |
| assertSame | 判断两个对象引用是否指向同一个对象 |
| assertNotSame | 判断两个对象引用是否指向不同的对象 |
| assertTrue | 判断给定的布尔值是否为 true |
| assertFalse | 判断给定的布尔值是否为 false |
| assertNull | 判断给定的对象引用是否为 null |
| assertNotNull | 判断给定的对象引用是否不为 null |
7.3.2 组合断言
assertAll 方法接收多个 org.junit.jupiter.api.Executable 函数式接口的实例作为要验证的断言,可以通过 lambda 表达式很容的提供这些断言
@DisplayName("组合断言") @Test void all(){ /** * 所有断言需要全部成功 */ assertAll("test", ()-> assertTrue(true && false), ()-> assertEquals(1,1) ); }
7.3.3 异常断言
在 JUnit4 使其,想要测试方法的异常情况时,需要用 @Rule 注解的ExpectedException 变量还是比较麻烦的。而JUnit5提供了一种新的断言方式 Assertions.assertThrows(),配合函数式编程就可以进行使用
@Test @DisplayName("异常断言") void testException(){ // 断言业务逻辑一定出现异常 assertThrows(ArithmeticException.class, ()->{ int i = 1/0; },"业务逻辑正常运行!!"); }
7.3.4 超时断言
JUnit5 还提供了 Assertions.asserTimeout() 为测试方法设置了超时时间
@Test @DisplayName("超时断言") void testTimeoutAssert(){ /** * 运行时间已超出 1000 毫秒 */ assertTimeout(Duration.ofMillis(1000),()->{ Thread.sleep(1100); }); }
7.3.5 快速失败
通过 fail 方法直接使得测试失败
@Test @DisplayName("快速失败") void testFail(){ System.out.println("测试开始......."); fail("直接宣告测试失败!"); System.out.println("测试正在运行...."); System.out.println("测试结束......"); }
7.4 前置条件(assumptions)
JUnit5 中的前置条件(assumptions 【假设】)类似于断言,不同之处在于不满足的断言会使得测试方法失败,而不满足的前置条件只会使得测试方法的执行终止。前置条件可以看成是测试方法执行的前提,当该前提不满足时,就没有继续执行的必要。
@Test @DisplayName("测试前置条件") void testAssumptions(){ Assumptions.assumeTrue(assumeIsTrue(),"结果不是true"); System.out.println("11"); } boolean assumeIsTrue(){ return false; }
assumeTrue 和 assumFalse 确保给定的条件为 true 或 false,不满足条件会使得测试执行种植。assumingThat 的参数是表示条件的布尔值和对应的 Executable 接口的实现对象。只有田间满足时,Executable 对象才会被执行;当条件不满足时,测试执行并不会终止
7.5 嵌套测试
JUnit5 可以通过 Java 中的内部类和 @Nested 注解实现嵌套测试,从而可以更好的把相关的测试方法组织在一起。在内部类中可以使用 @BeforEach 和 @AfterEach 注解,而且嵌套的层次没有限制
内层的 Test 可以驱动外层的 Befor(After)Each / All 之类的方法 提前 / 之后 运行
7.6 参数化测试
参数化测试是 JUnit5 很重要的一个新特性,它使得用不同的参数多次运行测试成为了可能,也为我们的单元测试带来许多遍历。
利用 @ValueSrouce 等注解,指定入参,我们将可以使用不同的参数进行多次单元测试,而不是每新增一个参数就新增一个单元测试。
| 注解名称 | 说明 |
| @ValueSource | 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型 |
| @NullSource | 表示为参数化测试提供一个null的入参 |
| @EnumSource | 表示为参数化测试提供一个枚举入参 |
| @CsvFileSource | 表示读取指定CSV文件内容作为参数化测试入参 |
| @MethodSource | 表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流) |
当然如果参数化测试仅仅只能做到指定普通的入参还达不到让我觉得惊艳的地步。真正强大之处在于他可以支持外部的各类入参。如:CSV,YML,JSON 文件甚至方法的返回值也可以作为入参。只需要去实现 ArgumentsProvider 接口,任何外部文件都可以作为它的入参。
@ParameterizedTest @DisplayName("参数化测试") @ValueSource(ints = {1,2,3,4,5,6}) void testParameterize(int i){ System.out.println(i); } @ParameterizedTest @DisplayName("参数化测试") @MethodSource("stringProvider")// 方法名 void testParameterize(String i){ System.out.println(i); } static Stream<String> stringProvider(){ return Stream.of("apple","bannana","atguigu"); }
8. ❤️👌SpringBoot 专栏前文回顾
- 【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
- 【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
- 【SpringBoot(三)】从请求到响应再到视图解析与模板引擎,本文带你领悟SpringBoot请求接收全流程!
9. 💕👉 其他好文推荐
- 还不了解Git分布式版本控制器?本文将带你全面了解并掌握
- 带你认识Maven的依赖、继承和聚合都是什么!有什么用?
- 2-3树思想与红黑树的实现与基本原理
- 全网最全!ElasticSearch8.7 搭配 SpringDataElasticSearch5.1 的使用
- 全面深入Java GC!!带你完全了解 GC垃圾回收机制!!
- 全面了解Java的内存模型(JMM)!详细清晰!
- 在JVM中,类是如何被加载的呢?本篇文章就带你认识类加载的一套流程!
- 带你了解Go语言的判断语句、切片和映射表!!
- (Java并发编程—JUC)带你重新认识进程与线程!!让你深层次了解线程运行的睡眠与打断!!
- JUC:从JMM内存模型的角度来分析CAS并发性问题
- 常见的设计模式概念分析与多把锁使用场景!!理解线程状态转换条件!带你深入JUC!!
- JUC:共享问题解决与synchronized对象锁分析!