How to Customize Code Generator Templates in ContiNew-Admin: A Complete Guide
ContiNew-Admin's code generator uses a two-layer customization system: YAML configuration defines which templates to render and where to place files, while Freemarker .ftl files control the actual code skeleton.
ContiNew-Admin includes a powerful code generator plugin that automates the creation of backend Java classes and frontend Vue components from database metadata. Understanding how to customize these code generator templates allows you to tailor the output to your specific project standards without modifying core generator logic. The system separates configuration from presentation, enabling template customization through simple YAML edits and Freemarker file modifications.
Understanding the Two-Layer Architecture
The generator operates through two independent layers that work together during the code generation process.
Template Configuration Layer
The template configuration controls which templates are rendered, their output destinations, file extensions, and whether they target the backend or frontend. This configuration lives in application-generator.yml (or any Spring Boot YAML file that merges into the generator prefix).
The GeneratorProperties class binds these settings into a usable structure:
@ConfigurationProperties(prefix = "generator")
public class GeneratorProperties {
// Binds generator.templateConfigs map from YAML
}
Located at continew-plugin/continew-plugin-generator/src/main/java/top/continew/admin/generator/config/properties/GeneratorProperties.java, this POJO captures the generator.* section and makes it available to the generation service.
Freemarker Template Execution Layer
The Freemarker template files define the actual source code skeleton using placeholders filled with values from InnerGenConfigDO. These templates reside in:
- Backend templates:
continew-plugin/continew-plugin-generator/src/main/resources/templates/backend/*.ftl - Frontend templates:
continew-plugin/continew-plugin-generator/src/main/resources/templates/frontend/*.ftl
In GeneratorServiceImpl.java (lines 341-342), the service creates a TemplateEngine instance and renders the template:
engine.getTemplate(templatePath).render(BeanUtil.beanToMap(innerGenConfig))
The rendered text becomes both the preview content displayed in the UI and the eventual file written to disk.
The Code Generation Flow in Detail
Understanding the internal flow helps you customize templates effectively. The process follows these exact steps as implemented in GeneratorServiceImpl:
-
Load configuration –
GeneratorPropertiesbinds the YAML configuration into a Java map accessible viageneratorProperties.getTemplateConfigs(). -
Collect metadata –
MetaUtils.getTables()andMetaUtils.getColumns()pull schema information from the configuredDataSource. -
Prepare template data –
InnerGenConfigDOaggregates class name prefixes, package paths, import statements, and field lists. TheconvertToFieldConfigDOmethod resolves dictionary enums and adds necessary imports. -
Iterate and render – Inside the
preview(String tableName)method, the service loops throughtemplateConfigMap.entrySet(). For each template:- Filters fields listed in
templateConfig.excludeFields - Sets sub-package and class name via
innerGenConfig.setSubPackageName() - Renders the template using the Freemarker engine with
BeanUtil.beanToMap(innerGenConfig)converting the data object to aMap<String, Object>
- Filters fields listed in
-
Write output – The
generateCode()ordownloadCode()methods write the rendered string to disk. Backend paths resolve tocontinew-admin/continew-system/src/main/java/...while frontend components land undercontinew-admin-ui/src/views/....
Because the template engine receives a plain Map<String, Object>, any new field added to InnerGenConfigDO automatically becomes available as a ${placeholder} in your .ftl files.
Practical Customization: Adding a Backend DTO Template
To add a custom DTO template, modify both the YAML configuration and create the corresponding .ftl file.
Step 1: Configure the template in application-generator.yml
generator:
templateConfigs:
Dto:
templatePath: backend/Dto.ftl
packageName: model.dto
excludeFields:
- id
- createUser
- createTime
- updateUser
- updateTime
extension: .java
suffix: Dto
Step 2: Create the template file at continew-plugin/continew-plugin-generator/src/main/resources/templates/backend/Dto.ftl
package ${innerGenConfig.subPackageName};
import lombok.Data;
<#if innerGenConfig.imports?has_content>
<#list innerGenConfig.imports as imp>
import ${imp};
</#list>
</#if>
@Data
public class ${innerGenConfig.className} {
<#list innerGenConfig.fieldConfigs as field>
/** ${field.columnComment} */
private ${field.fieldType} ${field.fieldName};
</#list>
}
When generating code for a table named user, this produces UserDto.java in the model.dto package, excluding audit fields like createTime and updateUser.
Practical Customization: Creating a Frontend Search Panel
Frontend customization follows the same pattern, using the backend: false flag.
Step 1: Add the configuration
generator:
templateConfigs:
SearchPanel:
templatePath: frontend/SearchPanel.ftl
packageName: src/views
extension: .vue
backend: false
Step 2: Create the Vue template
<template>
<div class="search-panel">
<el-form :model="query">
<#list innerGenConfig.fieldConfigs as field>
<#if field.showInQuery>
<el-form-item label="${field.columnComment}">
<el-input v-model="query.${field.fieldName}" placeholder="请输入${field.columnComment}" />
</el-form-item>
</#if>
</#list>
<el-form-item>
<el-button type="primary" @click="search">搜索</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import { ref } from 'vue';
const query = ref({});
function search() {
console.log('search params:', query.value);
}
</script>
<style scoped>
.search-panel { padding: 16px; }
</style>
This generates SearchPanel.vue under continew-admin-ui/src/views/<moduleName>/, including only fields marked for query display.
Triggering Generation via the REST API
The generator exposes REST endpoints through GeneratorController.java for programmatic access:
Preview generated files:
curl -X POST "http://localhost:8080/api/generator/preview" \
-H "Content-Type: application/json" \
-d '{"tableNames":["user"]}'
Download as ZIP:
curl -X POST "http://localhost:8080/api/generator/download" \
-H "Content-Type: application/json" \
-d '{"tableNames":["user"]}' \
-o continew-code.zip
Generate directly to disk:
curl -X POST "http://localhost:8080/api/generator/generate" \
-H "Content-Type: application/json" \
-d '{"tableNames":["user"]}'
These endpoints accept the table names and execute the full generation flow using your customized templates.
Summary
- Two-layer architecture: YAML configuration controls rendering logic while Freemarker
.ftlfiles define code structure. - Configuration location: Edit
application-generator.ymlto add or modify template entries, defining paths, extensions, and exclusions. - Template location: Place backend templates in
templates/backend/and frontend templates intemplates/frontend/within the generator plugin module. - Data model:
InnerGenConfigDOprovides the data map; extending it adds new placeholders for templates. - Hot reload: Template changes apply immediately on the next generation request without recompiling the Java code.
- Entry points: Use
GeneratorControllerendpoints or the admin UI to trigger generation with custom templates.
Frequently Asked Questions
Where are the default generator templates located in the source code?
Default templates reside in continew-plugin/continew-plugin-generator/src/main/resources/templates/, separated into backend/ for Java files (entities, services, controllers) and frontend/ for Vue components. The default configuration mapping these templates is defined in continew-server/src/main/resources/config/application-generator.yml.
Do I need to restart the application after modifying templates?
No restart is required for Freemarker template changes (.ftl files), as they are read at request time. However, if you modify application-generator.yml to add new template configurations, you must restart the Spring Boot application to rebind the GeneratorProperties configuration class.
How do I add custom variables to my Freemarker templates?
Add fields to the InnerGenConfigDO class located in the generator plugin module. Since GeneratorServiceImpl converts this object to a Map using BeanUtil.beanToMap(), any new getter methods automatically become available as ${variableName} placeholders in your templates.
Can I exclude specific database columns from generated code?
Yes. Use the excludeFields list in your template configuration within application-generator.yml. Specify the Java field names (such as id, createTime, or updateUser) to remove them from that specific template's output while retaining them in other generated files.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →