【开发篇】二、属性绑定与校验

文章目录

  • 1、@ConfigurationProperties自定义Bean属性绑定
  • 2、@EnableConfigurationProperties注解
  • 3、@ConfigurationProperties第三方Bean属性绑定
  • 4、松散绑定
  • 5、常用计量单位
  • 6、数据校验
  • 7、yaml绑定值的坑--关于进制

【开发篇】二、属性绑定与校验_第1张图片

1、@ConfigurationProperties自定义Bean属性绑定

前面读取yaml文件配置时,用过这个注解,先复习下它的用法。首先在yml配置文件中定义个属性:

# spring默认在用server,我加个s刻意回避下,别影响到服务启动
servers:
  hostAddr: http://127.0.0.1
  port: 9527
  timeout: 6000

定义实体类接收这个参数:

OData
@Component  //首先它得是受Spring管控的对象,即Bean,不然我哪怕拿到值,我怎么联系你给你
@ConfigurationProperties("servers")
public class ServerInfo {

	private String hostAddr:
	
	private int port:
	
	private long timeout;
}

接下来看下效果,懒得写UT,再获取IoC容器对象了 ,直接借用启动类run方法返回的IoC对象来获取上面这个Bean

@SpringBootApplication
public class MyApplication{

	public static void main(String[] args){
	
		ConfigurableApplicationContext applicationContext = SpringApplication.run(MyApplication.class,args);
		
		ServerInfo bean = applicationContext.getBean(ServerInfo.class);
		
		System.out.printin(bean);

	}
}

成功:
【开发篇】二、属性绑定与校验_第2张图片

@ConfigurationProperties中写你要加载的属性的上一层级的,如果上一层还有父级,则xxx.xx就行。最后,@ConfigurationProperties注解使用时可能有warn信息:

在这里插入图片描述

要解除使用@ConfigurationProperties注释警告,引入以下这个依赖然后IDEA中点Hide隐藏就行:

<dependency>
   <groupId>org.springframework.bootgroupId>
   <artifactId>spring-boot-configuration-processorartifactId>
dependency>

2、@EnableConfigurationProperties注解

有个关联知识点:@EnableConfigurationProperties注解,修改上面的代码,启动类上加@EnableConfigurationProperties注解:

@SpringBootApplication
@EnableConfigurationProperties(ServerInfo.class)
public class MyApplication{

	public static void main(String[] args){
	
		ConfigurableApplicationContext applicationContext = SpringApplication.run(MyApplication.class,args);
		
		ServerInfo bean = applicationContext.getBean(ServerInfo.class);
		
		System.out.printin(bean);

	}
}

此时,重启服务报错:excepted single matching bean but found 2

【开发篇】二、属性绑定与校验_第3张图片

这里的原因是@EnableConfigurationProperties(ServerInfo.class)指定了ServerInfo.class,就会把这个类的Bean加载进来,而之前ServerInfo类中又用@Component注册了一次。解决报错把@Component注释掉就好。因此:

@EnableConfigurationProperties注解不能与@Component注解同时使用!

@ConfigurationProperties和@EnableConfigurationProperties,前者是做属性绑定的,后者是开启属性绑定,设定对应的目标是谁。

@EnableConfigurationProperties(ServerInfo.class)

后者的好处是可以通过这一行代码清晰看到都有哪些类从yml中读取了属性,使得对于这种类的管理不松散。

3、@ConfigurationProperties第三方Bean属性绑定

以上是给我们自定义的Bean注入属性,那第三方Bean呢?@ConfigurationProperties也可以实现。先写个测试的yml配置:

datasource:
  driverClassName: com.mysql.hhhh  # 我只是测拿数据,不连数据库,驱动随便写

再定义第三方Bean,@SpringBootApplication注解本身往下追就有@Configuration注解,所以这里直接在启动类里定义第三方Bean

@SpringBootApplication
public class MyApplication{

	@Bean
	@ConfigurationProperties(prefix = "datasource")
	public DruidDataSource dataSource(){
		DruidDataSource dataSource = new DruidDataSource();
		return dataSource;
	}

	public static void main(String[] args){
	
		ConfigurableApplicationContext applicationContext = SpringApplication.run(MyApplication.class,args);
		
		DruidDataSource bean = applicationContext.getBean(DruidDataSource.class);
		
		System.out.printin(bean);
		
		System.out.printin(bean.getDriverClassName());

	}
}

运行,属性绑定成功:

【开发篇】二、属性绑定与校验_第4张图片

4、松散绑定

@ConfigurationProperties绑定属性支持属性名宽松绑定 ,即:

