Spring Boot 注解有哪些?
- 了解常见的注解以及使用的层级
- 了解注解的含义
Spring Boot项目的层级关系以及相关注解
entity层
entity层为数据库实体层,一般一个实体类对应数据库中的一张数据表,类中的属性与数据表中的字段一 一对应。默认情况下,类名即为数据表的表名,属性名则是对应字段名,字段类型也与变量的类型相对应。
@Entity
该注解用于表明这个类是一个实体类,会给他生成一张对应的数据表。
@Table(name = “table_name”)
该注解主要用于修改表名,name的值就是修改的数据表的名称。
@Id
该注解用于声明主键,标在哪个属性上面对应的哪个字段就是主键
@GeneratedValue(strategy = GenerationType.IDENTITY)
该注解的strategy属性主要用于设置主键的增长方式,IDENTITY表示主键由数据库自己生成,从1开始单调递增。
@Column(name = “column_name”)
该注解的name属性用于更改数据表的列名,如果不想用默认的就用这个属性改吧
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
这个注解得上是本项目得核心了,它声明了实体之间的多对多关系,使两张数据表关联关联起来,一般是通过生成一张映射表来实现这种映射关系。关于上面的cascade属性和fetch属性,有兴趣的读者可以查资料了解。
@JoinTable
这个注解是配套@ManyToMany使用的,一般在多对多关系的维护端标注,用于生成上面提到的映射表。一般该注解常用三个属性:name属性表示生成的数据表的名称,joinColumns属性表示关系维护端的主键,inverseJoinColumns则表示关系被维护端的主键。关于嵌套在里面的@JoinColumn注解,在这里主要用于配置映射表的外键,一般有两个属性:name用于配置外键在映射表中的名称,referencedColumnName 用于表明外键在原表中的字段名称。
@JsonBackReference
关于这个注解,建议先去掉试试然后再加上,对比一下效果。它主要可以使标注属性避免被json序列化,进而避免多对多关系的查询中出现死循环的情况。但是加上了这注解后,就不能进行反向查询了(也就是说不能利用权限名查询拥有这个权限的角色了)
@Data
lombok包提供的工具类,可以自动生成setter和getter等方法。
在eclipse中使用lombok需要安装lombok插件。->官网<-
@ConfigurationProperties(prefix=“键的上一级前缀”)
用于注入配置文件中设置的值。
@EnableConfigurationProperties(Xxx.class)
与上面的注解相关,表示启用配置属性的注入,用在自定义Bean注入属性。需要注意的是使用了该注解就不需要在自定义bean的类中使用注入Bean的注解了,如:@Component
repository
也可以称dao层,或mapper层,是数据持久层。主要负责访问数据库,向数据库发送SQL语句,完成基础的增删查改任务。主要通过定义继承JpaRepository类的接口来实现,<>中填写的是实体类的名称和该实体主键的变量类型。
service
service层是业务逻辑层,主要通过调用持久层的接口,接收持久层返回的数据,完成项目的基本功能设计。
controller
controller层是控制层,其功能为请求和响应控制,负责前后端交互,接受前端请求,调用service层,接收service层返回的数据,最后返回具体的页面和数据到客户端。
Spring通过提供@Autowired注解来提供基于注解的自动装配。
自动装配指的就是使用将 Spring 容器中的 bean 自动的和我们需要这个 bean 的类组装在一起。
@Controller
处理http请求
@RestController
返回json(相当于@ResponseBody配合@Controller)
@RequestMapping
配置url映射(可传入数组,Crtl+P查看)
@PathVariable
获取url中的数据
@RequestParam
获取请求参数的值
其它注解
标注一个类为Spring容器的Bean,(把普通pojo实例化到spring容器中,相当于配置文件中的)
1 2 3 4 5 6 7 8 9
| <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>org.eclipse.persistence.jpa</artifactId> <version>2.6.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
|

基于SpringBoot的SSMP整合案例

图书管理系统

