设计的目标
为所有使用 Spring 的开发者提供一个更简单,快速的入门体验
提供一些常见的功能、如监控、WEB容器,健康,安全等功能
干掉XML,遵循规范,开箱即用
Spring Initializr(官方的构建插件,需要联网)
常用配置详解 1 2 3 4 5 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-configuration-processor</artifactId > <optional > true</optional > </dependency >
提供配置项自动提示功能。
自定义配置文件
定义一个名为 my2.properties 的资源文件,自定义配置文件的命名不强制 application 开头
1 2 3 my2.age=22 my2.name=Levin my2.email=1837307557 @qq .com
其次定义 MyProperties2.java 文件,用来映射我们在 my2.properties 中的内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package com.battcn.properties;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.PropertySource;import org.springframework.stereotype.Component;@Component @PropertySource("classpath:my2.properties") @ConfigurationProperties(prefix = "my2") public class MyProperties2 { private int age; private String name; private String email; @Override public String toString () { return "MyProperties2{" + "age=" + age + ", name='" + name + '\'' + ", email='" + email + '\'' + '}' ; } }
接下来在 PropertiesController 用来注入 MyProperties2 测试我们编写的代码
1 2 3 4 5 6 7 @GetMapping("/2") public MyProperties2 myProperties2 () { log.info("=================================================================================================" ); log.info(myProperties2.toString()); log.info("=================================================================================================" ); return myProperties2; }
多环境化配置 在真实的应用中,常常会有多个环境(如:开发,测试,生产等 ),不同的环境数据库连接都不一样,这个时候就需要用到spring.profile.active 的强大功能了,它的格式为 application-{profile}.properties,这里的 application 为前缀不能改,{profile} 是我们自己定义的。
创建application-dev.properties、application-test.properties、application-prod.properties,内容分别如下
application-dev.properties
1 server.servlet.context-path=/dev
application-test.properties
1 server.servlet.context-path=/test
application-prod.properties
1 server.servlet.context-path=/prod
在application.properties 配置文件中写入 spring.profiles.active=dev,这个时候我们在次访问 http://localhost:8080/properties/1 就没用处了,因为我们设置了它的context-path=/dev,所以新的路径就是 http://localhost:8080/dev/properties/1 ,由此可以看出来我们激活不同的配置读取的属性值是不一样的
外部命令引导
前面三种方式都是基于配置文件层面的,那么有没有办法外部引导呢,假设这样的场景,我们对已经开发完成的代码打包发布,期间在测试环境测试通过了,那么即可发布上生产,这个时候是修改application.properties的配置方便还是直接在命令参数配置 方便呢,毫无疑问是后者更有说服力。默认情况下,SpringApplication 会将命令行选项参数(即:–property,如–server.port=9000)添加到Environment,命令行属性始终优先于其他属性源 。
java -jar chapter2-0.0.1-SNAPSHOT.jar --spring.profiles.active=test --my1.age=32
数据验证 简单验证 导入依赖
在pom.xml 中添加上 spring-boot-starter-web 的依赖即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-validation</artifactId > </dependency > </dependencies >
注意,在2.6以后 validation 相关jar需要单独引入,不在web-starter中依赖。
JSR-303 注释介绍
这里只列举了 javax.validation 包下的注解,同理在 spring-boot-starter-web 包中也存在 hibernate-validator 验证包,里面包含了一些 javax.validation 没有的注解,有兴趣的可以看看
注解
说明
@NotNull
限制必须不为null
@NotEmpty
验证注解的元素值不为 null 且不为空(字符串长度不为0、集合大小不为0)
@NotBlank
验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Pattern(value)
限制必须符合指定的正则表达式
@Size(max,min)
限制字符长度必须在 min 到 max 之间(也可以用在集合上)
@Email
验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式
@Max(value)
限制必须为一个不大于指定值的数字
@Min(value)
限制必须为一个不小于指定值的数字
@DecimalMax(value)
限制必须为一个不大于指定值的数字
@DecimalMin(value)
限制必须为一个不小于指定值的数字
@Null
限制只能为null(很少用)
@AssertFalse
限制必须为false (很少用)
@AssertTrue
限制必须为true (很少用)
@Past
限制必须是一个过去的日期
@Future
限制必须是一个将来的日期
@Digits(integer,fraction)
限制必须为一个小数,且整数部分的位数不能超过 integer,小数部分的位数不能超过 fraction (很少用)
实体类
为了体现 validation 的强大,分别演示普通参数属性验证与对象的验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package com.battcn.pojo;import org.hibernate.validator.constraints.Length;import javax.validation.constraints.DecimalMin;import javax.validation.constraints.NotBlank;import javax.validation.constraints.NotNull;import java.math.BigDecimal;public class Book { private Integer id; @NotBlank(message = "name 不允许为空") @Length(min = 2, max = 10, message = "name 长度必须在 {min} - {max} 之间") private String name; @NotNull(message = "price 不允许为空") @DecimalMin(value = "0.1", message = "价格不能低于 {value}") private BigDecimal price; }
控制层
与前面的代码相比,新的代码中仅仅多了几个注解而已。(此处只是为了图方便写在了 Controller 层,同理你可以将它作用在 Service 层)
注解介绍
@Validated: 开启数据有效性校验,添加在类上即为验证方法,添加在方法参数中即为验证参数对象。(添加在方法上无效)
@NotBlank: 被注释的字符串不允许为空(value.trim() >` 0 ? true : false)
@Length: 被注释的字符串的大小必须在指定的范围内
@NotNull: 被注释的字段不允许为空(value != null ? true : false)
@DecimalMin: 被注释的字段必须大于或等于指定的数值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package com.battcn.controller;import com.battcn.pojo.Book;import org.hibernate.validator.constraints.Length;import org.springframework.validation.annotation.Validated;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import javax.validation.constraints.NotBlank;@Validated @RestController public class ValidateController { @GetMapping("/test2") public String test2 (@NotBlank(message = "name 不能为空") @Length(min = 2, max = 10, message = "name 长度必须在 {min} - {max} 之间") String name) { return "success" ; } @GetMapping("/test3") public String test3 (@Validated Book book) { return "success" ; } }
主函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.battcn;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication public class Chapter18Application { public static void main (String[] args) { SpringApplication.run(Chapter18Application.class, args); } }
在pom.xml 中添加上 spring-boot-starter-web 的依赖即可
1 2 3 4 5 6 7 8 9 10 11 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > </dependencies >
自定义注解(自定义验证) 这里定义了一个 @DateTime 注解,在该注解上标注了 @Constraint 注解,它的作用就是指定一个具体的校验器类
关键字段(强制性)
message: 验证失败提示的消息内容
groups: 为约束指定验证组(非常不错的一个功能,下一章介绍)
payload: 不太清楚(欢迎留言交流)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package com.battcn.annotation;import com.battcn.validator.DateTimeValidator;import javax.validation.Constraint;import javax.validation.Payload;import java.lang.annotation.Retention;import java.lang.annotation.Target;import static java.lang.annotation.ElementType.FIELD;import static java.lang.annotation.ElementType.PARAMETER;import static java.lang.annotation.RetentionPolicy.RUNTIME;@Target({FIELD, PARAMETER}) @Retention(RUNTIME) @Constraint(validatedBy = DateTimeValidator.class) public @interface DateTime { String message () default "格式错误" ; String format () default "yyyy-MM-dd" ; Class<?>[] groups() default {}; Class<? extends Payload >[] payload() default {}; }
具体验证
定义校验器类 DateTimeValidator 实现 ConstraintValidator 接口,实现接口后需要实现它里面的 initialize: 与 isValid: 方法。
方法介绍
initialize: 主要用于初始化,它可以获得当前注解的所有属性
isValid: 进行约束验证的主体方法,其中 value 就是验证参数的具体实例,context 代表约束执行的上下文环境。
这里的验证方式虽然简单,但职责明确;为空验证可以使用 @NotBlank、@NotNull、@NotEmpty 等注解来进行控制,而不是在一个注解中做各种各样的规则判断,应该职责分离
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package com.battcn.validator;import com.battcn.annotation.DateTime;import javax.validation.ConstraintValidator;import javax.validation.ConstraintValidatorContext;import java.text.ParseException;import java.text.SimpleDateFormat;public class DateTimeValidator implements ConstraintValidator <DateTime, String> { private DateTime dateTime; @Override public void initialize (DateTime dateTime) { this .dateTime = dateTime; } @Override public boolean isValid (String value, ConstraintValidatorContext context) { if (value == null ) { return true ; } String format = dateTime.format(); if (value.length() != format.length()) { return false ; } SimpleDateFormat simpleDateFormat = new SimpleDateFormat (format); try { simpleDateFormat.parse(value); } catch (ParseException e) { return false ; } return true ; } }
控制层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.battcn.controller;import com.battcn.annotation.DateTime;import org.springframework.validation.annotation.Validated;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;@Validated @RestController public class ValidateController { @GetMapping("/test") public String test (@DateTime(message = "您输入的格式错误,正确的格式为:{format}", format = "yyyy-MM-dd HH:mm") String date) { return "success" ; } }
主函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.battcn;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication public class Chapter19Application { public static void main (String[] args) { SpringApplication.run(Chapter19Application.class, args); } }
分组验证 定义一个验证组,里面写上不同的空接口类即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.battcn.groups;public class Groups { public interface Update { } public interface Default { } }
实体类
groups 属性的作用就让 @Validated 注解只验证与自身 value 属性相匹配的字段,可多个,只要满足就会去纳入验证范围; 我们都知道针对新增的数据我们并不需要验证 ID 是否存在,我们只在做修改操作的时候需要用到,因此这里将 ID 字段归纳到 Groups.Update.class 中去,而其它字段是不论新增还是修改都需要用到所以归纳到 Groups.Default.class 中…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.battcn.pojo;import com.battcn.groups.Groups;import javax.validation.constraints.NotBlank;import javax.validation.constraints.NotNull;import java.math.BigDecimal;public class Book { @NotNull(message = "id 不能为空", groups = Groups.Update.class) private Integer id; @NotBlank(message = "name 不允许为空", groups = Groups.Default.class) private String name; @NotNull(message = "price 不允许为空", groups = Groups.Default.class) private BigDecimal price; }
控制层
创建一个 ValidateController 类,然后定义好 insert、update 俩个方法,比由于 insert 方法并不关心 ID 字段,所以这里 @Validated 的 value 属性写成 Groups.Default.class 就可以了;而 update 方法需要去验证 ID 是否为空,所以此处 @Validated 注解的 value 属性值就要写成 Groups.Default.class, Groups.Update.class;代表只要是这分组下的都需要进行数据有效性校验操作…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.battcn.controller;import com.battcn.groups.Groups;import com.battcn.pojo.Book;import org.springframework.validation.annotation.Validated;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;@RestController public class ValidateController { @GetMapping("/insert") public String insert (@Validated(value = Groups.Default.class) Book book) { return "insert" ; } @GetMapping("/update") public String update (@Validated(value = {Groups.Default.class, Groups.Update.class}) Book book) { return "update" ; } }
主函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.battcn;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication public class Chapter20Application { public static void main (String[] args) { SpringApplication.run(Chapter20Application.class, args); } }