Springboot中常用注解@Accessors/@Data/@JsonInclude(JsonInclude.Include.NON_NULL)/@EqualsAndHashCode

一、@Accessors(chain = true)

包含的属性

fluent(布尔型)chain(布尔型)prefix(String型)

作用域:

既可以注解在类上也可以注解在属性上

作用在VO实体类加注解@Accessors(chain = true)之后,在service层写业务逻辑实例化vo对象的相关赋值动作就可通过链式写法来编程,简洁高效。如下例子:

 VO实例:

@Data
@Accessors(chain = true)
public class User {
    private int id;
    private String name;
    private String sex;
}

 Service层调用:


//实例化对象后,通过链式写法设置多个属性值
Person user=new User();
user.setId(1).setName("user").setSex("m");

 解析原理:

        ​​​​​​

// 注解生成的setter方法如下,方法体略

  1. public User setId(int id) {}

  2. public User setName(String name) {}

  3. public User setSex(String sex) {}

        我们在进行属性赋值的时候,因为set方法返回的是当前的对象,所以可以进行连续调用set方法进行赋值,如上述代码所示。没加注解的情况下一般我们是使用@Data,默认生成对应的set方法的返回值是void;由于set方法返回值是void类型,所以需分开赋值user.setId(1);user.setName("user");user.setSex("um");从代码简洁可读性看,明显是链式写法更优。
 

二、@JsonInclude(JsonInclude.Include.NON_NULL)

是为实体类在接口序列化返回值时增加规则的注解

在springboot项目中,前端发送请求后得到的响应体,我们都会先设计一个对应的实体类,将其转换为json数据,最终返回改响应体。该注解用在对应的vo实体类,如果某一属性为空,在前端请求后返回的json数据中,字段值为null的字段则不显示。即一个接口需要过滤掉返回值为null的字段,即值为null的字段不返回,可以在实体类中增加该注解。

另外还有一个属性是ALWAYS, ALWAYS为默认值,表示全部序列化,即默认返回全部字段,例:

@JsonInclude(JsonInclude.Include.ALWAYS)

 三、@Data

简化了我们VO实体类中的代码,加上注解后无需再生成属性对应的get,set方法,构造器等

  • 省去get,set这种冗余的方法
  • 其中包含了@Getter、@Setter、@ToString、@EqualsAndHashCode、@RequiredArgsConstructor等

其中特别说明一下 

我们的vo实体类使用@Data注解时,@Data默认包含的是:@EqualsAndHashCode(callSuper = false),如果我们的实体类有继承父类的情况下,这个就需要根据实际情况来赋值了。

true&false两者区别:假设当前实体类A实例化了两个对象,实体类A继承父类B,

@EqualsAndHashCode(callSuper = false):当我们在对两个对象属性比较的时候,如果两个对象属性一致,父类属性不一致,在比较时候仍是出现相同的结果,也就是返回的true。

@EqualsAndHashCode(callSuper = true):如果加了这个注解,则相反,进行对象属性比较时,子类和父类一同进行比较,也就是:如果两个对象子类属性一致,父类不一致,返回的是false;只有子类和继承类的属性都一致时,才会返回true

四、@JsonIgnoreProperties(ignoreUnknown = true)

json转换成的实体类加注解@JsonIgnoreProperties(ignoreUnknown = true),注意这是类级别的注解。

  • @JsonIgnore注解用来忽略某些字段,可以用在Field或者Getter方法上,用在Setter方法时,和Filed效果一样。这个注解只能用在POJO存在的字段要忽略的情况,不能满足现在需要的情况。

  • @JsonIgnoreProperties(ignoreUnknown = true),将这个注解写在类上之后,就会忽略类中不存在的字段,可以满足当前的需要。这个注解还可以指定要忽略的字段。使用方法如下:

  • @JsonIgnoreProperties({ "name", "remark" })
    指定的字段不会被序列化和反序列化。

五、@MapKey作用以及@MapKey is required解决方案

@MapKey MyBatis框架的注解,作用是将List结果集转换成key-value形式的Map结果集,方便快速从结果集中查询指定结果。

六、@TableField(updateStrategy = FieldStrategy.IGNORED)

就会忽略为空的判断,将该字段设置为null也会更新表中的数据。

    /**
     * 是否闭环
     */
    @TableField(value = "IS_CLOSED",updateStrategy = FieldStrategy.IGNORED)
    private String isClosed;

