Fields such as creatby, updateby, etc. are automatically filled
When inserting each field into the database or updating, it is necessary to fill fields such as creatby, updateby, etc. at the serviceimpl layer. This is too cumbersome. The following two methods can realize automatic filling of fields. This project uses the first type.
Method 1:
First create an AutoFillInterceptor class. The code will be analyzed line by line below.
The following code can also be copied and pasted directly, but only if the fields in your entity class are the same as the following four static constant names.
@Component @Intercepts({ @Signature(type = , method = "update", args = {, }) }) public class AutoFillInterceptor implements Interceptor { private static final String CREATE_BY = "createdBy"; private static final String UPDATE_BY = "updatedBy"; private static final String CREATE_TIME = "createdAt"; private static final String UPDATE_TIME = "updatedAt"; @Override public Object intercept(Invocation invocation) throws Throwable { Object[] args = (); MappedStatement ms = (MappedStatement) args[0]; SqlCommandType sqlCommandType = (); Object parameter = args[1]; if(parameter != null && sqlCommandType!=null){ if((sqlCommandType)){ if(parameter instanceof ){ paramMap = () parameter; ArrayList list= (ArrayList) ("list"); (v->{ setFieldValByName(CREATE_TIME, (), v); setFieldValByName(UPDATE_TIME, (), v); }); ("list", list); }else{ // Single insertion // Set the create person and create time field values setFieldValByName(CREATE_TIME, (), parameter); setFieldValByName(UPDATE_TIME, (), parameter); } } else if((sqlCommandType)){ // Update operation // Set the update person and update time field values setFieldValByName(UPDATE_TIME, (), parameter); } } // Continue to execute the original method return (); } private void setFieldValByName(String fieldName, Object fieldVal, Object parameter) { MetaObject metaObject = (parameter); if ((fieldName)) { (fieldName, fieldVal); } } @Override public void setProperties(Properties properties) { (properties); } @Override public Object plugin(Object target) { return (target); } }
Code structure and function
This is an implementation of MyBatis interceptor (Interceptor
Interface classAutoFillInterceptor
, used to automatically fill some common fields when performing SQL operations (INSERT or UPDATE), such as creation time (createdAt
), update time (updatedAt
)wait.
In enterprise-level projects, it is usually necessary to record the creation time and modification time of data. This interceptor is to solve this requirement and automatically fill these fields when adding and modifying data. Let's analyze the code line by line.
Line by line analysis
@Component @Intercepts({ @Signature(type = , method = "update", args = {, }) })
-
@Component
: Spring annotation, register this class as a Spring bean for easy management. -
@Intercepts
: MyBatis annotation, declares that this is an interceptor and specifies the target to be intercepted.-
@Signature
: Define the specific interception method of the interceptor.-
type =
: Indicates intercepting MyBatisExecutor
kind. -
method = "update"
: Indicates interceptionupdate
Method, this method is used to perform update operations (including INSERT, UPDATE, DELETE). -
args = {, }
:Specifyupdate
The parameter type of the method, that is, SQL mapping informationMappedStatement
and parameter objectsObject
。
-
-
public class AutoFillInterceptor implements Interceptor {
- These lines define some constants that represent field names, such as creator, modifyer, creation time, and modification time. These constants will be used in intercept logic to automatically populate fields.
@Override public Object intercept(Invocation invocation) throws Throwable { Object[] args = (); MappedStatement ms = (MappedStatement) args[0]; SqlCommandType sqlCommandType = (); Object parameter = args[1];
-
intercept
The method is the core logic of the interceptor.-
Object[] args = ()
: Get parameters of the intercept method. -
MappedStatement ms = (MappedStatement) args[0]
: GetMappedStatement
, contains information about SQL statements. -
SqlCommandType sqlCommandType = ()
: Get the operation type of SQL (INSERT, UPDATE, DELETE). -
Object parameter = args[1]
: Get parameter objects, usually data that the user wants to insert or update.
-
if(parameter != null && sqlCommandType != null){
- Check whether the parameters are empty and confirm whether the operation type is not empty to ensure that it is necessary to continue to perform subsequent operations.
if((sqlCommandType)){ if(parameter instanceof ){ paramMap = () parameter; ArrayList list= (ArrayList) ("list"); (v -> { setFieldValByName(CREATE_TIME, (), v); setFieldValByName(UPDATE_TIME, (), v); }); ("list", list); } else { // Single insertion // Set the create person and create time field values setFieldValByName(CREATE_TIME, (), parameter); setFieldValByName(UPDATE_TIME, (), parameter); } }
-
if ((sqlCommandType))
: If the current SQL is an INSERT operation:-
if (parameter instanceof )
: Determine whether the parameter istype, which is usually used for batch insertion.
-
ArrayList list = (ArrayList) ("list")
: Get the name from the parameter Maplist
The parameter is a set of data inserted in batches. -
(v -> {...})
: Perform operations on each element and callsetFieldValByName
Method SettingscreatedAt
andupdatedAt
is the current time.
-
-
else
Part: Handle the case of single insertion, give it directlyparameter
Object settings creation time and update time.
-
else if((sqlCommandType)){ // Update operation // Set the update person and update time field values setFieldValByName(UPDATE_TIME, (), parameter); }
-
else if ((sqlCommandType))
: If the current SQL is a UPDATE operation:- use
setFieldValByName
Method willupdatedAt
The field is set to the current time.
- use
} // Continue to execute the original method return (); }
- Finally passed
()
Call the intercepted method and continue to perform the original database operation.
private void setFieldValByName(String fieldName, Object fieldVal, Object parameter) { MetaObject metaObject = (parameter); if ((fieldName)) { (fieldName, fieldVal); } }
-
setFieldValByName
Methods are used to set the value of the specified field in the object:-
MetaObject metaObject = (parameter)
:createMetaObject
, used to manipulate the metadata of the incoming object. -
if ((fieldName))
: Check whether the object has a setter method for corresponding fields. -
(fieldName, fieldVal)
: If there is a setter method, set the value of the field.
-
@Override public void setProperties(Properties properties) { (properties); } @Override public Object plugin(Object target) { return (target); } }
-
setProperties
andplugin
The method isInterceptor
The default implementation of the interface,plugin
Methods are used to generate proxy objects.
Summarize
- The function of this interceptor is to fill automatically
createdAt
andupdatedAt
Fields to automatically record creation and update times when INSERT and UPDATE operations are performed. - Main interception
Executor
ofupdate
Method: determine whether it is an INSERT or UPDATE operation by determining the SQL type, thereby setting the corresponding field. - Using MyBatis
MetaObject
Tool class to dynamically operate the field values of parameter objects.
With this interceptor, developers do not need to manually set it in business codecreatedAt
andupdatedAt
, greatly reduces duplicate code and ensures the consistency and correctness of these public fields.
Method 2:
This method is written using custom annotations, so add this annotation to the SQL that needs to be filled. This may be more flexible and simple.
Public fields are automatically filled
Technical points: enumeration, annotation, AOP, reflection
Create time, modify time, create person, and modify person.
Annotate the mapper method AutoFill, and the identification needs to be automatically filled with public fields
Customize the section class AutoFillAspect, and unified intercepts the method of adding AutoFill annotation, assigning values to public fields through reflection.
Connect AutoFill annotations to the Mapper method.
public enum OperationType { Update operation UPDATE, Insert operation INSERT } @Target()Where is the current annotation added @Retention() public @interface AutoFill { //Database operation type: UPDATE INSERT OperationType value(); }
Supplementary annotation basic knowledge
public @interface MyAnnotation { // Define the members of the annotation String value(); // This is a member named "value" int count() default 1; // This is a member named "count" with default values} @MyAnnotation(value = "Hello", count = 3) public class MyClass { // Class code}
For AutoFillAspect classPoint-cutting, execution expression
/** * Customize the section to realize the automatic filling processing logic of common fields */ @Aspect @Component @Slf4j public class AutoFillAspect { /** * Point of entry */ All classes,All methods,All parameter types @Pointcut("execution(* .*.*(..)) && @annotation()") public void autoFillPointCut(){} /** * Pre-notification, assign public fields in the notification */ @Before("autoFillPointCut()")Specify entry point public void autoFill(JoinPoint joinPoint){Connection point ("Start the public field autofill..."); //Get the database operation type on the currently intercepted method MethodSignature signature = (MethodSignature) ();//Method Signature Object AutoFill autoFill = ().getAnnotation();//Get the annotation object on the method OperationType operationType = ();//Get database operation type //Get the parameters of the currently intercepted method - Entity object Make a convention and place the first entity object Object[] args = (); if(args == null || == 0){ return; } Object entity = args[0];entity //Prepare the assigned data LocalDateTime now = (); Long currentId = (); //Depend on the current different operation types, the corresponding attributes are assigned through reflection to the corresponding attributes if(operationType == ){ // Assign values to 4 public fields try { Method setCreateTime = ().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, ); Method setCreateUser = ().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, ); Method setUpdateTime = ().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, ); Method setUpdateUser = ().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, ); // Assign value to object attributes through reflection (entity,now); (entity,currentId); (entity,now); (entity,currentId); } catch (Exception e) { (); } }else if(operationType == ){ // Assign values to 2 public fields try { Method setUpdateTime = ().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, ); Method setUpdateUser = ().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, ); // Assign value to object attributes through reflection (entity,now); (entity,currentId); } catch (Exception e) { (); } } } }
use
@AutoFill(value = ) void update(Employee employee);
Customized sections: Implement automatic filling of common fields
This code uses Spring AOP (sectional programming) to automatically fill in some common fields when operating the database, such as creation time, update time, create person, update person, etc. Next, we parse this code line by line to help you understand the functions and implementation logic of each part.
Code structure overview
@Aspect @Component @Slf4j public class AutoFillAspect { // entry point @Pointcut("execution(* .*.*(..)) && @annotation()") public void autoFillPointCut(){} // Pre-Notice @Before("autoFillPointCut()") public void autoFill(JoinPoint joinPoint){ ("Start the public field autofill..."); ... } }
This code defines a sectionAutoFillAspect
, it will use a pre-notification before the database operation method that meets the criteria is executed (@Before
) Automatically populate certain public fields.
Annotation explanation
-
@Aspect
: Indicates that the current class is a facet class that defines notifications and entry points. -
@Component
: Register this aspect class as a component in the Spring container. -
@Slf4j
: Used to enable logging function to facilitate debugging and logging information.
Point-cut definition
@Pointcut("execution(* .*.*(..)) && @annotation()") public void autoFillPointCut(){}
explain:
-
@Pointcut
: Used to define an entry point and describe which methods need to be intercepted by facet logic. -
execution(* .*.*(..))
: MatchAll classes and methods under the package,
(..)
Represents any parameter type and quantity. -
&& @annotation()
: It means only intercepting@AutoFill
The method of annotating marks.
Through this definition, only the classes that meet the specified package and have@AutoFill
The annotation method will be intercepted by the facet logic.
Before Advice
@Before("autoFillPointCut()") public void autoFill(JoinPoint joinPoint) { ("Start the public field autofill..."); ... }
- @Before("autoFillPointCut()"): This is a pre-notice, indicating that the autoFill() method is executed before the method matched by the point-cutting is executed.
- JoinPoint joinPoint: JoinPoint is a connection point that represents the intercepted method, allowing some information about the target method, such as method name and parameters.
Get annotation and method information
MethodSignature signature = (MethodSignature) (); AutoFill autoFill = ().getAnnotation(); OperationType operationType = ();
-
MethodSignature signature = (MethodSignature) ();
: Get the signature information of the currently intercepted method and convert it toMethodSignature
type. -
AutoFill autoFill = ().getAnnotation();
: Obtain the method@AutoFill
Annotate the object. -
OperationType operationType = ();
: Gets the database operation type specified in the annotation (for example, INSERT or UPDATE).
Get method parameters
Object[] args = (); if (args == null || == 0) { return; } Object entity = args[0];
-
Object[] args = ();
: Get the parameters of the currently intercepted method. -
if (args == null || == 0)
: If there are no parameters, return directly. -
Object entity = args[0];
: Assume that the first parameter is an entity object, used to operate the database. There is a convention here, that is, entity objects are always the first parameter.
Prepare the assigned data
LocalDateTime now = (); Long currentId = ();
-
LocalDateTime now = ();
: Get the current time to fill in the creation time and update time. -
Long currentId = ();
: Get the ID of the current operation user to populate the creator and updater information.
Assign values according to operation type
Insert operation (INSERT)
if (operationType == ) { try { Method setCreateTime = ().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, ); Method setCreateUser = ().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, ); Method setUpdateTime = ().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, ); Method setUpdateUser = ().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, ); (entity, now); (entity, currentId); (entity, now); (entity, currentId); } catch (Exception e) { (); } }
-
if (operationType == )
: If the database operation type is Insert (INSERT). - Obtain the entity class through reflection
setCreateTime
、setCreateUser
、setUpdateTime
andsetUpdateUser
method. -
invoke()
Methods are used to call these setter methods and pass in corresponding values to complete the assignment of public fields.
Update operation (UPDATE)
else if (operationType == ) { try { Method setUpdateTime = ().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, ); Method setUpdateUser = ().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, ); (entity, now); (entity, currentId); } catch (Exception e) { (); } }
-
else if (operationType == )
: If the operation type is Update (UPDATE). - Here you just need to fill in the fields related to update, that is, the update time and the update person.
summary
This code implements automatic filling of common fields for database operations, as follows:
- Define a section
AutoFillAspect
, used to intercept methods in specific packages, and the method needs to be@AutoFill
Annotations are marked. - Use AOP's pre-notification to auto-fill fields before method execution.
- The method of obtaining entity objects through reflection mechanism and assigning values, filling different fields according to the operation type.
This makes the code more concise and maintainable, reduces duplicate public field assignment logic, and facilitates consistency management of public attributes such as creation time and update time.
The above is the detailed content of two ways to implement automatic field filling in SpringBoot. For more information about automatic field filling in SpringBoot, please pay attention to my other related articles!