# FAQ (Frequently Asked Questions)
# Target Audience
The target audience for this document is: Developers and implementers of this system
# Why is an enum field recognized as an object field by the system?
Please ensure that the package name of the enum field contains the 'enums' part, for example:
package tech.muyan.dynamic.task.enums // --> Package name contains 'enums' part, can be correctly recognized
Enum DynamicTaskType {
RUN_AT_STARTUP('RUN_AT_STARTUP'),
CRON_TASK('CRON_TASK'),
SCHEDULE_TASK('SCHEDULE_TASK'),
;
String value
}
2
3
4
5
6
7
8
9
10
11
This can be recognized normally, while the following enum will be recognized as an object type:
package tech.muyan.dynamic.task // --> Package name does not contain 'enums' part, cannot be correctly recognized
enum DynamicTaskType {
RUN_AT_STARTUP('RUN_AT_STARTUP'),
CRON_TASK('CRON_TASK'),
SCHEDULE_TASK('SCHEDULE_TASK'),
;
String value
}
2
3
4
5
6
7
8
9
10
11
# How to manually inject service definitions in customized code
During project implementation, for code reuse, some common logic may be defined in the system in the form of services. In customized Groovy code, you can conveniently find the service definition and call its related methods.
Refer to the following code to manually find the service definition from the bean registry by name, where authorityService is the name of the service, corresponding to the class name of the Service definition, with the first letter lowercase.
import tech.muyan.BeanHelper
import grails.core.GrailsApplication
GrailsApplication grailsApplication = (application as GrailsApplication)
AuthorityService authorityService = BeanHelper.getBean(grailsapplication, "authorityService")
2
3
4
5
# Default filter defined in the form is not working
Please confirm that the field used as a filter condition is included in the form fields. If the field used as a filter condition is not returned to the frontend, it cannot be used as a filter condition.
# Unable to successfully import extInfo field via CSV
Please confirm that for the extInfo field (stored in the database as JSON type) in the imported CSV, if the content contains quotation marks ("), use two double quotes ("") to escape, rather than using a backslash (\) to escape.
# Sharing global configurations, connections, or caching data between Dynamic Logic executions
In some scenarios, you may need to share some data across multiple Dynamic Logic executions, typical scenarios include:
- Saving and sharing some computationally expensive cached data
- Some configurations or resources that need to be shared globally, such as stateful connections to third-party systems, management of connections to Kafka, Message Queue, etc.
- There may be a business logic order between different Dynamic Logic executions, and unavoidably, the results of previous steps can be cached.
The current system provides the tech.muyan.helper.RegistryHelper
class for managing globally shared data, which can be accessed through:
RegistryHelper.memoryGet(key)
to retrieve cached data,RegistryHelper.memoryPut(key, value)
to set cached data and return the currently saved data,RegistryHelper.memoryRemove(key)
to remove cached data.
# User opens Dashboard, Widget reports an error
Error screenshot as follows:
First confirm:
- Please confirm that the jar file was not packaged on a Windows system. Currently, Grails has a bug that causes the class file names generated by compiling the gson file in the backend deployment package generated on Windows to be incorrect, resulting in all enum fields being passed to the frontend with incorrect values.
Solution:
- Find the action run corresponding to the commit SHA to be deployed from the Github action page, and directly download the deployment package generated by the action run.
- Package the backend application on MacOS or Linux.
# Backend starts normally but frontend connection shows 401 and cannot connect
Please check if the application.yml file is correct. Common problems include indentation or other format issues caused by modifications, which lead to related configurations not being correctly read by the system. You can try restoring the application.yml file to the original version in the template repository or from someone else.
# After the system frontend and backend go live, frontend requests to backend APIs report errors or users cannot log in, blank screen, etc.
Please try the following operations:
- On the web server side, delete or force refresh the nginx cache.
- On the browser side, clear the entries in the frontend
localStorage
. - On the browser side, delete or force refresh the browser cache.
# Domain contains nullable primitive type fields, object fails to save when the value is null
In the Domain definition, please define nullable primitive type fields as their corresponding wrapper types, such as changing int
to Integer
, double
to Double
, boolean
to Boolean
, etc.
# Fields contained in the Domain are not displayed on the frontend
Please check if the field is defined in the constraints
of the Domain definition
static constraints = {
attachments nullable: true
}
2
3
Here's an example configuration:
class Feedback implements Serializable, MultiTenant<Feedback>,
Auditable, Stampable<Feedback>, HasComment<Feedback> {
List<StorageFieldValue> attachments
static hasMany = [attachments: StorageFieldValue]
}
2
3
4
5
# Unable to save associations in One-to-many relationships
A usable definition can be found in DynamicMenu.groovy, which defines a parent field pointing to itself and a reversely referenced children field
For specific GORM documentation, refer to GORM Associations (opens new window)
class DynamicMenu implements MultiTenant<DynamicMenu>,
Auditable, Stampable<DynamicMenu>, Serializable {
// Other fields omitted
// Field in Many side pointing to One side
DynamicMenu parent
// Field in One side pointing to Many side
static hasMany = [children: DynamicMenu]
// Please note that you cannot explicitly define the children field using List<DynamicMenu> children
// Otherwise, GORM will not be able to save the parent field
static constraints = {
// Other constraints omitted
parent nullable: true
children nullable: true
}
static mapping = {
// No need to define mapping for the children field, it's only used as a reverse reference
parent index: 'dynamic_menu_parent_idx'
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# How to define a new Websocket interface
- Implement the
tech.muyan.websocket.WebSocketService
interface - Implement the
abstract String getWebSocketPath()
method to return the websocket path - Implement the
void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception
method to handle websocket messages
# How to define default values for fields in the first step of a Wizard
â đ Cookbook đŗ Docker â