@Value的几个特殊用法

目录

默认值

static变量

变量类型

基本数据类型

数组

集合类

List

Set

Map

EL高端玩法

注入bean

bean的变量和方法

静态类

逻辑运算

${}和#{}的区别

${}

#{} 


默认值

        比如有这样一个需求:如果配置了系统属性,userName就用配置的属性值。如果没有配置,则userName用默认值nieyp。

错误用法:

@Value(value = "${susan.test.userName}")
private String userName = "susan";

设置userName默认值的时机,比@Value注解依赖注入属性值要早,也就是说userName初始化好了默认值,后面还是会被覆盖

正确用法:

@Value(value = "${susan.test.userName:nieyp}")
private String userName; 

如果配置了系统属性,userName就用配置的属性值。如果没有配置,则userName用默认值nieyp。

建议:

假如有这种场景:在business层中包含了UserService类,business层被api服务和job服务都引用了。但UserService类中@Value的userName只在api服务中有用,在job服务中根本用不到该属性。

对于job服务来说,如果不在.properties文件中配置同名的系统属性,则服务启动时就会报错。

这个坑,我之前踩过多次。所以,建议大家,使用@Value注解时,最好给参数设置一个默认值,以防止出现类似的问题。

static变量

静态变量可以自动注入系统属性值不?

我们一起看看,假如将上面的userName定义成static的:

@Value("${nieyp.test.userName}")
private static String userName;

程序可以正常启动,但是获取到userName的值却是null。由此可见,被static修饰的变量通过@Value会注入失败。

正确方法:

@Service
public class UserService {
 
    private static String userName;
 
    @Value("${nieyp.test.userName}")
    public void setUserName(String userName) {
        UserService.userName = userName;
    }
 
    public String test() {
        return userName;
    }

提供一个静态参数的setter方法,在该方法上使用@Value注入属性值,并且同时在该方法中给静态变量赋值。@Value注解在这里竟然使用在setUserName方法上了,也就是对应的setter方法,而不是在变量上。

变量类型

基本数据类型

  • 整型:byte、short、int、long

  • 浮点型:float、double

  • 布尔型:boolean

  • 字符型:char

包装类型 

  • 整型:Byte、Short、Integer、Long

  • 浮点型:Float、Double

  • 布尔型:Boolean

  • 字符型:Character

@Value注解对这8中基本类型和相应的包装类,有非常良好的支持,例如:

@Value("${nieyp.test.a:1}")
private byte a;
 
@Value("${nieyp.test.b:100}")
private short b;
 
@Value("${nieyp.test.c:3000}")
private int c;
 
@Value("${nieyp.test.d:4000000}")
private long d;
 
@Value("${nieyp.test.e:5.2}")
private float e;
 
@Value("${nieyp.test.f:6.1}")
private double f;
 
@Value("${nieyp.test.g:false}")
private boolean g;
 
@Value("${nieyp.test.h:h}")
private char h;
 
@Value("${nieyp.test.a:1}")
private byte a1;
 
@Value("${nieyp.test.b:100}")
private Short b1;
 
@Value("${nieyp.test.c:3000}")
private Integer c1;
 
@Value("${nieyp.test.d:4000000}")
private Long d1;
 
@Value("${nieyp.test.e:5.2}")
private Float e1;
 
@Value("${nieyp.test.f:6.1}")
private Double f1;
 
@Value("${nieyp.test.g:false}")
private Boolean g1;
 
@Value("${nieyp.test.h:h}")
private Character h1; 

数组

定义数组时可以这样写:

@Value("${susan.test.array:1,2,3,4,5}")
private int[] array;

spring默认使用逗号分隔参数值。

如果用空格分隔,例如:

@Value("${susan.test.array:1 2 3 4 5}")
private int[] array;

spring会自动把空格去掉,导致数据中只有一个值:12345,注意千万别搞错了。

定义数组时一定要注意属性值的类型,必须完全一致才可以

集合类

List

使用spring的EL表达式。

@Value("#{'${nieyp.test.list}'.split(',')}")
private List<String> list;

配置文件

nieyp.test.list=10,11,12,13

适用@ConfigurationProperties

配置文件:

nieyp.test.list[0]=10
nieyp.test.list[1]=11
nieyp.test.list[2]=12
nieyp.test.list[3]=13

配置类

@Configuration
@ConfigurationProperties(prefix = "susan.test")
@Data
public class MyConfig {
    private List<String> list;

调用:

@Service
public class UserService {
 
