jeecgboot/JeecgBoot · error · RuntimeException

解析SQL模板异常

Error message

解析SQL模板异常

What it means

Thrown by FreemarkerParseFactory.parseTemplate's catch-all when ANY exception occurs during FreeMarker template processing — template not found, syntax error in the .ftl, an undefined variable reference, the reserved-key collision (error 49), or an I/O error. The original message is logged but only the generic '解析SQL模板异常' is surfaced to the caller, which makes root-causing require the log.

Source

Thrown at jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/FreemarkerParseFactory.java:111

    public static String parseTemplate(String tplName, Map<String, Object> paras) {
        try {
            log.debug(" minidao sql templdate : " + tplName);
            StringWriter swriter = new StringWriter();
            Template mytpl = TPL_CONFIG.getTemplate(tplName, ENCODE);
            if (paras.containsKey(MINI_DAO_FORMAT)) {
                throw new RuntimeException("DaoFormat 是 minidao 保留关键字,不允许使用 ,请更改参数定义!");
            }
            paras.put(MINI_DAO_FORMAT, new SimpleFormat());
            mytpl.process(paras, swriter);
            String sql = getSqlText(swriter.toString());
            paras.remove(MINI_DAO_FORMAT);
            return sql;
        } catch (Exception e) {
            log.error(e.getMessage(), e.fillInStackTrace());
            log.error("发送一次的模板key:{ " + tplName + " }");
            //System.err.println(e.getMessage());
            //System.err.println("模板名:{ "+ tplName +" }");
            throw new RuntimeException("解析SQL模板异常");
        }
    }

    /**
     * 解析ftl
     *
     * @param tplContent 模板内容
     * @param paras      参数
     * @return String 模板解析后内容
     */
    public static String parseTemplateContent(String tplContent,Map<String, Object> paras) {
        return parseTemplateContent(tplContent, paras, false);
    }
    public static String parseTemplateContent(String tplContent, Map<String, Object> paras, boolean keepSpace) {
        try {
            String sqlUnderline="sql_";
            StringWriter swriter = new StringWriter();
            if (stringTemplateLoader.findTemplateSource(sqlUnderline + tplContent.hashCode()) == null) {

View on GitHub (pinned to 96fb33f5ec)

Solutions

  1. Read the preceding log.error lines — they print the real exception message and the offending template name.
  2. Confirm the .ftl file exists at the expected path and is packaged in the jar/war resources.
  3. Align every ${param} in the template with keys actually supplied in the paras map.
  4. If caused by error 49, fix the reserved key first.

Example fix

# before
# userList.ftl contains ${undefinedVar}
FreemarkerParseFactory.parseTemplate("userList.ftl", paras); // -> 解析SQL模板异常

# after
# fix the template to reference only supplied params
SELECT * FROM sys_user WHERE id = :id
Defensive patterns

Strategy: try-catch

Validate before calling

// sanity: template exists and params cover interpolations
if (!templateLoader.exists(tplName)) throw new IllegalArgumentException("missing tpl");

Type guard

public static boolean templateReady(String tpl, Set<String> keys){ return tpl != null && !tpl.trim().isEmpty(); }

Try / catch

try { FreemarkerParseFactory.parseTemplate(tplName, paras); }
catch (RuntimeException e) { log.error("parse failed for {}: {}", tplName, e.getMessage()); throw e; }

Prevention

When it happens

Trigger: An .ftl template referenced by tplName does not exist in the template loader; a ${var} in the template has no matching key in paras; invalid FreeMarker syntax; a map key collision (DaoFormat); or the template string itself is malformed SQL after rendering.

Common situations: Renaming a DAO method without renaming its .ftl file; changing a parameter name but not the template; deploying a partial jar missing template resources; Freemarker version change introducing stricter parsing.

Related errors


AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14). Data as JSON: /api/errors/7ff56db7d5de72ca. Report an issue: GitHub.