功能分析
1、静态资源访问
1、静态资源目录
只要静态资源放在类路径下: called /static
(or /public
or /resources
or /META-INF/resources
访问 : 当前项目根路径/ + 静态资源名
原理: 静态映射/**。
请求进来,先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器。静态资源也找不到则响应404页面
改变默认的静态资源路径
spring:
mvc:
static-path-pattern: /res/**
resources:
static-locations: [classpath:/haha/]
2、静态资源访问前缀
默认无前缀
spring:
mvc:
static-path-pattern: /res/**
当前项目 + static-path-pattern + 静态资源名 = 静态资源文件夹下找
3、webjar
自动映射 /webjars/**
https://www.webjars.org/
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.5.1</version>
</dependency>
访问地址:http://localhost:8080/webjars/jquery/3.5.1/jquery.js 后面地址要按照依赖里面的包路径
2.静态资源配置原理
- SpringBoot启动默认加载 xxxAutoConfiguration 类(自动配置类)
- SpringMVC功能的自动配置类 WebMvcAutoConfiguration,生效
spring:
# mvc:
# static-path-pattern: /res/**
resources:
add-mappings: false 禁用所有静态资源规则
3、请求参数处理
1.请求映射
1、rest使用与原理
Rest风格支持(使用HTTP请求方式动词来表示对资源的操作)
Rest原理(表单提交要使用REST的时候)
- 表单提交需要带上**_method=PUT**
-
请求过来被HiddenHttpMethodFilter拦截
# 默认是false,需要开启 @Bean @ConditionalOnMissingBean(HiddenHttpMethodFilter.class) @ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false) public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() { return new OrderedHiddenHttpMethodFilter(); }
-
spring: mvc: hiddenmethod: filter: enabled: true #开启页面表单的Rest功能
-
- 请求是否正常,并且是POST
-
-
- 获取到**_method**的值。
- 兼容以下请求;PUT.DELETE.PATCH
- 原生request(post),包装模式requesWrapper重写了getMethod方法,返回的是传入的值。
- 过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requesWrapper的。
-
修改默认的_method
//自定义filter
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
methodFilter.setMethodParam("_m");
return methodFilter;
}
2、请求映射原理
SpringMVC功能分析都从 org.springframework.web.servlet.DispatcherServlet-》doDispatch()
protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
throws Exception {
HandlerExecutionChain mappedHandler = null;
、、、
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 找到当前请求使用哪个Handler(Controller的方法)处理
mappedHandler = getHandler(processedRequest);
//HandlerMapping:处理器映射。/xxx->>xxxx
RequestMappingHandlerMapping:保存了所有@RequestMapping 和handler的映射规则。
2.普通参数与基本注解
// car/2/owner/zhangsan
@GetMapping("/car/{id}/owner/{username}")
public Map<String,Object> getCar(@PathVariable("id") Integer id,
@PathVariable("username") String name,
@PathVariable Map<String,String> pv,){
}
# @PathVariable Map<String,String> pv, 用来存放所有的键值对,
#@PathVariable、@RequestParam、@RequestHeader 都可用map接受,意为全部
@RequestAttribute 获取request域属性
@MatrixVariable 矩阵变量
//1、语法: 请求路径:/cars/sell;low=34;brand=byd,audi,yd (以分号分隔,可以是kv,也可以是数组)
//2.使用场景:cookie禁用了,可以通过矩阵变量方式传递jsessionid。
//2、SpringBoot默认是禁用了矩阵变量的功能
// 手动开启:原理。对于路径的处理。UrlPathHelper进行解析。
// removeSemicolonContent(移除分号内容)支持矩阵变量
//3、矩阵变量必须有url路径变量才能被解析
@GetMapping("/cars/{path}")
public Map carsSell(@MatrixVariable("low") Integer low,
@MatrixVariable("brand") List<String> brand,
@PathVariable("path") String path){
Map<String,Object> map = new HashMap<>();
map.put("low",low);
map.put("brand",brand);
map.put("path",path);
return map;
}
// /boss/1;age=20/2;age=10
// pathVar 代表获取那个路径下的值
@GetMapping("/boss/{bossId}/{empId}")
public Map boss(@MatrixVariable(value = "age",pathVar = "bossId") Integer bossAge,
@MatrixVariable(value = "age",pathVar = "empId") Integer empAge){
Map<String,Object> map = new HashMap<>();
map.put("bossAge",bossAge);
map.put("empAge",empAge);
return map;
}
配置类:
3.复杂参数
Map、**Model(map、model里面的数据会被放在request的请求域 request.setAttribute)、**Errors/BindingResult、RedirectAttributes( 重定向携带数据)、ServletResponse(response)
4.拦截器
1.HandlerInterceptor 接口
package com.atxins.practicedemo.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* @author Axin
* @since 2021/9/5 22:18
* 1.配置好拦截器拦截那些请求
* 2.把这些配置放在容器中
* 3.拦截器执行步骤,preHandle->目标方法->postHandle->afterCompletion
*/
public class LoginInterceptor implements HandlerInterceptor {
/**
* 目标方法执行之前
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
Object user = session.getAttribute("loginUser");
if (user != null) {
//放行
return true;
}
request.setAttribute("msg","请先登录");
//拦截住,转发到登录页
request.getRequestDispatcher("/").forward(request,response);
return false;
}
/**
* 目标方法执行完成后
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
/**
* 页面渲染以后
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
2.配置拦截器
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
//所有请求都被拦截包括静态资源
.addPathPatterns("/**")
//放行的请求
.excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**");
}
}
3、拦截器原理
5、文件上传
1.文件上传代码
@PostMapping("/upload")
public String upload(@RequestParam("email") String email,
@RequestParam("username") String username,
@RequestPart("headerImg") MultipartFile headerImg,
@RequestPart("photos") MultipartFile[] photos) throws IOException {
if(!headerImg.isEmpty()){
//保存到磁盘
String originalFilename = headerImg.getOriginalFilename();
headerImg.transferTo(new File("H:\\cache\\"+originalFilename));
}
if(photos.length > 0){
for (MultipartFile photo : photos) {
if(!photo.isEmpty()){
String originalFilename = photo.getOriginalFilename();
photo.transferTo(new File("H:\\cache\\"+originalFilename));
}
}
}
return "main";
}
2.文件大小限制
spring:
servlet:
multipart:
//单个文件最大限制
max-file-size: 10MB
//所有文件总的限制
max-request-size: 100MB
6、全局异常处理器
spring boot 默认情况下会映射到 /error 进行异常处理,但是提示并不十分友好,下面自定义异常处理,提供友好展示。
@RestControllerAdvice +@ExceptionHandler 实现拦截异常并统一处理
/**
* controller 增强器
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 全局异常捕捉处理
* @param ex
* @return
*/
@ExceptionHandler(value = Exception.class)
public Map errorHandler(Exception ex) {
Map map = new HashMap();
map.put("code", 100);
map.put("msg", ex.getMessage());
return map;
}
/**
* 拦截捕捉自定义异常 MyException.class
* @param ex
* @return
*/
@ExceptionHandler(value = MyException.class)
public Map myErrorHandler(MyException ex) {
Map map = new HashMap();
map.put("code", ex.getCode());
map.put("msg", ex.getMsg());
return map;
}
}
public class MyException extends RuntimeException {
public MyException(String code, String msg) {
this.code = code;
this.msg = msg;
}
private String code;
private String msg;
// getter & setter
}
@RestControllerAdvice是一个组合注解,由@ControllerAdvice、@ResponseBody组成,而@ControllerAdvice继承了@Component,因此@RestControllerAdvice本质上是个Component,用于定义@ExceptionHandler,@InitBinder和@ModelAttribute方法,适用于所有使用@RequestMapping方法。
@ControllerAdvice
public class GlobalController{
//(1)全局数据绑定
//应用到所有@RequestMapping注解方法
//此处将键值对添加到全局,注解了@RequestMapping的方法都可以获得此键值对
@ModelAttribute
public void addUser(Model model) {
model.addAttribute("msg", "此处将键值对添加到全局,注解了@RequestMapping的方法都可以获得此键值对");
}
//(2)全局数据预处理
//应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
//用来设置WebDataBinder
@InitBinder("user")
public void initBinder(WebDataBinder binder) {
}
// (3)全局异常处理
//应用到所有@RequestMapping注解的方法,在其抛出Exception异常时执行
//定义全局异常处理,value属性可以过滤拦截指定异常,此处拦截所有的Exception
@ExceptionHandler(Exception.class)
@ResponseBody
public String handleException(Exception e) {
return "error";
}
}
@ModelAttribute:在Model上设置的值,对于所有被 @RequestMapping 注解的方法中,都可以通过 ModelMap 获取,如下:
@RequestMapping("/home")
public String home(ModelMap modelMap) {
System.out.println(modelMap.get("author"));
}
//或者 通过@ModelAttribute获取
@RequestMapping("/home")
public String home(@ModelAttribute("author") String author) {
System.out.println(author);
}
7、Web原生组件注入(Servlet、Filter、Listener)
1.使用Servlet API
@WebServlet、@WebFilter、@WebListener +@ServletComponentScan
//urlPatterns = "/my" 处理的路径,效果:直接响应,没有经过Spring的拦截器
@WebServlet(urlPatterns = "/my")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("666");
}
}
//拦截静态资源路径
@WebFilter(urlPatterns = {"/css/*","/images/*"})
@Slf4j
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("MyFilter初始化完成");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("MyFilter工作");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
log.info("MyFilter销毁");
}
}
@WebListener
@Slf4j
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContextListener.super.contextInitialized(sce);
log.info("MyServletContextListener监听到项目初始化完成");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
log.info("MyServletContextListener监听到项目销毁");
}
}
//主启动类标注@ServletComponentScan注解,指定原生Servlet组件都放在那里
@SpringBootApplication
@ServletComponentScan
public class PracticeDemoApplication {
public static void main(String[] args) {
SpringApplication.run(PracticeDemoApplication.class, args);
}
}
2.使用RegistrationBean
ServletRegistrationBean
, FilterRegistrationBean
, and ServletListenerRegistrationBean
@Configuration
public class MyRegistConfig {
@Bean
public ServletRegistrationBean myServlet(){
MyServlet myServlet = new MyServlet();
return new ServletRegistrationBean(myServlet,"/my","/my02");
}
@Bean
public FilterRegistrationBean myFilter(){
MyFilter myFilter = new MyFilter();
// return new FilterRegistrationBean(myFilter,myServlet());
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean myListener(){
MySwervletContextListener mySwervletContextListener = new MySwervletContextListener();
return new ServletListenerRegistrationBean(mySwervletContextListener);
}
}
@WebServlet(urlPatterns = “/my”),为什么没有经过Spring的拦截器?
对于多个Servlet都能处理到同一层路径,根据精确优选匹配原则
A: /
B: /my/
B会执行,会由原生的servlet(Tomcat处理),而只有由DispatcherServlet(Spring)处理的请求才会经过spring的拦截器。
执行顺序:监听器>filter>自定义servlet>dispatchServlet(springMvc)
8、定制化原理
1.定制化的常见方式
- 修改配置文件;
- xxxxxCustomizer(定制化器,可以改变xxxx的默认规则);
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;
@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
@Override
public void customize(ConfigurableServletWebServerFactory server) {
server.setPort(9000);
}
}
- 编写自定义的配置类 xxxConfiguration;+@Bean替换、增加容器中默认组件;
- Web应用 编写一个配置类实现WebMvcConfigurer 即可定制化web功能;+ @Bean给容器中再扩展一些组件
@Configuration
public class AdminWebConfig implements WebMvcConfigurer
-
@EnableWebMvc + WebMvcConfigurer —— @Bean 可以全面接管SpringMVC,所有规则全部自己重新配置,实现定制和扩展功能;
原理:
- WebMvcAutoConfiguration 默认的SpringMVC的自动配置功能类。静态资源、欢迎页…
- 一旦使用 @EnableWebMvc ,会 @Import(DelegatingWebMvcConfiguration.class)
- DelegatingWebMvcConfiguration 的 作用,只保证SpringMVC最基本的使用
- 把所有系统中的 WebMvcConfigurer 拿过来。所有功能的定制都是这些 WebMvcConfigurer 合起来一起生效
- 自动配置了一些非常底层的组件。RequestMappingHandlerMapping、这些组件依赖的组件都是从容器中获取
- public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
- WebMvcAutoConfiguration 类上有注解,@ConditionalOnMissingBean(WebMvcConfigurationSupport.class),@EnableWebMvc 会导致了 WebMvcAutoConfiguration 没有生效。
2.原理分析套路
场景starter - >xxxxAutoConfiguration -> 导入xxx组件 -> 绑定xxxProperties – 绑定配置文件项
9、SpringBoot整合MyBatis-Plus
1.MyBatis-Plus
整合:
-
引入mybatis-plus-boot-starter
-
引入mybatis-plus后,mybatis-spring-boot-starter无需再引,构成的依赖都包含了
-
mapperLocations 自动配置好的。有默认值。
classpath*:/mapper/**/*.xml
;类路
径下的所有mapper文件夹下任意路径下的所有xml都是sql映射文件。
-
- 配置appHcation.yaml中,可做一些全局配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
- @MapperScan(“com.atguigu.admin.mapper”)会批量扫描@Mapper标注的接口,接口就可以不用标注@Mapper注解
自动配置:
- MybatisPlusAutoConfiguration 配置类, MybatisPlusProperties 配置项绑定配置文件前缀为mybatis-plus,xxx就是对mybatis-plus的定制
- SqISessionFactory 自动配置好,底层是容器中默认的数据源
- 容器中也自动配置好了 SqISessionTemplate
- @Mapper标注的接口也会被自动扫描
**优点:**只需要我们的Mapper继承 BaseMapper 就可以拥有crud能力
2.mybatis
- 导入mybatis官方starter
- 在application.yaml中指定Mapper配置文件的位置,以及指定全局配置文件的信息 (建议;配置在mybatis.configuration)
# 配置mybatis规则
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml
configuration:
map-underscore-to-camel-case: true #匹配驼峰命名
- 简单方法直接注解方式
- 复杂方法编写mapper.xml进行绑定映射
@Mapper
public interface CityMapper {
@Select("select *from city where id=#{id}")
public City getById( Long id);
}
3.MyBatis-Plus分页使用
分页插件
@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor();
// 数据库类型
paginationInterceptor.setDbType(DbType.POSTGRE_SQL);
// 溢出总页数后是否进行处理
paginationInterceptor.setOverflow(false);
//数据库类型
interceptor.addInnerInterceptor(paginationInterceptor);
// 防止全表更新与删除插件
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
}
controller:
@ApiOperation(value = "分页查询老师信息")
@GetMapping("/pageTeacher/{current}/{limit}")
public R pageListTeacher(
@ApiParam(name = "current", value = "当前页", required = true) @PathVariable long current,
@ApiParam(name = "limit", value = "每页记录数", required = true)@PathVariable long limit){
Page<EduTeacher> page = new Page<>(current, limit);
// 把分页结果封装到 page 对象中
teacherService.page(page, null);
return R.ok().data("total", page.getTotal()).data("rows", page.getRecords());
}
springboot~@ConditionalOnMissingBean注解的作用
10、SpringBoot整合redis
1.redis的自动配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot- starter-data-redis</artifactId>
</dependency>
自动配置:
- RedisAutoConfiguration 自动配置类。RedisProperties 属性类 --> spring.redis.xxx是对redis
的配置 - 连接工厂是准备好的。导入了LettuceConnectionConfiguration、JedisConnectionConfiguration配置类
- 自动注入了RedisTemplate<Object, Object> : xxxTemplate;
- 自动注入了StringRedisTemplate; k: v都是String
- 底层只要我们使用 StringRedisTemplate、RedisTemplate就可以操作redis
redis环境搭建:
- 阿里云搜索redis,立即购买
- 阿里云按量付费redis、经典网络、读写分离板
- 申请redis的公网连接地址
- 修改白名单 允许0.0.0.0/0 访问,即允许所有机器访问
- 可以分配账号
- 用完后进行资源释放
2.RedisTemplate与Lettuce
spring:
# redis 配置
redis:
host: law.internal.gridsumdissector.com
port: 34490
# 数据库索引
database: 0
# 密码
password: Zsydian88
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池中的最小空闲连接
min-idle: 0
# 连接池中的最大空闲连接
max-idle: 8
# 连接池的最大数据库连接数
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
@Test
void testRedis() {
redisTemplate.opsForValue().set("hello","world");
String hello = redisTemplate.opsForValue().get("hello");
System.out.println(hello);
}
3.切换至jedis
<!--导入jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
spring:
# redis 配置
redis:
host: law.internal.gridsumdissector.com
port: 34490
# 数据库索引
database: 0
# 密码
password: Zsydian88
client-type: jedis
jedis:
pool:
# 连接池的最大数据库连接数
max-active: 8
4.使用redis统计接口访问次数
@Component
public class RedisUrlCountInterceptor implements HandlerInterceptor {
@Resource
StringRedisTemplate stringRedisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String url = String.valueOf(request.getRequestURL());
//默认每次访问当前url就会计数+1
stringRedisTemplate.opsForValue().increment(url);
return true;
}
}
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
/**
* Filter、Interceptor的区别:
* 1、Filter是Servlet定义的原生组件。好处,脱离Spring应用也能使用
* 2、Interceptor是Spring定义的接口。可以使用Spring的自动装配等功能
*/
@Autowired
RedisUrlCountInterceptor urlCountInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//直接new,自动注入stringRedisTemplate不会生效,因为只有容器的中组件Spring才会解析
//registry.addInterceptor(new RedisUrlCountInterceptor());
//从容器中拿
registry.addInterceptor(urlCountInterceptor)
.addPathPatterns("/**")
// 放行静态资源
.excludePathPatterns("/css/**","/js/**","/images/**","/html/**");
}
}
//获取接口访问次数
@Test
void testGetUrlCount(){
String s = stringRedisTemplate.opsForValue().get("/addOrUpdateTag");
System.out.println(Long.parseLong(s));
}
11、单元测试
1.JUnit5 的变化
Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库
JUnit 5由三个不同子项目的几个不同模块组成。
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
JUnit Platform: Junit Platform是在JVM上启动测试框架的基础,不仅支持Junit自制的测试引擎,其他测试引擎也都可以接入。
JUnit Jupiter: JUnit jupiter提供了JUnit5的新的编程模型,是jUnit5新特性的核心。内部包含了一个测试引擎,用于在junit Platform上运行。
JUnit Vintage: 由于JUint已经发展多年,为了照顾老的项目,JUnit Vintage提供了兼容JUnit4.x,Junit3.x的测试引擎。
<dependency>
< groupId >org.springframework.boot </groupId >
< artifactId > spring- boot -starter-test </artifactId >
< scope>test </scope>
</dependency>
注意:
SpringBoot 2.4以上版本移除了默认对 Vintage 的依赖。如果需要兼容junit4需要自行引入
<dependency>
< gnoupId >org.junit.vintage</groupId >
< antifactld >junit-vintage-engine</artifactld >
< scope>test </scope>
<exclusions>
< exclusion>
< groupId >org.hamcrest </groupId >
< artifactId > hamcrest-core</artifactId >
</exclusion >
</exclusions>
</dependency>
@SpringBootTest
class Boot05WebAdminApplicationTests {
@Test
void contextLoads(){
}
}
以前:
@SpringBootTest + @RunWith(SpringTest.class)
SpringBoot整合junit以后。
- 编写测试方法:@Test标注(注意需要使用junit5版本的注解)
- Junit类具有Spring的功能, @Autowired、比如 @Transactional 标注测试方法,测试完成后自
动回滚
2.JUnit5常用注解
https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations
@Test:表示方法是测试方法。但是与JUnit4的@Test不同,他的职责非常单一不能声明任何属性,拓展的测试将会由jupiter提供额外测试
@ParameterizedTest:表示方法是参数化测试
@RepeatedTest :表示方法可重复执行
@DisplayName:为测试类或者测试方法设置展示名称
@BeforeEach:表示在每个单元测试之前执行
@AfterEach:表示在每个单元测试之后执行
@BeforeAII:表示在所有单元测试之前执行
@AfterAII:表示在所有单元测试之后执行
@Tag:表示单元测试类别,类似于JUnit4中的@Categories
@Disabled:表示测试类或测试方法不执行,类似于JUnit4中的@lgnore
@Timeout:表示测试方法运行如果超过了指定时间将会返回错误
@ExtendWith:为测试类或测试方法提供扩展类引用
import org.junit.jupiter.api.Test; //注意这里使用的是jupiter的Test注解!!
@DisplayName( "JUnit5的功能测试类")
public class TestDemo {
@Test
@DisplayName( "第一次测试")
public void firstTest() {
System.out.printIn("hello world");
}
// 规定方法超时时间。超出时间测试出异常
@Timeout(value = 500,unit = TimeUnit.MILLISECONDS)
@Test
void testTimeout() throws InterruptedException {
Thread.sleep( millis: 600);
}
}
//@BootstrapWith(SpringBootTestContextBootstrapper.class)
//@ExtendWith(SpringExtension.class)
@SpringBootTest //包含上面两个注解
public class TestDemo {
@Test
public void firstTest() {
System.out.printIn("hello world");
}
3.断言(assertions)
简单断言
方法 | 说明 |
---|---|
assertEquals | 判断两个对象或两个原始类型是否相等 |
assertNotEquals | 判断两个对象或两个原始类型是否不相等 |
assertSame | 判断两个对象弓I用是否指向同一个对象 |
assertNotSame | 判断两个对象弓I用是否指向不同的对象 |
assertTrue | 判断给定的布尔值是否为 true |
assertFalse | 判断给定的布尔值是否为 false |
assertNull | 判断给定的对象弓I用是否为 null |
assertNotNull | 判断给定的对象引用是否不为 null |
数组断言
组合断言
assertAII 方法接受多个 org.junit.jupiter.api.Executable 函数式接口的实例作为要验证的断言,可以通过 lambda 表达式很容易的提供这些断言
异常断言
超时断言
快速失败
4.前置条件(assumptions)
JUnit 5 中的前置条件 (assumptions【假设】) 类似于断言,不同之处在于不满足的断言会使得测试方法失败,而不满足的前置条件只会使得测试方法的执行终止。前置条件可以看成是测试方法执行的前提,当该前提不满足时,就没有继续执行的必要。
5.嵌套测试
JUnit 5 可以通过 java 中的内部类和@Nested 注解实现嵌套测试,从而可以更好的把相关的测试方法组织在一起。在内部类中可以使用@BeforeEach 和@AfterEach 注解,而且嵌套的层次没有限制。
6.参数化测试
@ValueSource: 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型
@Nu11Source: 表示为参数化测试提供一个nu11的入参
@EnumSource: 表示为参数化测试提供一个枚举入参
@CsvFileSource: 表示读取指定CSV文件内容作为参数化测试入参
@MethodSource: 表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)
12、Profile功能
1.pplication-profile功能
-
默认配置文件 application.yaml; 任何时候都会加载
-
指定环境配置文件 application-{env}.yaml
-
激活指定环境
- 通过配置文件激活,在application.yml中
Spring: profiles: active: prod
- 命令行激活:java -jar xxx.jar -spring.profiles.active=prod —person.name=haha
- 修改配置文件的任意值,命令行优先
-
默认配置与环境配置同时生效
-
同名配置项,profile配置优先
2.@Profile条件装配功能
@Profile标注在类上
public interface Person {
String getName();
Integer getAge();
}
@Profile("prod")
@Data
@Component
@ConfigurationProperties("person")
public class Boss implements Person{
private String name;
private Integer age;
}
@Profile("test")
@Data
@Component
@ConfigurationProperties("person")
public class Worker implements Person{
private String name;
private Integer age;
}
若当前环境是test,则Worker对象生效,若当前环境是prod,则Boss对象生效。
@Profile标注在方法上,指定的环境,对应的方法组件会生效
@Configuration
public class MyConfig {
@Profile("test")
@Bean
public Color red(){
return Color.RED;
}
@Profile("prod")
@Bean
public Color blue(){
return Color.BLUE;
}
}
3.profile分组
spring.profiles.group.production[0]=proddb
spring.profiles.group.production[l]=prodmq
使用: spring,profiles.active=production 激活
4.外部化配置
- 外部配置源
常用:Java properties 文件、YAML文件、环境变量、命令行参数;
(环境变量、命令行参数):系统环境变量,java -jar xxx.jar --spring.application.name=xxx
@Value("MAVEN_HOME")
private String msg;
@SpringBootApplication
public class SupervisionApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(SupervisionApplication.class, args);
ConfigurableEnvironment environment = run.getEnvironment();
//系统的环境变量
Map<String, Object> systemEnvironment = environment.getSystemEnvironment();
//系统的属性
Map<String, Object> systemProperties = environment.getSystemProperties();
System.out.println(systemEnvironment);
System.out.println(systemProperties);
}
}
- 配置文件查找位置(后面的可以覆盖前面的同名配置项)
Core Features (spring.io)Core Features (spring.io)
(1) classpath 根路径(源码包标识的都叫,java、resource)
(2) classpath 根路径下config目录
(3) jar包当前目录
⑷ jar包当前目录的config目录
(5) /config子目录的直接子目录(在linux系统下验证)
- 配置文件加载顺序(指定环境优先,外部优先,后面的可以覆盖前面的同名配置项)
- 当前jar包内部的的application.properties和application.yml
- 当前jar包内部的的application-{profile}.properties 和 application-{profile}.yml
- 引用的外部jar包的application.properties和application.ym
- 引用的外部jar包的application-{profile}.properties 和 application-{profile}.yml