Mybatis plus提供的快速开发方案
- Dao层继承
BaseMapper类
,可以实现快速通用数据层方法。
- Servcie层实现
IService<T>接口
并继承ServiceImpl<M,T>类
,可以实现快速通用业务层方法。


Bean属性校验
JSR303规范
导入坐标
1 2 3 4
| <dependency> <groupId>jakarta.validation</groupId> <artifactId>jakarta.validation-api</artifactId> </dependency>
|
1 2 3 4
| <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> </dependency>
|
使用方法
@Validated 在对应类上使用,用于开启数据格式校验
具体的校验规则,用于字段的注解:
@Max()
@Min()…

补充 使用yaml配置的数字格式问题
yml格式的文件中配置整数,支持二进制、八进制、十六进制的书写方式。如果单纯使用十进制以字符串形式接受的话,建议使用双引号括起来
!
测试
加载测试临时属性应用于小范围的测试环境
属性测试
@SpringBootTest注解中可以使用properties参数
1 2 3 4 5 6 7 8 9
| @SpringBootTest(properties = {"test.prop=test1"}) class SpringBootProjectApplicationTests { @Value("${test.prop}") private String prop; @Test void testProperties() { System.out.println("prop = "+ prop); } }
|
还可以使用args参数
1 2 3 4 5 6 7 8 9
| @SpringBootTest(args = {"--test.prop=test2"}) class SpringBootProjectApplicationTests { @Value("${test.prop}") private String prop; @Test void testProperties() { System.out.println("prop = "+ prop); } }
|
!!! note 优先级关系
args命令行参数形式>properties临时属性配置>配置文件
1 2 3 4 5 6 7 8 9 10
| @SpringBootTest(properties = {"test.prop=test1"}, args = {"--test.prop=test2"}) class SpringBootProjectApplicationTests { @Value("${test.prop}") private String prop; @Test void testProperties() { System.out.println("prop = "+ prop); } }
|
外部bean测试
在测试中需要使用额外的Bean,这时如何进行测试?
在测试目录下新建一个需要导入的配置类,类中加载需要使用的第三方Bean。(此处为了方便直接使用String作为外部Bean)
1 2 3 4 5 6 7 8 9 10
| package com.lptexas.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MsgConfig { @Bean public String msg() { return "msg config."; } }
|
进行测试
@Import注解,将新建的第三方Bean配置类导入。(如果配置类运行在测试程序的同目录下
或子目录下
可以省略这个注解也生效)
1 2 3 4 5 6 7 8 9 10
| @SpringBootTest @Import(MsgConfig.class) public class TestMsgConfig { @Autowired private String msg; @Test void testMsg() { System.out.println("msg = "+msg); } }
|
Web环境测试
导入坐标
直接修改原本的spring-boot-starter就行
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
|
准备一个Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package com.lptexas.controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
@RestController @RequestMapping("/books") public class BookController {
@GetMapping public String test() { System.out.println("Get Mapping Running..."); return "Get Mapping Running"; } }
|
启动环境模拟
@SpringBootTest提供webEnvironment参数用于配置web环境
1 2 3 4 5 6 7
| @SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT) public class TestWeb { @Test void test() {
} }
|