OData
@Component 
@ConfigurationProperties("servers")
public class ServerInfo {

	private String ipAddress:
	
	private int port:
	
	private long timeout;
}

属性的名字和配置文件的字段不用一模一样,以下配置都是生效的:

  • 驼峰
servers:
  ipAddress: 192.168.1.1
  port: 2345  
  timeout: -1

  • 下划线
servers:
  ip_address: 192.168.1.2
  port: 2345
  timeout: -1

  • 中划线(烤肉串写法,形似 00-0-0-0—,推荐写法)
servers:
  ip-address: 192.168.1.2
  port: 2345
  timeout: -1

  • 常量模式
servers:
  IP_ADDRESS: 192.168.1.2
  port: 2345
  timeout: -1

  • 随便加下划线或者中划线
servers:
  ip-ad-d_rEss: 192.168.1.2
  Port: 2345
  timeout: -1

当然实体类中的属性名也一样:

public class ServerInfo {

	private String ipADDRESS:
	
	private int port:
	
	private long timeout;
}

但@ConfigurationProperties注解的prefix属性,前缀名必须符合命名规范,即仅能使用纯小写字母、数字、下划线作为合法的字符,大写都不行。此外,@Value注解不支持宽松绑定,大小写不一样就会解析失败。

5、常用计量单位

SpringBoot支持JDK8提供的时间与空间计量单位,@DurationUnit和@DataSizeUnit注解标明所在属性的值的单位。还是上面的例子,加个属性serverTimeOut做调试:

servers:
  ipAddress: 192.168.1.1
  port: 2345  
  timeout: -1
  serverTimeOut: 6

此时, serverTimeOut值6的单位是不确定的,实体类中使用一个时间类Duration来接收:

OData
@Component 
@ConfigurationProperties("servers")
public class ServerInfo {

	private String ipAddress:
	
	private int port:
	
	private long timeout;

	private Duration serverTimeOut;
}

打印这个Bean,可以看到0.06s,即默认为ms:

【开发篇】二、属性绑定与校验_第5张图片
接下来加注解指定这个属性的单位:


...
@DurationUnit(ChronoUnit.MINUTES)
private Duration serverTimeOut;
...

【开发篇】二、属性绑定与校验_第6张图片

同理,还有空间单位,默认单位Byte,可加@DataSizeUnit注解指定:

OData
@Component 
@ConfigurationProperties("servers")
public class ServerInfo {

	private String ipAddress:
	
	private int port:
	
	private long timeout;

	@DurationUnit(ChronoUnit.MINUTES)
	private Duration serverTimeOut;

	@DataSizeUnit(DataUnit.MEGABYTES)
	private DataSize dataSize;
}

6、数据校验

开启数据校验有助于系统安全性,J2EE规范中JSR303规范定义了一组有关数据校验相关的API,先导入JSR303的依赖坐标:

<dependency>    
	<groupId>javax.validationgroupId>
    <artifactId>validation-apiartifactId>
dependency>

然后在需要校验的地方开启数据校验:

//springframework下的
@Valiated

然后给属性加具体的校验规则,相关注解有:

【开发篇】二、属性绑定与校验_第7张图片

此时,运行出现报错:

【开发篇】二、属性绑定与校验_第8张图片

报错信息为找不到具体的实现,这就和JDBC和mysql驱动是一个意思,有接口,代码能写,但一运行,没有实现,跑不起来。再引入JSR303校验框架的实现,如Hibernate:

<dependency>    
	<groupId>org.hibernate.validatorgroupId>
    <artifactId>hibernate-validatorartifactId>
dependency>

再运行,校验成功:

【开发篇】二、属性绑定与校验_第9张图片

JSR303的校验,用处很多,比如写接口时,对前端的传参做校验,只需要在Dto类中的属性加相关注解即可,如:

【开发篇】二、属性绑定与校验_第10张图片

添加校验规则:

【开发篇】二、属性绑定与校验_第11张图片

7、yaml绑定值的坑–关于进制

在yaml中定义一个属性password,取值0127,使用属性绑定或者@Value取值,打印这个值:

【开发篇】二、属性绑定与校验_第12张图片
【开发篇】二、属性绑定与校验_第13张图片
问题的原因就是,在yaml中,书写数字和简单字符串都不用加引号,而0127又特殊在以0开头,后面的字符在0-7之间,被当作了八进制,可通过加引号解决:

datasource:
  password: "0127"

【开发篇】二、属性绑定与校验_第14张图片
即:注意yaml文件中对于数字的定义支持进制书写格式,如需使用字符串请使用引号明确标注

你可能感兴趣的:(SpringBoot,java,开发语言)