    @Autowired
    private MyConfig myConfig;
 
    public String test() {
        System.out.println(myConfig.getList());
        return null;
    }
}

Set

set用法和list相似不在介绍

如何给set和list添加默认值

这种是正确的用法

@Value("#{'${susan.test.set:}'.empty ? null : '${susan.test.set:}'.split(',')}")
private Set<String> set;

以下说明两种错误的用法:

@Value("#{'${susan.test.set:}'.split(',')}")
private Set<String> set;

set集合怎么不是空的,而是包含了一个空字符串的集合?

@Value("#{'${susan.test.set: null}'.split(',')}")
private Set<String> set;

Set集合也不是空的,而是包含了一个"null"字符串的集合。

Map

java代码:

@Value("#{${susan.test.map}}")
private Map<String, String> map;

配置文件

susan.test.map={"name":"苏三", "age":"18"}

 设置默认值

@Value("#{'${susan.test.map:}'.empty ? null : '${susan.test.map:}'}")
private Map<String, String> map;

EL高端玩法

注入bean

@Value("#{roleService}")
private RoleService roleService;

通过这种方式,可以注入id为roleService的bean。

bean的变量和方法

通过EL表达式,@Value注解已经可以注入bean了。既然能够拿到bean实例,接下来,可以再进一步。

在RoleService类中定义了:成员变量、常量、方法、静态方法。

@Service
public class RoleService {
    public static final int DEFAULT_AGE = 18;
    public int id = 1000;
 
    public String getRoleName() {
        return "管理员";
    }
 
    public static int getParentId() {
        return 2000;
    }
}

 在调用的地方这样写:

@Service
public class UserService {
 
    @Value("#{roleService.DEFAULT_AGE}")
    private int myAge;
 
    @Value("#{roleService.id}")
    private int id;
 
    @Value("#{roleService.getRoleName()}")
    private String myRoleName;
 
