# Object Lifecycle Customization
The system supports customizing the logic at various points in an object's lifecycle through customization, including object creation, update, deletion, access, API data return, and search.
# Creation
The system supports customizing additional logic when an object is created through customization, which can be inserted at the following points:
- Before saving on creation: The object has been created in memory, all object properties have been constructed, but it has not yet been saved to the database.
- After saving on creation: The object's save method has been called, but the transaction has not yet been committed.
For the two types of customization described above, you need to create the following Dynamic Object Hook
objects respectively
Object Type: Select the object type this custom logic applies to
Hook Type: Select "Before creating"
Core Logic: Custom code, see the documentation below for available injected variables and return value conventions
2
3
Object Type: Select the object type this custom logic applies to
Hook Type: Select "After creating"
Core Logic: Custom code, see the documentation below for available injected variables and return value conventions
2
3
The injected variables that can be used in this custom code are shown in the following table:
Variable Name | Variable Type | Description |
---|---|---|
object | <? extends GormEntity> | Object instance |
dynamicFieldValues | List<tech.muyan.dynamic.field.DynamicFieldValue> | Values of all dynamic fields |
userContext | grails.plugin.springsecurity.userdetails.GrailsUser | Current operating user information |
application | grails.core.GrailsApplication | Current grails application context |
log | Closure<?> | Log closure for printing execution logs |
hookType | tech.muyan.enums.ObjectHookType | Type of the current executing object hook |
For return results and exception handling, please refer to the Return Results and Exception Handling section below.
WARNING
The dynamicFieldDefinition
parameter is only available in the customization point after saving on creation
# Update
The system supports customizing additional logic when an object is updated through customization, which can be inserted at the following points:
- Before updating: The object has been updated in memory, including all object properties including dynamic properties, but has not yet been saved to the database.
- After updating: The update methods for the object and all dynamic fields have been called, but the transaction has not yet been committed.
For the two types of customization described above, you need to create the following Dynamic Object Hook
objects respectively
Object Type: Select the object type this custom logic applies to
Hook Type: Select "Before updating"
Core logic: Custom code definition, see the documentation below for available injected variables and return value conventions
2
3
Object Type: Select the object type this custom logic applies to
Hook Type: Select "After updating"
Core logic: Custom code definition, see the documentation below for available injected variables and return value conventions
2
3
The injected variables that can be used in this custom code are shown in the following table:
Variable Name | Variable Type | Description |
---|---|---|
oldObject | <? extends GormEntity> | Copy of the object instance before update |
newObject | <? extends GormEntity> | Updated object instance including dynamic fields |
userContext | grails.plugin.springsecurity.userdetails.GrailsUser | Current operating user information |
application | grails.core.GrailsApplication | Current grails application context |
log | Closure<?> | Log closure for printing execution logs |
hookType | tech.muyan.enums.ObjectHookType | Type of the current executing object hook |
For return results and exception handling, please refer to the Return Results and Exception Handling section below.
# Deletion
The system supports customizing additional logic when an object is deleted through customization, which can be inserted at the following points:
- Before deletion: The object has been queried from the database, before the object's delete method is called
- After deletion: After the object's delete method has been called, before the transaction is committed
For the two types of customization described above, you need to create the following Dynamic Object Hook
objects respectively
Object Type: Select the object type this custom logic applies to
Hook Type: Select "Before deleting"
Core logic: Custom code definition, see the documentation below for available injected variables and return value conventions
2
3
Object Type: Select the object type this custom logic applies to
Hook Type: Select "After deleting"
Core logic: Custom code definition, see the documentation below for available injected variables and return value conventions
2
3
The injected variables that can be used in this custom code are shown in the following table:
Variable Name | Variable Type | Description |
---|---|---|
object | <? extends GormEntity> | Object to be deleted |
userContext | grails.plugin.springsecurity.userdetails.GrailsUser | Current operating user information |
application | grails.core.GrailsApplication | Current grails application context |
log | Closure<?> | Log closure for printing execution logs |
hookType | tech.muyan.enums.ObjectHookType | Type of the current executing object hook |
For return results and exception handling, please refer to the Return Results and Exception Handling section below.
# Return Results and Exception Handling
In the customization logic before an operation, you can directly modify the object instance parameter to implement customization, and modifications to the object instance will be saved to the database.
During the execution of the customization code logic before and after the operation, exceptions can be thrown to interrupt the system's operation process on the object, as detailed below:
If an exception of type
tech.muyan.exception.CustomLogicInterruptException
or its subtype is caught, the object's operation process will be interrupted, the operation will not be saved to the database, and the Message of the exception will be displayed to the user as an error in the frontend.If an exception of type
tech.muyan.exception.CustomLogicWarningException
or its subtype is caught, the object's operation process will not be interrupted, but the Message of the exception will be displayed to the user as a warning in the frontend.
TIP
At the customization point before saving on creation, the id field of the object is empty. At the customization point after saving on creation, the id field of the object has already obtained a value.
# API Return Data Customization
The system supports customizing the structure and values of object data returned by the API interface to the frontend for a certain object through customization. Create the following Dynamic Object Hook
object to implement this customization.
Object Type: Select the object type this custom logic applies to
Logic Type: Select "Object render"
Core logic: Custom code, see the documentation below for available injected variables and return value conventions
2
3
- Injected variables
The injected variables that can be used in this custom code are shown in the following table:
Variable Name | Variable Type | Description |
---|---|---|
object | <? extends GormEntity> | Object instance to be returned by the interface |
userContext | grails.plugin.springsecurity.userdetails.GrailsUser | Current operating user information |
application | grails.core.GrailsApplication | Current grails application context |
page | tech.muyan.enums.CustomRenderPageType | Page calling this render method |
log | Closure<?> | Log closure for printing execution logs |
ownerClass | java.lang.Class<? extends GormEntity> | For search pages, the object owning the search field |
fieldName | java.lang.String | For search pages, the name of the search field |
fetchType | tech.muyan.enums.FetchType | Type of data retrieval |
The fetchType
parameter selects the range of data to be returned based on different business scenarios on the interface. The current optional values are explained as follows:
Value | Description |
---|---|
ONLY_LABEL_FIELD | Only retrieve the Label field and id |
EXCLUDE_ARRAY_COLUMNS | Return values of all fields except one-to-many and many-to-many associated objects |
ALL_COLUMNS | Return values of all fields |
The optional values for the page parameter are as follows:
Value | Description |
---|---|
RELATED_SEARCH | Related object list page with search conditions |
RELATED | Related object list page |
LIST_SEARCH | Main list page with search conditions |
LIST | Main list page |
FINDER | Search page |
FINDER_SEARCH | Search page with search conditions |
DETAIL | Detail or edit page |
SHOW_MULTIPLE | Return value of Show multiple API |
WARNING
In non-search result rendering scenarios, the injected ownerClass field is empty. Please pay attention to compatibility when implementing the render API.
- Return result
The result that needs to be returned by this custom code is a Map data type or an instance of an org.grails.datastore.gorm.GormEntity
object.
When the return value is of Map type, the Key of the Map is "result", and the Value of the Map is another Map. The key of this inner Map is the name of each field, and the value is the value of the field. The system will return the JSON representation of this Map data to the client calling the API.
// ่ฏฅๅฎขๅถๅไปฃ็ ้่ฆ่ฟๅ็็ปๆไธบไธไธช Map, key ไธบ result, value ไธญไธบ [่ฟๅๅญๆฎตๅ: ๅญๆฎตๅผ] ็ Map ็ๆ ผๅผ่ฟๅ็ปๆ
// The result returned by the custom code needs to be a Map, with a key of result and a value of [return field name: field value] in the format of a Map
[
result: [
columnName: columnValue,
// ๅฏน่ฑก็ฑปๅ็ๅญๅญๆฎต่ฟๅไธไธชๅชๅ
ๅซ id ็ๅญ map
objectField: [
id: objectId
],
// ็จไบ card list view ่ฟ่ก HTML ๆธฒๆ็ๅฑๆง
"@HTML_CONTENT@": ""
]
]
// ๆ่
็ดๆฅไธบไธไธช org.grails.datastore.gorm.GormEntity ๅฏน่ฑก็ๅฎไพ
// Or directly return an instance of an org.grails.datastore.gorm.GormEntity object
return object
2
3
4
5
6
7
8
9
10
11
12
13
14
15
System Limitations
- Currently, this customization only applies to entity classes that do not include dynamic fields.
- Card list rendering
In the table rendering interface, users can switch between table and card display modes.
Specifically, if the data returned by the render API includes a property named @HTML_CONTENT@, when rendering the card list view, the system will directly render the value of this property in the card, instead of displaying the details of the object in table form.
# Object Detail Access
The system supports calling custom logic when object details are viewed through customization. A more intuitive application scenario is an object access counter.
Currently, the calling point for this customization is: When an object is accessed through the /show/<domainId>
interface
For this customization, you need to create the following Dynamic Object Hook
object
Object Type: Select the object type this custom logic applies to
Hook Type: Select "Object access"
Code: Custom code, see the documentation below for available injected variables and return value conventions
2
3
The injected variables that can be used in this custom code are shown in the following table:
Variable Name | Variable Type | Description |
---|---|---|
object | <? extends GormEntity> | Object instance |
renderedObject | <? extends GormEntity> or Map<String, Object> | Object instance or Map object containing object data returned by Render API |
userContext | grails.plugin.springsecurity.userdetails.GrailsUser | Current operating user information |
application | grails.core.GrailsApplication | Current grails application context |
fetchType | tech.muyan.enums.FetchType | Type of data retrieval |
log | Closure<?> | Log closure for printing execution logs |
hookType | tech.muyan.enums.ObjectHookType.ACCESS | Type of the current executing object hook |
Tip
This customization has no return value and should not modify the object to be accessed. The ACCESS customization should not modify the value of the object to be rendered, but should only implement logic such as object access counting.
Tip
The difference between this customization point and the render API is that
this customization point is only called when the details of an object are requested, corresponding to the system code, when the DomainDataController.show
method is called.
While the render API is called in various scenarios where object data is requested, such as object lists, creating, returning data after updating objects, returning object lists after searching, etc.
# Attachment Storage and Return Customization
To support requirements such as virus scanning, encryption, and decryption, the system supports calling custom code to transform attachment content when writing and reading attachment content. This transformation is implemented through the RENDER API of the StorageFieldValue
object.
When creating an attachment, in the render customization code, you can obtain the original attachment file data through the object.getData()
method, and by setting the data attribute of the same object, you can inject the transformed file data into the save node and save it in the file storage engine.
When reading an attachment, in the render code, you can obtain the file data stored in the storage engine through the object.getData()
method, and by setting the data attribute of the same object, you can inject the transformed file data into the return data node and return it to the caller.
For specific injected parameters of the customization API, please refer to the API Return Data Customization section.