lombok详解

lombok是一个开源的代码生成库,能以简单的注解形式来简化Java类中的大量样板代码,提高开发人员的开发效率。

例如开发中经常需要写的javabean,都需要花时间去添加相应的getter/setter,也许还要去写构造器、equals等方法,而且需要维护,当属性多时会出现大量的getter/setter方法,这些显得很冗长也没有太多技术含量。

lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法,使代码看起来更简洁。

lombok对应的maven坐标:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.28</version>
</dependency>

1. lombok插件安装

要使用lombok需要在IDE中安装对应的lombok插件。开发工具为IntelliJ IDEA,安装插件过程如下:

  • 打开IntelliJ IDEA后点击菜单栏中的File–>Settings进入到设置页面
图片[1]-lombok详解-不念博客
  • 点击设置页面中的Plugins进行插件的安装,在右侧选择Browse repositories…,然后在搜索页面输入lombok,可以查询到下方的Lombok Plugin,鼠标点击Lombok Plugin可在右侧看到Install按钮,点击该按钮便可安装
图片[2]-lombok详解-不念博客

注意:一般安装IntelliJ IDEA后,lombok插件已经自动安装

2. lombok常用注解

注解说明
@Setter注解在类或属性,注解在类时为所有属性生成setter方法,注解在属性上时只为该属性生成setter方法
@Getter使用方法同@Setter,区别在于生成的是getter方法
@ToString注解在类,添加toString方法
@EqualsAndHashCode注解在类,生成hashCode和equals方法
@NoArgsConstructor注解在类,生成无参的构造方法
@RequiredArgsConstructor注解在类,为类中需要特殊处理的属性生成构造方法,比如final和被@NonNull注解的属性
@AllArgsConstructor注解在类,生成包含类中所有属性的构造方法
@Data注解在类,生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法
@Slf4j注解在类,生成log变量,用于记录日志
@Builder将类转变为建造者模式

3.  lombok入门案例

【步骤一】:创建maven工程zbbmeta-lombok-demo并配置pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.7.15</version>
    </parent>

    <groupId>com.zbbmeta</groupId>
    <artifactId>zbbmeta-lombok-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>


        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
    </dependencies>
</project>
  • 创建user表
create table user
(
    id     bigint      null comment '主键',
    name   varchar(20) null,
    age    int         null,
    s_name varchar(20) null
);
-- 插入数据
INSERT INTO backend_db.user (id, name, age, s_name) VALUES (1740047068249387009, 'zbbmeta', 18, 'test1');
INSERT INTO backend_db.user (id, name, age, s_name) VALUES (1740047068350050306, 'springboot不念博客', 20, 'test2');
INSERT INTO backend_db.user (id, name, age, s_name) VALUES (1740047068350050307, 'springboot不念博客2', 22, null);

【步骤二】:创建User类并加入lombok提供的注解

package com.zbbmeta.entity;


import java.io.Serializable;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @TableName user
 */

@Data
public class User implements Serializable {
    private Long id;

    private String name;

    private Integer age;
    //注意该特殊字段
    private String sName;


    private static final long serialVersionUID = 1L;
}

【步骤三】:创建UserController

package com.zbbmeta.controller;

import com.zbbmeta.entity.User;
import com.zbbmeta.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * @author springboot不念博客
 * @description: TODO
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    UserService userService;
    //查询User表数据
    @GetMapping
    public List<User> getUsers(){
        List<User> list = userService.getUsers();
        return list;
    }
}

【步骤四】:使用POST发送请求 GET http://localhost:8899/user

[
    {
        "id": 1740047068249387009,
        "name": "zbbmeta",
        "age": 18,
        "sname": null
    },
    {
        "id": 1740047068350050306,
        "name": "springboot不念博客",
        "age": 20,
        "sname": null
    },
    {
        "id": 1740047068350050307,
        "name": "springboot不念博客2",
        "age": 22,
        "sname": null
    }
]
图片[3]-lombok详解-不念博客

4.lombok存在问题

发现uese类的sName属性没有进行赋值

原因

Lombok对于第一个字母小写,第二个字母大写的属性生成的get-set方法和Mybatis以及想法还是说是Java官方认可的get-set方法生成的不一样

lombok生成的User对象

public class User
    implements Serializable
{
    private Long id;
    private String name;
    private Integer age;
    private String sName;
    private static final long serialVersionUID = 1L;
    
    public void setId(Long id) {
        this.id = id; } 
 public void setName(String name) { this.name = name; } 
 public void setAge(Integer age) { this.age = age; } 
 public void setSName(String sName) { this.sName = sName; }

     public Long getId() {
        return this.id;
    } public String getName() {
        return this.name;
    } public Integer getAge() {
        return this.age;
    } public String getSName() {
        return this.sName;
    }

发现sName的set-get方法如下setSName和getSName不是我们想的setsName和getsName

Mybatis(3.4.6版本)解析get-set方法获取属性名字的源码:

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.reflection.property;

import java.util.Locale;

import org.apache.ibatis.reflection.ReflectionException;

/**
 * @author Clinton Begin
 */
public final class PropertyNamer {

  private PropertyNamer() {
    // Prevent Instantiation of Static Class
  }

  public static String methodToProperty(String name) {
    //is开头的一般是bool类型,直接从第二个(索引)开始截取(简单粗暴)
    if (name.startsWith("is")) {
      name = name.substring(2);
    } else if (name.startsWith("get") || name.startsWith("set")) {//set-get的就从第三个(索引)开始截取
      name = name.substring(3);
    } else {
      throw new ReflectionException("Error parsing property name '" + name + "'.  Didn't start with 'is', 'get' or 'set'.");
    }
 //下面这个判断很重要,解释如下
            //第一句话:name.length()==1
            //       对于属性只有一个字母的,例如private int x;
            //          对应的get-set方法是getX();setX(int x);
            //第二句话:name.length() > 1 && !Character.isUpperCase(name.charAt(1)))
            //属性名字长度大于1,并且第二个(代码中的charAt(1),这个1是数组下标)字母是小写的
            //      如果第二个char是大写的,那就直接返回name
    if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) {
    //让属性名第一个字母小写,然后加上后面的内容
      name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
    }

    return name;
  }

  public static boolean isProperty(String name) {
    return isGetter(name) || isSetter(name);
  }

  public static boolean isGetter(String name) {
    return (name.startsWith("get") && name.length() > 3) || (name.startsWith("is") && name.length() > 2);
  }

  public static boolean isSetter(String name) {
    return name.startsWith("set") && name.length() > 3;
  }

}

运行分析:

图片[4]-lombok详解-不念博客

Mybatis解析get-set方法为属性名字测试

 @GetMapping("/test")
  public void getTest(){

      String isName = "isName";
      String getName = "getName";
      String getnMetaType = "getsName";
      String getNMetaType = "getSName";

      Stream.of(isName,getName,getnMetaType,getNMetaType)
              .forEach(methodName->System.out.println("方法名字是:"+methodName+" 属性名字:"+ PropertyNamer.methodToProperty(methodName)));

  }

输出结果

方法名字是:isName 属性名字:name
方法名字是:getName 属性名字:name
方法名字是:getsName 属性名字:sName
方法名字是:getSName 属性名字:SName
  • 1.修改属性名字,让第二个字母小写
  • 2.如果数据库已经设计好,并且前后端接口对接好了,不想修改,手动添加 get 前缀,这样 Lombok 就会生成符合规范的方法名。
© 版权声明
THE END