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:

  1. Load configurationGeneratorProperties binds the YAML configuration into a Java map accessible via generatorProperties.getTemplateConfigs().

  2. Collect metadataMetaUtils.getTables() and MetaUtils.getColumns() pull schema information from the configured DataSource.

  3. Prepare template dataInnerGenConfigDO aggregates class name prefixes, package paths, import statements, and field lists. The convertToFieldConfigDO method resolves dictionary enums and adds necessary imports.

  4. Iterate and render – Inside the preview(String tableName) method, the service loops through templateConfigMap.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 a Map<String, Object>
  5. Write output – The generateCode() or downloadCode() methods write the rendered string to disk. Backend paths resolve to continew-admin/continew-system/src/main/java/... while frontend components land under continew-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 .ftl files define code structure.
  • Configuration location: Edit application-generator.yml to add or modify template entries, defining paths, extensions, and exclusions.
  • Template location: Place backend templates in templates/backend/ and frontend templates in templates/frontend/ within the generator plugin module.
  • Data model: InnerGenConfigDO provides 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 GeneratorController endpoints 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →