Spring注解
1. @SpringBootApplication
注解
@SpringBootApplication
注解默认加载主类上,可以把他看作是@Configuration
、@EnableAutoConfiguration
、@ComponentScan
注解的集合。
- @Configuration:允许在 Spring 上下文中注册额外的 bean 或导入其他配置类
- @ComponentScan:扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描该类所在的包下所有的类。
- @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制
其中
@EnableAutoConfiguration
的自动装配机制:该注解的Import注解导入了名为自动配置导入选择器的配置类(AutoConfigurationImportSelector),自动装配导入选择器的selectImports方法中获取配置实例方法getAutoConfigurationEntry里,会有一个获取候选配置方法(getCandidateConfigurations),有一个断言,表明选择器会从spring-boot-autoconfigure-2.1.5.RELEASE.jar包的META-INF目录下的spring,factories配置文件里获取到所有的候选配置,包括springboot内置的tomcat,事务等批量的自动装配,简化了很多繁琐的配置。
2 Spring Bean相关注解
2.1 @Autowired
注解
自动导入对象到类,被Spring容器管理
@Service
public class UserService {
......
}
@RestController
@RequestMapping("\users")
public class UserController {
@Autowired
private UserService userService;
......
}
2.2 @Component
,@Repository
,@Service
, @Controller
注解
如果想要使用@Autowire
注解导入对象到指定类,就需要使用注解来标识被引入类,可以使用一下注解:
- @Component:通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注。
- @Repository:对应持久层即 Dao 层,主要用于数据库相关操作。
- @Service:对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。
- @Controller:对应 Spring MVC 控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。
2.3 @RestController
和Controller
注解
- @RestController:是
@Controller
和@ResponseBody
两个注解的合集,只返回对象对象数据直接以 JSON 或 XML 形式写入 HTTP 响应(Response)中,这种情况属于 RESTful Web服务,这也是目前日常开发所接触的最常用的情况(前后端分离) - @Controller:返回一个页面,可以使用Thymeleaf 模板引擎进行渲染
2.4 @Scope
注解
声明 Spring Bean 的作用域,使用方法:
@Bean
@Scope("singleton")
public Person personSingleton() {
return new Person();
}
四种常见的 Spring Bean 的作用域:
- singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
- prototype : 每次请求都会创建一个新的 bean 实例。
- request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
- session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
3 HTTP请求
- @GetMapping :请求从服务器获取特定资源。举个例子:GET \users(获取所有学生)
- @PostMapping :在服务器上创建一个新的资源。举个例子:POST \users(创建学生)
- @PutMapping :更新服务器上的资源(客户端提供更新后的整个资源)。举个例子:PUT \users\12(更新编号为 12 的学生)
- @DeleteMapping :从服务器删除特定的资源。举个例子:DELETE \users\12(删除编号为 12 的学生)
- @PatchMapping :更新服务器上的资源(客户端提供更改的属性,可以看做作是部分更新),使用的比较少,这里就不举例子了。
相当于
@RequestMapping(value="\users\{userId}",method=RequestMethod.*)
4 前后端传值
4.1 @PathVariable
和 @RequestParam
注解
@PathVariable
用于获取路径参数,@RequestParam
用于获取查询参数。
@GetMapping("\klasses\{klassId}\teachers")
public List<Teacher> getKlassRelatedTeachers(
@PathVariable("klassId") Long klassId,
@RequestParam(value = "type", required = false) String type ) {
...
}
如果只有@RequestParam String type 的话,则参数type默认必传
4.2 @RequestBody
注解
用于读取 Request 请求(可能是 POST,PUT,DELETE,GET 请求)的 body 部分并且Content-Type 为 application\json 格式的数据,接收到数据之后会自动将数据绑定到 Java 对象上去。
系统会使用HttpMessageConverter或者自定义的HttpMessageConverter将请求的 body 中的 json 字符串转换为 java 对象。
5 读取配置信息
很多时候我们需要将一些常用的配置信息比如阿里云 oss、发送短信、微信认证的相关配置信息等等放到配置文件中。
application.yml
文件如下:
wuhan2020: 2020年初武汉爆发了新型冠状病毒,疫情严重,但是,我相信一切都会过去!武汉加油!中国加油!
my-profile:
name: name
email: xx@163.com
library:
location: 湖北武汉加油中国加油
email:xx@163.com
books:
- name: 天才基本法
description: 描述1
- name: 时间的秩序
description: 描述2
- name: 了不起的我
description: 描述3
5.1 @value
(常用)
@Value("${wuhan2020}")
String wuhan2020;
需要注意的是@value这种方式是不被推荐的,Spring 比较建议的是下面几种读取配置信息的方式。
5.2 @ConfigurationProperties
(常用)
@Component
\\ 没有加@Component注解则需要在主类上加@EnableConfigurationProperties({LibraryProperties.class})
@Data
@ConfigurationProperties(prefix = "library")
@Validated \\ 校验需要加此注解,校验失败则启动报错
class LibraryProperties {
@NotEmpty
private String location;
@Email
@NotEmpty
private String email;
private List<Book> books;
@Data
static class Book {
String name;
String description;
}
......
}
加上
@Component
注解后可以像Bean一样引入使用
5.3 PropertySource
(不常用)
@PropertySource
读取指定 properties 文件
@Component
@PropertySource("classpath:website.properties")
@Data
class WebSite {
@Value("${url}")
private String url;
......
}
5.4 题外话:配置文件读取优先级
其中如果有集成spring-cloud-config配置中心的话,则优先级最高的是配置中心的配置文件
6 参数校验
不止前端需要对数据进行初步校验,为了防止绕过浏览器直接访问接口的请求(含有违法\恶意的数据),后端也需要对参数进行校验
JSR(Java Specification Requests) 是一套 JavaBean 参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们 JavaBean 的属性上面,这样就可以在需要校验的时候进行校验了,非常方便!
SpringBoot 项目的 spring-boot-starter-web 依赖中已经有 hibernate-validator 包,不需要引用相关依赖。
校验的时候我们实际用的是 Hibernate Validator 框架。
6.1. 一些常用的字段验证的注解
JSR提供的校验注解:
@Null
被注释的元素必须为 null@NotNull
被注释的元素必须不为 null@AssertTrue
被注释的元素必须为 true@AssertFalse
被注释的元素必须为 false@Pattern(regex=,flag=)
被注释的元素必须符合指定的正则表达式@Min(value)
被注释的元素必须是一个数字,其值必须大于等于指定的最小值@Max(value)
被注释的元素必须是一个数字,其值必须小于等于指定的最大值@DecimalMin(value)
被注释的元素必须是一个数字,其值必须大于等于指定的最小值@DecimalMax(value)
被注释的元素必须是一个数字,其值必须小于等于指定的最大值@Size(max=, min=)
被注释的元素的大小必须在指定的范围内@Digits(integer, fraction)
被注释的元素必须是一个数字,其值必须在可接受的范围内@Past
被注释的元素必须是一个过去的日期@Future
被注释的元素必须是一个将来的日期
例子:
@Pattern(regexp=”^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,10}$", message=”密码必须是6~10位数字和字母的组合
private String password;
Hibernate Validator提供的校验注解:
@NotBlank(message =)
验证字符串非null,且长度必须大于0@NotEmpty
被注释的字符串的必须非空@Email
被注释的元素必须是电子邮箱地址@Length(min=,max=)
被注释的字符串的大小必须在指定的范围内@Range(min=,max=,message=)
被注释的元素必须在合适的范围内
Controller层在需要校验的接口参数上加上@Valid,类上加上@Validate注解,如果校验失败它将抛出MethodArgumentNotValidException
的异常
@RestController
@RequestMapping("\api")
@Validate
public class PersonController {
\** PS: @RequestBody不加的话就通过url的方式拼接在后面**\
@PostMapping("\person")
public ResponseEntity<Person> getPerson(@RequestBody @Valid Person person) {
return ResponseEntity.ok().body(person);
}
}
7 全局异常处理
- 1:
@ControllerAdvice
:注解定义全局异常处理类 - 2:
@ExceptionHandler
:注解声明异常处理方法
可以对抛出的异常进行捕获并且进行友好返回等处理
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
\**
* 请求参数异常处理
*\
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, HttpServletRequest request) {
......
}
}
8 JPA相关(数据持久层)
8.1 创建表
@Entity
声明一个类对应一个数据库实体(实体类)@Table(name = "table_name")
声明表的名称
@Entity
@Table(name = "role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
省略getter\setter......
}
8.2 创建主键
@Id
声明一个字段为主键。@GeneratedValue
直接使用 JPA 内置提供的四种主键生成策略来指定主键生成策略。
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
一般使用 MySQL 数据库的话,使用GenerationType.IDENTITY策略比较普遍一点(分布式系统的话需要另外考虑使用分布式 ID)
拓展:@GeneratedValue注解
8.3 设置字段类型
@Column
声明字段。
示例:
设置属性 userName 对应的数据库字段名为 user_name,长度为 32,非空
@Column(name = "user_name", nullable = false, length=32)
private String userName;
设置字段类型并且加默认值,这个还是挺常用的。
Column(columnDefinition = "tinyint(1) default 1")
private Boolean enabled;
8.4 指定不持久化特定字段
@Transient
:声明不需要与数据库映射的字段,在保存的时候不需要保存进数据库 。
8.5 声明大字段
@Lob
:声明某个字段为大字段。@Column(length = 10000000)
也可
更详细的声明:
@Lob
\\指定 Lob 类型数据的获取策略, FetchType.EAGER 表示非延迟 加载,而 FetchType. LAZY 表示延迟加载 ;
@Basic(fetch = FetchType.EAGER)
\\columnDefinition 属性指定数据表对应的 Lob 字段类型
@Column(name = "content", columnDefinition = "LONGTEXT NOT NULL")
private String content;
8.6 创建枚举类型的字段
可以使用枚举类型的字段,不过枚举字段要用@Enumerated
注解修饰。
public enum Gender {
MALE("男性"),
FEMALE("女性");
private String value;
Gender(String str){
value=str;
}
}
@Entity
@Data
@Table(name = "role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
@Enumerated(EnumType.STRING)
private Gender gender;
}
8.7 增加审计功能
只要继承了 AbstractAuditBase
的类都会默认加上下面四个字段。
@Data
@AllArgsConstructor
@NoArgsConstructor
@MappedSuperclass
@EntityListeners(value = AuditingEntityListener.class)
public abstract class AbstractAuditBase {
@CreatedDate
@Column(updatable = false)
@JsonIgnore
private Instant createdAt;
@LastModifiedDate
@JsonIgnore
private Instant updatedAt;
@CreatedBy
@Column(updatable = false)
@JsonIgnore
private String createdBy;
@LastModifiedBy
@JsonIgnore
private String updatedBy;
}
我们对应的审计功能对应地配置类可能是下面这样的(Spring Security 项目):
@Configuration
@EnableJpaAuditing
public class AuditSecurityConfiguration {
@Bean
AuditorAware<String> auditorAware() {
return () -> Optional.ofNullable(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication)
.filter(Authentication::isAuthenticated)
.map(Authentication::getName);
}
}
简单介绍一下上面设计到的一些注解:
@CreatedDate
: 表示该字段为创建时间时间字段,在这个实体被 insert 的时候,会设置值@CreatedBy
:表示该字段为创建人,在这个实体被 insert 的时候,会设置值@LastModifiedDate、@LastModifiedBy
同理。@EnableJpaAuditing
:开启 JPA 审计功能。
数据库里面对应存储的是 MAIL\FEMAIL。
9 事务 @Transactional
@Transactional
注解一般用在可以作用在类或者方法上。
- 作用于类:当把
@Transactional
注解放在类上时,表示所有该类的public 方法都配置相同的事务属性信息。 - 作用于方法:当类配置了
@Transactional
,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息。
事务管理主要分为两种:编程式事务
和 声明式事务
- 编程式事务:使用事务代码来手动commit和rollback,代码侵入性比较强
@Autowired
private DataSourceTransactionManager transactionManager;
public void doSomething(){
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(definition);
try{
...
transactionManager.commit(status);
}catch(Exception e){
transactionManager.rollback(status);
}
}
- 声明式事务:基于AOP面向切面的,它将具体业务与事务处理部分解耦,代码侵入性很低
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
public void doSomething(){
...
}
默认使用@Transactional
注解的话,事务传播为Propagation.REQUIRED
,rollback为RuntimeException.class
一般POST请求(新增修改删除)则事务传播使用Propagation.REQUIRED
,GET请求事务传播使用Propagation.SUPPORTS
10 Json解析
10.1. 过滤 json 数据
@JsonIgnoreProperties 作用在类上用于过滤掉特定字段不返回或者不解析。
\\生成json时将userRoles属性过滤
@JsonIgnoreProperties({"userRoles"})
public class User {
private String userName;
private String fullName;
private String password;
@JsonIgnore
private List<UserRole> userRoles = new ArrayList<>();
}
@JsonIgnore一般用于类的属性上,作用和上面的@JsonIgnoreProperties 一样。
public class User {
private String userName;
private String fullName;
private String password;
\\生成json时将userRoles属性过滤
@JsonIgnore
private List<UserRole> userRoles = new ArrayList<>();
}
10.2. 格式化 json 数据
@JsonFormat一般用来格式化 json 数据。
比如:
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone="GMT")
private Date date;
10.3. 扁平化对象 - @JsonUnwrapped
@Getter
@Setter
@ToString
public class Account {
@JsonUnwrapped
private Location location;
@JsonUnwrapped
private PersonInfo personInfo;
@Getter
@Setter
@ToString
public static class Location {
private String provinceName;
private String countyName;
}
@Getter
@Setter
@ToString
public static class PersonInfo {
private String userName;
private String fullName;
}
}
未扁平化之前:
{
"location": {
"provinceName":"湖北",
"countyName":"武汉"
},
"personInfo": {
"userName": "coder1234",
"fullName": "shaungkou"
}
}
使用@JsonUnwrapped 扁平对象之后:
@Getter
@Setter
@ToString
public class Account {
@JsonUnwrapped
private Location location;
@JsonUnwrapped
private PersonInfo personInfo;
......
}
{
"provinceName":"湖北",
"countyName":"武汉",
"userName": "coder1234",
"fullName": "shaungkou"
}
参考链接:
1:Spring\Spring常用注解总结!- JavaGuide
2:@RestController vs @Controller
3:SpringBoot 如何优雅读取配置文件
4:如何在 Spring\Spring Boot 中做参数校验
5:Spring 事务管理详解