启动虚拟MVC调用
@AutoConfigureMockMvc 开启虚拟MVC调用
1 2 3 4 5 6 7 8 9 10 11 12 13
| @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc public class TestWeb { @Test void test(@Autowired MockMvc mvc) throws Exception { MockHttpServletRequestBuilder builder=MockMvcRequestBuilders.get("/books"); mvc.perform(builder); } }
|
虚拟请求匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc public class TestWeb { @Test void test(@Autowired MockMvc mvc) throws Exception { MockHttpServletRequestBuilder builder=MockMvcRequestBuilders.get("/books"); ResultActions action = mvc.perform(builder); StatusResultMatchers status=MockMvcResultMatchers.status(); ResultMatcher ok=status.isOk(); action.andExpect(ok); } }
|
虚拟请求内容匹配
String型的返回值(实际不会用到)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc public class TestWeb { @Test void test(@Autowired MockMvc mvc) throws Exception { MockHttpServletRequestBuilder builder=MockMvcRequestBuilders.get("/books"); ResultActions action = mvc.perform(builder); ContentResultMatchers content=MockMvcResultMatchers.content(); ResultMatcher result=content.string(""); action.andExpect(result); } }
|
Json格式的内容
准备一个Book实体类
1 2 3 4 5 6 7
| @Data public class Book { private Integer id; private String name; private String type; private String description; }
|
修改一下Controller
1 2 3 4 5 6 7 8 9 10 11
| @RestController @RequestMapping("/books") public class BookController { @GetMapping public Book getById(Book book) { book.setId(1); book.setName("TestBook"); book.setType("TestType"); return book; } }
|
单元测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc public class TestWeb { @Test void test(@Autowired MockMvc mvc) throws Exception { MockHttpServletRequestBuilder builder=MockMvcRequestBuilders.get("/books"); ResultActions action = mvc.perform(builder); ContentResultMatchers ctt=MockMvcResultMatchers.content(); ResultMatcher res=ctt.json("{\"id\":1,\"name\":\"TestBook\",\"type\":\"TestType\"}"); action.andExpect(res); } }
|
如果要测试错误的结果,需要修改Controller
1 2 3 4 5
| @GetMapping public String test() { System.out.println("Get Mapping Running..."); return "TestWeb"; }
|
单元测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Test void testHeaderType(@Autowired MockMvc mvc) throws Exception { MockHttpServletRequestBuilder builder=MockMvcRequestBuilders.get("/books"); ResultActions action = mvc.perform(builder); HeaderResultMatchers header=MockMvcResultMatchers.header(); ResultMatcher res=header.string("content-type", "application/json"); action.andExpect(res); }
|
业务层测试数据回滚
即,不希望测试的时候在数据库中产生数据。
模拟连接数据库的环境
导入坐标
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.2</version> </dependency>
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.8</version> </dependency>
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
|
application.yml 主配置文件
1 2 3 4 5 6 7
| spring: datasource: druid: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.31.5:3306/managerSys username: root password: root
|
Book实体类(用上面创建的那个即可)
BookDao.java 数据层
1 2 3
| @Mapper public interface BookDao extends BaseMapper<Book>{ }
|
BookService.java 服务层接口
1 2 3
| public interface BookService { boolean save(Book book); }
|
BookService.java 服务层实现
1 2 3 4 5 6 7 8 9 10
| @Service public class BookServiceImpl implements BookService { @Autowired private BookDao bookDao;
@Override public boolean save(Book book) { return bookDao.insert(book) > 0; } }
|
BookController.java 控制层
1 2 3
| @Mapper public interface BookDao extends BaseMapper<Book>{ }
|
为测试用例添加事务
@Transactional注解 SpringBoot会对用力对应的事务提交操作进行回滚
@Rollback(true) 可以设置是否穷回滚,默认为true
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @SpringBootTest @Transactional @Rollback(false) public class TestService {
@Autowired private BookService bookService; @Test void testSave() { Book book=new Book(); book.setName("TestBook"); book.setType("TestType"); book.setDescription("TestDescription"); bookService.save(book); } }
|
测试用例使用随机数据
application.yaml 配置文件

1 2 3 4 5 6 7
| test: book: id: ${random.int(100)} type: ${random.int(10,20)} uuid: ${random.uuid} name: ${random.value} publishTime: ${random.long}
|
需要创建一个数据模型与之对应
1 2 3 4 5 6 7 8 9 10
| @Component @Data @ConfigurationProperties(prefix = "test.book") public class BookCase { private int id; private int type; private String uuid; private String name; private long publishTime; }
|
单元测试
1 2 3 4 5 6
| @Autowired private BookCase bookCase; @Test void testBookCase() { System.out.println(bookCase); }
|