一、springboot常用注解
参考:SpringBoot之常用注解 - Nihaorz - 博客园 (cnblogs.com)
配置类
@SpringBootApplication
是一个复合注解,包含了@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan这三个注解。这三个注解的作用分别为:
- @SpringBootConfiguration:标注当前类是配置类,这个注解继承自@Configuration。并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到srping容器中,并且实例名就是方法名。
- @EnableAutoConfiguration:是自动配置的注解,这个注解会根据我们添加的组件jar来完成一些默认配置,我们做微服务时会添加spring-boot-starter-web这个组件jar的pom依赖,这样配置会默认配置springmvc 和tomcat。
- @ComponentScan:扫描当前包及其子包下被@Component,@Controller,@Service,@Repository注解标记的类并纳入到spring容器中进行管理。等价于context:component-scan的xml配置文件中的配置项。
@ServletComponentScan
Servlet、Filter、Listener 可以直接通过 @WebServlet、@WebFilter、@WebListener 注解自动注册,这样通过注解servlet ,拦截器,监听器的功能而无需其他配置,所以这次相中使用到了filter的实现,用到了这个注解。
@MapperScan
spring-boot支持mybatis组件的一个注解,通过此注解指定mybatis接口类的路径,即可完成对mybatis接口的扫描。添加mybatis相应组建依赖之后。就可以使用该注解。
它和@mapper注解是一样的作用,不同的地方是扫描入口不一样。@mapper需要加在每一个mapper接口类上面。所以大多数情况下,都是在规划好工程目录之后,通过@MapperScan注解配置路径完成mapper接口的注入。
@ComponentScan
表示该类将自动发现扫描组件。如果扫描到有@Component、@Controller、@Service等这些注解的类,并注册为Bean,可以自动收集所有的Spring组件,包括@Configuration类。
我们经常使用@ComponentScan注解搜索beans,并结合@Autowired注解导入。可以自动收集所有的Spring组件,包括@Configuration类。
如果没有配置的话,Spring Boot会扫描启动类所在包下以及子包下的使用了@Service,@Repository等注解的类。
@ImportResource @Import @PropertySource
这三个注解都是用来导入自定义的一些配置文件。
@ImportResource(locations={}) ,导入其他xml配置文件,需要标准在主配置类上。
@PropertySource,导入property的配置文件,指定文件路径,这个相当于使用spring的标签来完成配置项的引入。
@import注解,是一个可以将普通类导入到spring容器中做管理
@Value
为变量注入Spring boot的application.properties配置文件中定义的属性的值。
controller层
@Controller
表明这个类是一个控制器类,和@RequestMapping来配合使用拦截请求,如果不在method中注明请求的方式,默认是拦截get和post请求。这样请求会完成后转向一个视图解析器。但是在大多微服务搭建的时候,前后端会做分离。所以请求后端只关注数据处理,后端返回json数据的话,需要配合@ResponseBody注解来完成。
这样一个只需要返回数据的接口就需要3个注解来完成,大多情况我们都是需要返回数据。也是基于最佳实践,所以将这三个注解进一步整合。
@RestController
是@Controller 和@ResponseBody的结合,一个类被加上@RestController 注解,数据接口中就不再需要添加@ResponseBody。更加简洁。
@RequestMapping
使用@RequestMapping(value=“”,method= RequestMethod.GET ),我们都需要明确请求方式。 该注解有六个属性:
- params :指定request中必须包含某些参数值是,才让该方法处理。
- headers :指定request中必须包含某些指定的header值,才能让该方法处理请求。
- value :指定请求的实际地址,指定的地址可以是URI Template 模式
- method :指定请求的method类型, GET、POST、PUT、DELETE等
- consumes :指定处理请求的提交内容类型(Content-Type),如application/json,text/html;
- produces :指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回
这样的写法又会显得比较繁琐,于是乎就有了如下的几个注解,目的是为了代码的更加简洁。
@GetMapping/@PostMapping
普通风格 | Rest风格 |
---|---|
@RequestMapping(value=“”,method = RequestMethod.GET) | @GetMapping(value =“”) |
@RequestMapping(value=“”,method = RequestMethod.POST) | @PostMapping(value =“”) |
@RequestMapping(value=“”,method = RequestMethod.PUT) | @PutMapping(value =“”) |
@RequestMapping(value=“”,method = RequestMethod.DELETE) | @DeleteMapping(value =“”) |
@CrossOrigin
@CrossOrigin(origins = “”, maxAge = 1000) 这个注解主要是为了解决跨域访问的问题。这个注解可以为整个controller配置启用跨域,也可以在方法级别启用。
我们在项目中使用这个注解是为了解决微服在做定时任务调度编排的时候,会访问不同的spider节点而出现跨域问题。
@Autowired
这是个最熟悉的注解,是spring的自动装配,这个个注解可以用到构造器,变量域,方法,注解类型上。当我们需要从bean 工厂中获取一个bean时,Spring会自动为我们装配该bean中标记为@Autowired的元素。
@Qualifier
当有多个同一类型的Bean时,可以用@Qualifier(“name”)来指定,例如同一个接口有多个实现类。通常与@Autowired配合使用。
@EnableCaching
这个注解是spring framework中的注解驱动的缓存管理功能。自spring版本3.1起加入了该注解。其作用相当于spring配置文件中的cache manager标签。
@PathVariable
路径变量注解,@RequestMapping中用{}来定义url部分的变量名,方法中则使用@PathVariable(变量名)来获取url中实际传入的值。
@RequestParam
用在方法的参数前面。
servcie层
@Service
这个注解用来标记业务层的组件,我们会将业务逻辑处理的类都会加上这个注解交给spring容器。事务的切面也会配置在这一层。当然这个注解不是一定要用。有个泛指组件的注解@Component,当我们不能确定具体作用的时候可以用泛指组件的注解托付给spring容器。
@Resource
@Resource和@Autowired一样都可以用来装配bean,都可以标注字段上,或者方法上。 @resource注解不是spring提供的,是属于J2EE规范的注解。
两者在匹配方式上有点不同,@Resource默认按照名称方式进行bean匹配,@Autowired默认按照类型方式进行bean匹配。
@EnableScheduling
开启定时任务功能。
@Scheduled
按指定执行周期执行方法。
@Schedules
包含多个@Scheduled,可同时运行多个周期配置。
@EnableAsync
开启方法异步执行的能力,通过@Async或者自定义注解找到需要异步执行的方法。通过实现AsyncConfigurer接口的getAsyncExecutor()和getAsyncUncaughtExceptionHandler()方法自定义Executor和异常处理。
@Async
标记方法为异步线程中执行。
持久层
@Repository
@Repository注解类作为DAO对象,管理操作数据库的对象。
总的来看,@Component, @Service, @Controller, @Repository是spring注解,注解后可以被spring框架所扫描并注入到spring容器来进行管理。
@Component
@Component是通用注解,其他三个注解是这个注解的拓展,并且具有了特定的功能。
通过这些注解的分层管理,就能将请求处理、业务逻辑处理、数据库操作处理分离出来,为代码解耦,也方便了以后项目的维护和开发。
所以我们在正常开发中,如果能用@Service、@Controller、@Repository其中一个标注这个类的定位的时候,就不要用@Component来标注。
@Transactional
通过这个注解可以声明事务,可以添加在类上或者方法上。
在spring boot中 不用再单独配置事务管理,一般情况是我们会在servcie层添加了事务注解,即可开启事务。要注意的是,事务的开启只能在public 方法上。并且主要事务切面的回滚条件。正常我们配置rollbackfor exception时 ,如果在方法里捕获了异常就会导致事务切面配置的失效。
二、mapper接口向sql传参方式
xxxxMapper.java,需要调用xml中的sql脚本,其通常位于资源文件夹下的xxxxMapper.xml 文件中。传参主要有以下几种方式:
- @Param 注解
在接口的参数上添加注解,在内部指定传递给 xml 的参数名,对应的 xml 文件中的 sql 使用相同的参数名来实现参数绑定。
- Map 传参
如果参数并不是简单类型而是 Map 类型时,在 xml 文件中的参数,可以直接使用 map 中对应的 key 来指代。
- POJO 对象
另外一种常见的 case 是传参为简单的实体对象,这个时候 xml 中的参数也可以直接使用对象的 fieldName 来指代,和 map 的使用方式差不多。
- 简单参数 + Map 参数
当参数有多个,其中部分为简单类型,部分为 Map时,简单类型遵循上面的规则,同时,map 参数的传参使用前缀 + “.” + key 的方式。
三、API调用时传参
GET方式
- 无参数(略)
- url中传参
如:
http://127.0.0.1:8081/user/queryUserByID?userId=2
在controller中,我们可以用以下2中方式接收参数:
(1)不使用注解,直接在方法的参数列表中指定参数名,如:public User queryUserByID(int userId)
(2)使用@RequestParam注解,如:public User queryUserByID(@RequestParam(“userId”) int uId)
POST方式
方法上使用PostMapping注解,表示这个方法只能接收post请求;
绝大多数场景下,我们使用JSON来从前台向后台传递表单数据等。当前台通过POST的方式传递一个JSON时,后台通常使用@RequestBody来处理:
- 用Map接收
import java.util.Map;
//这里仅显示该方法所在部分,类定义未显示
@PostMapping("/user/queryUserByName")
public User queryUserByName(@RequestBody Map<String,String> params) {
String name = params.get("name");
User user = userMapper.queryUserByName(name);
return user;
}
- 用bean接收
此时需注意:
(1)JSON中的参数名必须跟bean中的变量名一致;
(2)bean中对于该变量,有get和set方法;
@PostMapping("/user/queryUserByName2")
public User queryUserByName2(@RequestBody User usr) {
User user = userMapper.queryUserByName(usr.getUsername());
return user;
}
四、改项目启动banner
将需要的banner,保存到banner.txt文件中,放在resources目录下即可
这里提供了几个在线生成banner的网址:
https://www.bootschool.net/ascii
http://www.network-science.de/ascii/
http://patorjk.com/software/taag/
http://www.degraeve.com/img2txt.php
五、sprint boot单元测试框架
框架介绍
Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库。作为最新版本的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: 由于JUint已经发展多年,为了照顾老的项目,JUnit Vintage提供了兼容JUnit4.x,Junit3.x的测试引擎。(SpringBoot 2.4 以上版本移除了默认对 Vintage 的依赖。如果需要兼容junit4需要自行引入)
参考:(15条消息) Junit5+Mockito单元测试详解_junit5 mock_感冒的方便面的博客-CSDN博客
Junit5常用注解
@Test 表示方法是测试方法。但是与JUnit4的@Test不同,其的职责非常单一不能声明任何属性,拓展的测试将会由Jupiter提供额外测试
@ParameterizedTest 表示方法是参数化测试,下方会有详细介绍
@RepeatedTest 表示方法可重复执行,下方会有详细介绍
@DisplayName 为测试类或者测试方法设置展示名称
@BeforeEach 表示在每个单元测试之前执行
@AfterEach 表示在每个单元测试之后执行
@BeforeAll 表示在所有单元测试之前执行
@AfterAll 表示在所有单元测试之后执行
@Tag 表示单元测试类别,类似于JUnit4中的@Categories
@Disabled 表示测试类或测试方法不执行,类似于JUnit4中的@Ignore
@Timeout 表示测试方法运行如果超过了指定时间将会返回错误
@ExtendWith 为测试类或测试方法提供扩展类引用
断言
方法 说明
assertEquals 判断两个对象或两个原始类型是否相等
assertNotEquals 判断两个对象或两个原始类型是否不相等
assertSame 判断两个对象引用是否指向同一个对象
assertNotSame 判断两个对象引用是否指向不同的对象
assertTrue 判断给定的布尔值是否为 true
assertFalse 判断给定的布尔值是否为 false
assertNull 判断给定的对象引用是否为 null
assertNotNull 判断给定的对象引用是否不为 null
参数化测试
参数化测试是JUnit5很重要的一个新特性,它使得用不同的参数多次运行测试成为了可能,也为我们的单元测试带来许多便利。
利用@ValueSource等注解,指定入参,我们将可以使用不同的参数进行多次单元测试,而不需要每新增一个参数就新增一个单元测试,省去了很多冗余代码。
@ValueSource: 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型
@NullSource: 表示为参数化测试提供一个null的入参
@EnumSource: 表示为参数化测试提供一个枚举入参
@CsvFileSource:表示读取指定CSV文件内容作为参数化测试入参
@MethodSource:表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)
六、mockito模拟测试
在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。 在具体的测试过程中,我们经常会碰到需要模拟数据或者接口的情况,因为环境问题或者系统复杂度的问题,我们需要使用 Mock 方式进行数据的模拟。
Mockito是一种Java测试框架,主要用来模拟任何Spring管理的bean,模拟方法的返回,抛出异常等。目前在Java中主流的测试工具有Mockito, JMock, easyMock等,springboot目前内建的是Mockito。它允许你用模拟对象来替换你的系统的部分,并对它们已使用的方式进行断言。
应用场景
- 对象信息难构建:在测试过程中,需要第三方接口返回特定的数据以符合特定的测试场景,这种情况往往需要跨条线的沟通协调测试数据,成本高,效率低;利用Mock可以自定义返回测试结果,支持手动构造依赖接口的返回值。
- 依赖的接口尚未开发完成:依赖接口性能参数无法保障。在对接口性能压测的时候,需要下游接口及时返回数据,满足上游接口的调用 频度。在依赖接口多的情况下,如何减轻工作量?
- 异常场景(连接异常、超时异常等):当需要测试接口一些异常数据,接口正常情况是否无法提供异常数据的。那么如何简便地构造接口的异常数据.
给 Mock 对象打桩(when语句)
真实对象有自己的行为;mock对象没有。于是拿到输入后,真实对象有输出,mock对象没有输出。为了让mock对象模拟真实对象,就要给mock对象一个输出。
这就要用到when语句。when语句常用的4种类型:
- when(mockObject.methodA(input1)).thenReturn(output1)
意思是当mock对象的方法A遇到输入input1时,输出将是output1。
- when(mockObject.methodA(input1)).thenReturn(output1).thenReturn(output2)
意思是mock对象的某一方法第一次调用时,返回值为output1;第二次及更多次调用时,返回值为output2。
- when(mockObject.methodA(input1)).thenThrow(output1)
当调用mock对象的方法A时,抛出一个异常。
例如,when(mock.someMethod(“some arg”)).thenThrow(new RuntimeException());
- doRetrun(output).when(mockObject).methodA(input)
意思是当调用mock对象的方法A时,返回output。
MockMvc使用
(15条消息) SpringBoot 实战:JUnit5+MockMvc+Mockito 做好单元测试_栗少的博客-CSDN博客
常用API
//mockMvc.perform 表示执行一个请求
mockMvc.perform(MockMvcRequestBuilders
.get("/xxx") //构造一个请求
// 设置返回值类型为utf-8,否则默认为ISO-8859-1
.accept(MediaType.APPLICATION_JSON_UTF8)
.param("xxx", "xxx"))//添加请求传值
//ResultActions.andExpect 添加执行完成后的断言,验证控制器执行完成后结果是否正确
.andExpect(MockMvcResultMatchers.status().isOk())//验证状态码是否正确
.andExpect(MockMvcResultMatchers.content().string("xxx"))//验证输出内容是否一致
.andDo(MockMvcResultHandlers.print());