Mybatis-Plus public field automatic filling problem analysis and code implementation

Table of Contents

  • 1. Introduction
  • 2. Implementation steps
    • 1. Add the @TableField annotation to the attribute of the entity class to specify the automatic filling strategy
    • 2. Write a metadata object handler, and assign values to public fields uniformly in this class. This class needs to implement the MetaObjectHandler interface
      • 2.1 Populate the createTime and updateTime fields:
      • 2.2 Populate the createUser and updateUser fields
        • 2.2.1 ThreadLocal
          • 1. What is ThreadLocal?
          • 2. Why can ThreadLocal be used?
          • 3. Common methods of ThreadLocal:
        • 2.2.2 ThreadLocal implementation steps
  • 3. Summary

1. Introduction

  • When writing the save or update method in our constructor, we need to manually fill in the creation time, update time, creator, updater, etc. If these fields need to be manually filled every time data is inserted or updated, it will not only increase development The workload of the reader, and it is easy to omit or fill in the wrong situation. These problems will bring unnecessary trouble to the development process.
  • Mybatis-Plus public field auto-fill is an automated data filling method that can automatically fill some public fields, such as creation time, update time, creator, updater, etc. This avoids manually populating these fields every time data is inserted or updated, improving development efficiency and reducing the possibility of errors.

IDE: idea, JDK: 1.8

2. Implementation steps

1. Add the @TableField annotation to the attribute of the entity class to specify the automatic filling strategy

 @TableField(fill = FieldFill.INSERT) //Fill the field when inserting
    private LocalDateTime createTime; // creation time

    @TableField(fill = FieldFill.INSERT_UPDATE) // The value of the filled field when inserting and updating
    private LocalDateTime updateTime; // update time

    @TableField(fill = FieldFill.INSERT) //Fill the field when inserting
    private Long createUser; // Creator

    @TableField(fill = FieldFill.INSERT_UPDATE) // The value of the filled field when inserting and updating
    private Long updateUser; // Updater

2. Write metadata object handlers, and assign values to public fields in this class. This class needs to implement the MetaObjectHandler interface

Mybatis-Plus provides an interface MetaObjectHandler, which can realize automatic filling of public fields. When inserting or updating data, methods in this interface are automatically called to populate public fields. You only need to implement this interface and fill in the corresponding fields in the implementation method. Two methods are defined in this interface:
insertFill(MetaObject metaObject): This method is automatically called when inserting data to fill public fields.
updateFill(MetaObject metaObject): This method is automatically called when updating data, and is used to fill public fields.

2.1 Populate the createTime and updateTime fields:

Create a new class MyMetaObjectHandler.class to implement the MetaObjectHandler interface, rewrite two methods, and assign the creation date and update date

/**
 * Custom metadata object handler
 */
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {<!-- -->
    /**
     * Insert operation autofill
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {<!-- -->
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime", LocalDateTime.now());
    }

    /**
     * Update operation autofill
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {<!-- -->
        metaObject.setValue("updateTime", LocalDateTime.now());
    }
}

2.2 Populate the createUser and updateUser fields

How to dynamically obtain the id of the currently logged-in user when automatically filling createUser and updateUser, we can use ThreadLocal to achieve

2.2.1 ThreadLocal

1. What is ThreadLocal?
  • ThreadLocal is not a Thread, but a local variable of Thread. When using ThreadLocal to maintain variables, ThreadLocal provides an independent copy of the variable for each thread that uses the variable, so each thread can change its own copy independently without affecting the corresponding copies of other threads.
  • ThreadLocal provides a separate storage space for each thread, which has the effect of thread isolation. The corresponding value can only be obtained within the thread, and cannot be accessed outside the thread.
2. Why can ThreadLocal be used?

For each HTTP request sent by the client, a corresponding new thread will be allocated on the server side for processing. During the processing, the methods involved in the following classes all belong to the same thread:
1. The doFilter method (filter) of LoginCheckFilter
2. The update method of EmployeeController (controller)
3. The updateFill method of MyMetaObjectHandler (custom metadata object handler)
The following code can be added to the above three methods respectively (get the current thread id)

long id = Thread.currentThread().getId( ;
log.info("thread id:{}",id);

By observing the console output, it can be found that the thread id corresponding to a request is the same:

3.ThreadLocal common methods:

public void set(T value) sets the value of the thread local variable of the current thread
public T get() returns the value of the thread local variable corresponding to the current thread

2.2.2 ThreadLocal implementation steps

1. Write the BaseContext tool class, based on the tool class encapsulated by ThreadLocal
2. Call BaseContext in the doFilter method of LoginCheckFilter to set the id of the currently logged in user
3. Call BaseContext in the method of MyMetaObjectHandler to obtain the id of the logged-in user

BaseContext.class tool class:

/**
 * Based on the ThreadLocal encapsulation tool class, used to save and get the id of the currently logged in user
 * ThreadLocal takes threads as the scope, and each individual thread has each data
 */
public class BaseContext {<!-- -->

    // The generic type is the type of user id
    private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    /**
     * Settings
     */
    public static void setCurrentId(Long id) {<!-- -->
        threadLocal. set(id);
    }

    /**
     * get value
     * @return
     */
    public static Long getCurrentId() {<!-- -->
        return threadLocal. get();
    }
}

In the doFilter method of LoginCheckFilter.class:
(I pass in the id after the login is successful)

// 4. Determine the login status, if it is already logged in, it will be released directly
        // Get the Session, let it go if it is not empty
        if (request.getSession().getAttribute("employee") != null) {<!-- -->
            log.info("The user has logged in, the user id is: {}", request.getSession().getAttribute("employee"));

            // Use ThreadLocal to pass in the user id here
            BaseContext.setCurrentId((Long) request.getSession().getAttribute("employee"));

            filterChain.doFilter(request, response);
            return;
        }

MyMetaObjectHandler.class In the custom metadata object handler class:

/**
 * Custom metadata object handler
 */
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {<!-- -->
    /**
     * Insert operation autofill
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {<!-- -->
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime", LocalDateTime.now());

        // Get the id saved by ThreadLocal
        Long currentId = BaseContext. getCurrentId();
        metaObject.setValue("createUser", currentId);
        metaObject.setValue("updateUser", currentId);

    }

    /**
     * Update operation autofill
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {<!-- -->
        Long currentId = BaseContext. getCurrentId();

        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("updateUser", currentId);

    }
}

3. Summary

Using the public field autofill function in Mybatis-Plus can simplify development, the steps are as follows:

1. Add the annotation @TableField(fill = FieldFill.INSERT) or @TableField(fill = FieldFill.INSERT_UPDATE) to the entity class that needs to be automatically filled with public fields, indicating that public fields are automatically filled when inserting and updating data.
2. Create a MyMetaObjectHandler class and implement the MetaObjectHandler interface.
3. Implement the insertFill and updateFill methods in this class to fill public fields.
4. To fill the createUser and updateUser fields, you need to use ThreadLocal, write the BaseContext tool class, based on the tool class encapsulated by ThreadLocal,
Then call BaseContext in the doFilter method of LoginCheckFilter to set the id of the currently logged in user, and finally call BaseContext in the method of MyMetaObjectHandler to get the id of the logged in user

Note: We cannot obtain the HttpSession object in the MyMetaObjectHandler class, so we cannot use HttpSession to solve it.