    @Value("#{roleService.getParentId()}")
    private String myParentId;
}

静态类

前面的内容都是基于bean的,但有时我们需要调用静态类,比如:Math、xxxUtil等静态工具类的方法,该怎么办呢?

答:用T加括号。

//可以注入系统的路径分隔符到path中。

@Value("#{T(java.io.File).separator}")
private String path;

//可以注入一个随机数到randomValue中。

@Value("#{T(java.lang.Math).random()}")
private double randomValue;

逻辑运算

通过上面介绍的内容,我们可以获取到绝大多数类的变量和方法的值了。但有了这些值,还不够,我们能不能在EL表达式中加点逻辑?

//拼接字符串

@Value("#{roleService.roleName + '' + roleService.DEFAULT_AGE}")
private String value;

//逻辑判断

@Value("#{roleService.DEFAULT_AGE > 16 and roleService.roleName.equals('苏三')}")

private String operation;

//三目运算

@Value("#{roleService.DEFAULT_AGE > 16 ? roleService.roleName: '苏三' }")
private String realRoleName;

${}和#{}的区别

${}

主要用于获取配置文件中的系统属性值。 

@Value(value = "${susan.test.userName:susan}")
private String userName;

可以设置默认值。如果在配置文件中找不到susan.test.userName的配置,则注入时用默认值。

如果在配置文件中找不到susan.test.userName的配置,也没有设置默认值,则启动项目时会报错

#{} 

主要用于通过spring的EL表达式,获取bean的属性,或者调用bean的某个方法。还有调用类的静态常量和静态方法。

@Value("#{roleService.DEFAULT_AGE}")

private int myAge;

@Value("#{roleService.id}")

private int id;

@Value("#{roleService.getRoleName()}")

private String myRoleName;

如果是调用类的静态方法,则需要加T(包名 + 方法名称)。例如:T(java.lang.Math)。

@Value("#{T(java.lang.Math).random()}")

private double randomValue;

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Data JPA中的@Query注解可以在抽象方法上使用。该注解允许我们直接编写自定义的SQL查询语句,以替代默认的基于方法命名规则的查询。 使用@Query注解,我们可以在抽象方法上定义自己的查询语句。可以通过在注解中编写原生的SQL查询语句或者使用JPQL查询语句来完成。 当使用原生的SQL查询语句时,我们需要设置nativeQuery参数为true。这样Spring Data JPA就会将查询结果与实体类进行映射。 如果使用JPQL查询语句,我们可以通过在查询语句中引用实体类和其属性来构建查询语句。Spring Data JPA会根据查询语句的返回类型自动进行结果映射。 在@Query注解中,我们还可以使用命名参数或者索引参数来指定查询参数。通过在查询方法的参数前添加@Param注解,我们可以将方法参数与查询参数进行映射。 除了定义查询语句,@Query注解还可以指定查询的排序方式、分页和锁定等。我们可以使用关键字ORDER BY来设置排序字段,使用关键字LIMIT和OFFSET来设置分页查询的起始位置和返回记录数。同时,我们还可以使用关键字FOR UPDATE来设置查询结果的锁定。 通过在抽象方法上使用@Query注解,我们可以实现更加灵活和复杂的查询需求。它为我们提供了一种强大的方式来利用Spring Data JPA进行自定义查询,以满足特定业务场景的需求。 ### 回答2: Spring Data JPA提供了一个 @Query 注解,可以在抽象方法上使用。 @Query 注解用于在 Repository 接口中定义查询方法的具体查询语句。通过使用 @Query 注解,我们可以将自定义的 JPQL 或者 SQL 语句与方法绑定在一起。 使用 @Query 注解有以下几个优点: 1. 灵活性:可以使用自定义的查询语句,满足特定的数据查询需求。 2. 类型安全:由于使用了命名参数或者索引参数,可以避免 SQL 注入等安全问题。 3. 提高代码可读性:通过在方法上添加 @Query 注解,可以直接看到方法的具体查询是如何实现的,提高代码的可读性和可维护性。 4. 内置分页支持:可以在 @Query 注解中使用内置的分页查询方法,如 Pageable 和 Sort。 使用 @Query 注解时,可以将查询语句写在注解的 value 属性中。语句可以是原生的 SQL 语句,也可以是 JPQL 查询语句。在查询语句中,可以使用实体类的属性名来代替数据库表字段名。 另外,@Query 注解还支持使用命名参数和索引参数。命名参数使用冒号(:)加参数名的方式,在方法参数中使用 @Param 注解指定参数名。索引参数使用问号(?)加索引位置的方式。 需要注意的是,使用 @Query 注解时,方法的返回类型可以是具体的实体类,也可以是包装类、List、Set 或者其他集合类。如果需要分页查询,返回类型可以是 Page 或者 Slice 类型。 总的来说,通过在抽象方法中使用 Spring Data JPA 的 @Query 注解,可以更加灵活地定义自定义查询,提高代码的可读性和可维护性。 ### 回答3: Spring Data JPA提供了 @Query 注解,它可以用在抽象方法上,用于自定义查询语句。 使用 @Query 注解,我们可以在抽象方法上定义自己的JPQL(Java Persistence Query Language)或SQL查询语句。通过在注解中定义查询语句,我们可以灵活地执行各种复杂的查询操作。 在定义查询语句时,我们可以使用实体类的属性名来引用实体的字段,并且可以使用 JPA 提供的各种查询关键字和函数进行组合。除此之外,我们还可以使用一些特殊的 JPA 提供的关键字,如:distinct、is not null、is null、order by等。 在定义查询语句时,@Query 注解还支持使用命名参数和位置参数两种方式来传递参数。命名参数使用 :paramName 的方式来引用参数,而位置参数使用 ?1、?2 等符号来引用参数。我们可以根据实际情况选择适合的参数传递方式。 除了定义查询语句,@Query 注解还有其他一些属性。例如,我们可以使用 @Modifying 注解来告诉 Spring Data JPA 这个查询是一个更新操作,需要通过 @Transactional 注解来开启事务。另外,还可以使用 @Query 注解的 nativeQuery 属性来指示是否执行原生 SQL 查询。 总之,通过在抽象方法上使用 @Query 注解,我们可以自定义我们需要的查询语句,使得我们可以方便地执行各种复杂的查询操作。这样,在使用 Spring Data JPA 进行数据访问时,我们就能够更加灵活地控制查询操作,并且减少重复代码的编写。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值