Mybatis-Plus是一款优秀的ORM框架,可以使得Java程序员在编写数据库操作代码时更加便捷快速。其中,`@TableField`注解是Mybatis-Plus中用来描述实体类与数据库字段的对应关系的注解,该注解的属性如下:

1. `value`:指定对应的数据库表字段名,默认值为空字符串,即使用属性名,在一般情况下不需要指定。
2. `exist`:指定对应的数据库表字段是否存在,默认为true,即如果对应数据库表不存在该字段,会抛出SqlException。如果该字段为false,则即使对应数据库不存在该字段,也不会异常。
3. `update`:在使用Mybatis-plus提供的`updateById()`方法时,指定该字段的更新策略,有以下取值。
1. FieldStrategy.DEFAULT:默认值,按照全局的配置进行判断。
2. FieldStrategy.NOT_NULL:当属性值不为null且不为Java默认值时进行更新操作。
3. FieldStrategy.NOT_EMPTY:当属性值不为null且不为空字符串或空集合或空数组时进行更新操作。
4. FieldStrategy.IGNORED:默认传参null,mp是不会更新的,加了这个注解,就相等与,传参null,也会更新数据库字段  

示例代码:

📋
@TableField(exist = false)
private String userName; // 对应的数据库字段名为userName,该字段可不存在于数据库表中
@TableField(value = "age", update = FieldStrategy.IGNORED)
private Integer age; // 对应的数据库字段名为age,更新策略为IGNORED,即age字段的值为null,都会进行更新操作。

当然,在其他的场景中,还可以根据需要在`@TableField`注解中使用更多的属性,之所以这里只列出了value、exist和update三个属性,是因为这三个属性是最为常用和重要的三个属性。

七、 @RequiredArgsConstructor

Lombok中的一个@RequiredArgsConstructor,简化了一些@Autowired注解,可以减少@Autowired的书写,我们在写controller或者Service层的时候,需要注入很多的mapper接口或者另外的service接口,这时候就会写很多的@Autowired注解,代码看起来很繁琐。

类上加上@RequiredArgsConstructor,需要注入的类要用final声明,或者使用

@NonNull。 

@Service
@RequiredArgsConstructor
@Slf4j
public class ProductionProblemKeywordServiceImpl implements ProductionProblemKeywordService {

    private final ProductionProblemKeywordMapper mapper;

八、Annotation

​ Annotation(注解)是JDK5开始引入的新特性,可以看作是一种特殊的注释,主要用于修饰类,方法或者变量,在框架中大量使用(如 Spring、Mybatis等) 

注解是一种能被添加到java代码中的元数据,类、方法、变量、参数和包都可以用注解来修饰。注解对于它所修饰的代码并没有直接的影响。

@Target
官方解释:

    指示注解类型适用的上下文。注解类型可能适用的声明上下文和类型上下文在 JLS 9.6.4.1 中指定,并在源代码中由java.lang.annotation.ElementType的枚举常量表示。
    如果注解类型T上不存在@Target元注解,则类型T的注解可以写为除类型参数声明之外的任何声明的修饰符。
    如果存在@Target元注解,编译器将强制执行ElementType枚举常量指示的使用限制
它指明了它所修饰的注解使用的范围 如果自定义的注解为含有@Target元注解修饰,那么默认可以是在(除类型参数之外的)任何项之上使用,若有@Target元注解修饰那么根据Value(ElementType枚举常量)的指定的目标进行规定。

ElementType
ElementType.class 

public enum ElementType {
    /** 类、接口(包括注解类型)或枚举声明 */
    TYPE,

    /** 字段声明(包括枚举常量) */
    FIELD,

    /** 方法声明 */
    METHOD,

    /** 参数声明 */
    PARAMETER,

    /** 构造函数声明 */
    CONSTRUCTOR,

    /** 局部变量声明 */
    LOCAL_VARIABLE,

    /** 注解类型声明 */
    ANNOTATION_TYPE,

    /** 包装声明 */
    PACKAGE,

    /**
     * 类型参数声明 类型参数即Map<String,Integer>中的String和Integer这里是作为类型
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * 使用类型 对应于 JLS 4.11 中的 15 个类型上下文,以及两个声明上下文:类型声明(包括注解类型声明)和类型参数声明。
     *
     * @since 1.8
     */
    TYPE_USE
}


ElementType的枚举常量指明了注解可以使用的目标。
@Target(ElementType.METHOD)//可修饰在方法之上

 

@Retention
官方解释: 

指示要保留带注解类型的注解多长时间。如果注释类型声明中不存在保留注释,则保留策略默认为RetentionPolicy.CLASS 。
仅当元注释类型直接用于注释时,保留元注释才有效。如果将元注释类型用作另一个注释类型中的成员类型,则它没有效果。

即@Retention用来约束注解的生命周期,分别有三个值,源码级别(source)、类文件级别(class)或者运行时级别(runtime)可以通过指定@Retention中的值来实现(值为RetentionPolicy枚举常量)。

RetentionPolicy.class

public enum RetentionPolicy {
    /**
     * 注解将被编译器丢弃。(该类型的注解信息指挥保留在源码中,源码经过编译后,注解信息会被丢弃,不会保留在编译好的class文件中)
     */
    SOURCE,

    /**
     * 注解将由编译器记录在类文件中,但不需要在运行时由 VM 保留。这是默认行为.(该类型的注解信息会保留在源码里和class文件里,在执行的时候,不会加载到虚拟机中) 该类型也是未指定@Retention值的缺省值
     */
    CLASS,

    /**
     * 注解将由编译器记录在类文件中,并在运行时由 VM 保留,因此可以反射性地读取它们。(源码,class文件和执行时(VM)都保留注解的信息)
     */
    RUNTIME
}

​ 注意:生命周期大小排序为SOURCE < CLASS < RUNTIME,范围依次增大,前者能使用的地方后者一定能使用。如果需要在运行时去动态获取注解信息,那只能使用RUNTIME;如果要在编译时进行一些预处理操作,比如生成一些辅助代码,就是用CLASS;如果只是做一些检查性的操作,比如@Override和@SupperssWarning,可选择SOURCE

@Documented
官方解释:

表示默认情况下,带有类型的注释将由 javadoc 和类似工具记录。这种类型应该用于注解类型的声明,这些类型的注释会影响其客户对注释元素的使用。如果使用 Documented 对类型声明进行注释,则其注释将成为注释元素的公共 API 的一部分。

带上该注解后的注解表明,在默认情况下这个注解是由JavaDoc和类似工具记录的,即带上了该文档化的注解被使用再生成文档时,会称为API的一部分。(默认情况下JavaDoc是不包含注解的,除非声明注解的时候使用了@Documented)

  • 生成的文档

 

  • 不带@Documented注解生成的文档

@Inherited
官方解释:

指示注解类型是自动继承的。如果注解类型声明中存在 Inherited 元注解,并且用户在类声明中查询注解类型,并且类声明没有该类型的注解,则将自动查询该类的超类以获取注解类型。将重复此过程,直到找到此类型的注释,或到达类层次结构(对象)的顶部。如果没有超类具有此类型的注释,则查询将指示所讨论的类没有此类注释。
请注意,如果注释类型用于注释类以外的任何内容,则此元注释类型无效。另请注意,此元注释仅导致注释从超类继承;已实现接口上的注解无效。

被该元注解修饰的自定义注解再使用后会自动继承,如果使用了该自定义注解去修饰一个class那么这个注解也会作用于该class的子类。就是说如果某个类使用了被@Inherited修饰的注解,则其子类将会自动具有该注释
​ 注意: @Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。


2023.06.27

@JsonAlias

在实际的工作需求中,写接口的人会经常遇到对于Bean各种各样的操作,比如我对数据库要写个Bean,返回前台还得有个Vo bean,在另一个需求又用到和这个类似的Bean了,有些字段不一样啊,字段的有些类型不一样,接收的参数名不一样,可能就需要写好几个不同的Bean
 

这个注解是在JackSon 2.9版本中才有的。
作用是在反序列化的时候可以让Bean的属性接收多个json字段的名称。可以加在字段上或者getter和setter方法上。

public class User {
  @JsonAlias({"name","user"})
  private String username;
  private String password;
  private Integer age;
}

 请求boby:
{
“name” : “小明”,
“password” : “123”,
age : 15
}

可以从下面看到json字段是name也成功对应到了Bean的username属性

 

如果不加上面那个注解肯定会报json解析异常错误。
注意:序列化的时候仍然是原始的属性名称,只是在反序列化的时候可以接收多个json字段,如果多个json字段对应了Bean里面的同一个属性,依然会报Json解析异常错误的。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值