Java实现模板引擎案例

wen java案例 1

本文目录导读:

Java实现模板引擎案例

  1. 简单的模板引擎实现
  2. 更完整的模板引擎(支持更多功能)
  3. 测试类
  4. 说明

我来为您提供一个完整的Java模板引擎实现案例,包含核心功能和示例:

简单的模板引擎实现

import java.util.*;
import java.util.regex.*;
/**
 * 简单的模板引擎实现
 */
public class SimpleTemplateEngine {
    // 变量替换模式:${variableName}
    private static final Pattern VARIABLE_PATTERN = 
        Pattern.compile("\\$\\{([^}]+)\\}");
    // 条件判断模式:{#if condition}...{/if}
    private static final Pattern IF_PATTERN = 
        Pattern.compile("\\{#if\\s+([^}]+)\\}(.*?)\\{/if\\}", Pattern.DOTALL);
    // 循环模式:{#foreach item in list}...{/foreach}
    private static final Pattern FOREACH_PATTERN = 
        Pattern.compile("\\{#foreach\\s+(\\w+)\\s+in\\s+(\\w+)\\}(.*?)\\{/foreach\\}", Pattern.DOTALL);
    private Map<String, Object> context = new HashMap<>();
    /**
     * 设置模板变量
     */
    public void setVariable(String name, Object value) {
        context.put(name, value);
    }
    /**
     * 批量设置模板变量
     */
    public void setVariables(Map<String, Object> variables) {
        context.putAll(variables);
    }
    /**
     * 渲染模板
     */
    public String render(String template) {
        if (template == null) {
            return "";
        }
        String result = template;
        // 处理条件判断
        result = processIfBlocks(result);
        // 处理循环
        result = processForeachBlocks(result);
        // 处理变量替换
        result = processVariables(result);
        return result;
    }
    /**
     * 处理条件判断
     */
    private String processIfBlocks(String template) {
        Matcher matcher = IF_PATTERN.matcher(template);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String condition = matcher.group(1).trim();
            String content = matcher.group(2);
            String replacement = evaluateCondition(condition) ? content : "";
            matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
        }
        matcher.appendTail(sb);
        return sb.toString();
    }
    /**
     * 评估条件表达式
     */
    private boolean evaluateCondition(String condition) {
        // 简化版条件评估
        if (condition.contains("==")) {
            String[] parts = condition.split("==");
            return getVariableValue(parts[0].trim())
                .equals(getVariableValue(parts[1].trim()));
        } else if (condition.contains("!=")) {
            String[] parts = condition.split("!=");
            return !getVariableValue(parts[0].trim())
                .equals(getVariableValue(parts[1].trim()));
        } else if (condition.contains(">")) {
            String[] parts = condition.split(">");
            try {
                double left = Double.parseDouble(getVariableValue(parts[0].trim()));
                double right = Double.parseDouble(getVariableValue(parts[1].trim()));
                return left > right;
            } catch (NumberFormatException e) {
                return false;
            }
        } else if (condition.contains("<")) {
            String[] parts = condition.split("<");
            try {
                double left = Double.parseDouble(getVariableValue(parts[0].trim()));
                double right = Double.parseDouble(getVariableValue(parts[1].trim()));
                return left < right;
            } catch (NumberFormatException e) {
                return false;
            }
        }
        // 直接变量判断
        return Boolean.parseBoolean(getVariableValue(condition));
    }
    /**
     * 处理循环
     */
    private String processForeachBlocks(String template) {
        Matcher matcher = FOREACH_PATTERN.matcher(template);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String itemName = matcher.group(1).trim();
            String listName = matcher.group(2).trim();
            String content = matcher.group(3);
            StringBuilder replacement = new StringBuilder();
            Object listObj = context.get(listName);
            if (listObj instanceof Collection) {
                Collection<?> list = (Collection<?>) listObj;
                for (Object item : list) {
                    Map<String, Object> oldContext = new HashMap<>(context);
                    context.put(itemName, item);
                    replacement.append(processVariables(content));
                    context.clear();
                    context.putAll(oldContext);
                }
            } else if (listObj != null && listObj.getClass().isArray()) {
                Object[] array = (Object[]) listObj;
                for (Object item : array) {
                    Map<String, Object> oldContext = new HashMap<>(context);
                    context.put(itemName, item);
                    replacement.append(processVariables(content));
                    context.clear();
                    context.putAll(oldContext);
                }
            }
            matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement.toString()));
        }
        matcher.appendTail(sb);
        return sb.toString();
    }
    /**
     * 处理变量替换
     */
    private String processVariables(String template) {
        Matcher matcher = VARIABLE_PATTERN.matcher(template);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String variablePath = matcher.group(1).trim();
            String value = getVariableValue(variablePath);
            matcher.appendReplacement(sb, Matcher.quoteReplacement(value));
        }
        matcher.appendTail(sb);
        return sb.toString();
    }
    /**
     * 获取变量值
     */
    private String getVariableValue(String path) {
        // 支持点号访问对象属性
        String[] parts = path.split("\\.");
        Object value = context.get(parts[0]);
        if (value == null) {
            return "null";
        }
        // 对象属性访问
        if (parts.length > 1) {
            for (int i = 1; i < parts.length; i++) {
                if (value instanceof Map) {
                    value = ((Map<?, ?>) value).get(parts[i]);
                } else {
                    // 使用反射访问属性
                    try {
                        String getter = "get" + parts[i].substring(0, 1).toUpperCase() 
                                      + parts[i].substring(1);
                        value = value.getClass().getMethod(getter).invoke(value);
                    } catch (Exception e) {
                        return "null";
                    }
                }
            }
        }
        return value != null ? value.toString() : "null";
    }
}
/**
 * 用户类(用于测试)
 */
class User {
    private String name;
    private int age;
    private String email;
    public User(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }
    public String getName() { return name; }
    public int getAge() { return age; }
    public String getEmail() { return email; }
    @Override
    public String toString() {
        return name;
    }
}

更完整的模板引擎(支持更多功能)

import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.regex.*;
/**
 * 高级模板引擎
 */
public class AdvancedTemplateEngine {
    private static final Map<String, Pattern> PATTERNS = new HashMap<>();
    private static final String CACHE_DIR = "template_cache";
    static {
        // 变量: {{ varName }}
        PATTERNS.put("variable", Pattern.compile("\\{\\{\\s*([^}]+?)\\s*\\}\\}"));
        // 循环: {% for item in items %}
        PATTERNS.put("for", Pattern.compile("\\{%\\s*for\\s+(\\w+)\\s+in\\s+(\\w+)\\s*%\\}(.*?)\\{%\\s*endfor\\s*%\\}", Pattern.DOTALL));
        // 条件: {% if condition %}
        PATTERNS.put("if", Pattern.compile("\\{%\\s*if\\s+(.+?)\\s*%\\}(.*?)(\\{%\\s*else\\s*%\\}(.*?))?\\{%\\s*endif\\s*%\\}", Pattern.DOTALL));
        // 注释: {# comment #}
        PATTERNS.put("comment", Pattern.compile("\\{#.*?#\\}", Pattern.DOTALL));
        // 包含: {% include "filename" %}
        PATTERNS.put("include", Pattern.compile("\\{%\\s*include\\s+[\"'](.+?)[\"']\\s*%\\}"));
    }
    private Map<String, Object> globalContext = new HashMap<>();
    private Map<String, String> templateCache = new HashMap<>();
    /**
     * 设置全局变量
     */
    public void setGlobalVariable(String name, Object value) {
        globalContext.put(name, value);
    }
    /**
     * 渲染字符串模板
     */
    public String render(String template, Map<String, Object> context) {
        Map<String, Object> mergedContext = new HashMap<>(globalContext);
        mergedContext.putAll(context);
        String result = template;
        // 1. 移除注释
        result = PATTERNS.get("comment").matcher(result).replaceAll("");
        // 2. 处理包含指令
        result = processIncludes(result, mergedContext);
        // 3. 处理循环
        result = processLoops(result, mergedContext);
        // 4. 处理条件
        result = processConditionals(result, mergedContext);
        // 5. 处理变量
        result = processVariables(result, mergedContext);
        return result;
    }
    /**
     * 从文件渲染模板
     */
    public String renderFile(String templatePath, Map<String, Object> context) throws IOException {
        String template = loadTemplate(templatePath);
        return render(template, context);
    }
    /**
     * 加载模板文件(带缓存)
     */
    private String loadTemplate(String path) throws IOException {
        if (templateCache.containsKey(path)) {
            return templateCache.get(path);
        }
        String content = new String(Files.readAllBytes(Paths.get(path)));
        templateCache.put(path, content);
        return content;
    }
    /**
     * 处理包含指令
     */
    private String processIncludes(String template, Map<String, Object> context) {
        Matcher matcher = PATTERNS.get("include").matcher(template);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String file = matcher.group(1);
            try {
                String includedContent = loadTemplate(file);
                String rendered = render(includedContent, context);
                matcher.appendReplacement(sb, Matcher.quoteReplacement(rendered));
            } catch (IOException e) {
                matcher.appendReplacement(sb, "<!-- Error including: " + file + " -->");
            }
        }
        matcher.appendTail(sb);
        return sb.toString();
    }
    /**
     * 处理循环
     */
    private String processLoops(String template, Map<String, Object> context) {
        Matcher matcher = PATTERNS.get("for").matcher(template);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String itemVar = matcher.group(1);
            String listVar = matcher.group(2);
            String content = matcher.group(3);
            Object listObj = context.get(listVar);
            StringBuilder result = new StringBuilder();
            if (listObj instanceof Collection) {
                for (Object item : (Collection<?>) listObj) {
                    Map<String, Object> newContext = new HashMap<>(context);
                    newContext.put(itemVar, item);
                    newContext.put("loop.index", ((Collection<?>) listObj).size());
                    result.append(processVariables(content, newContext));
                }
            } else if (listObj instanceof Map) {
                Map<?, ?> map = (Map<?, ?>) listObj;
                for (Map.Entry<?, ?> entry : map.entrySet()) {
                    Map<String, Object> newContext = new HashMap<>(context);
                    newContext.put(itemVar, entry.getValue());
                    newContext.put("loop.key", entry.getKey());
                    result.append(processVariables(content, newContext));
                }
            }
            matcher.appendReplacement(sb, Matcher.quoteReplacement(result.toString()));
        }
        matcher.appendTail(sb);
        return sb.toString();
    }
    /**
     * 处理条件语句
     */
    private String processConditionals(String template, Map<String, Object> context) {
        Matcher matcher = PATTERNS.get("if").matcher(template);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String condition = matcher.group(1).trim();
            String thenContent = matcher.group(2);
            String elseContent = matcher.group(4) != null ? matcher.group(4) : "";
            boolean result = evaluateCondition(condition, context);
            String replacement = result ? thenContent : elseContent;
            matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
        }
        matcher.appendTail(sb);
        return sb.toString();
    }
    /**
     * 评估条件
     */
    private boolean evaluateCondition(String condition, Map<String, Object> context) {
        condition = condition.trim();
        // 处理 NOT 操作
        if (condition.startsWith("not ")) {
            return !evaluateCondition(condition.substring(4), context);
        }
        // 处理 AND
        if (condition.contains(" and ")) {
            String[] parts = condition.split("\\s+and\\s+");
            for (String part : parts) {
                if (!evaluateCondition(part, context)) {
                    return false;
                }
            }
            return true;
        }
        // 处理 OR
        if (condition.contains(" or ")) {
            String[] parts = condition.split("\\s+or\\s+");
            for (String part : parts) {
                if (evaluateCondition(part, context)) {
                    return true;
                }
            }
            return false;
        }
        // 处理比较操作
        if (condition.matches(".*\\s*(==|!=|>=|<=|>|<)\\s*.*")) {
            String[] parts = condition.split("\\s*(==|!=|>=|<=|>|<)\\s*");
            if (parts.length == 2) {
                Object left = getValue(parts[0].trim(), context);
                Object right = getValue(parts[1].trim(), context);
                if (left instanceof Number && right instanceof Number) {
                    double l = ((Number) left).doubleValue();
                    double r = ((Number) right).doubleValue();
                    if (condition.contains(">")) return l > r;
                    if (condition.contains("<")) return l < r;
                    if (condition.contains(">=")) return l >= r;
                    if (condition.contains("<=")) return l <= r;
                }
                return left != null && left.equals(right);
            }
        }
        // 检查变量是否存在且为true
        Object value = getValue(condition, context);
        if (value instanceof Boolean) {
            return (Boolean) value;
        }
        return value != null && !value.toString().isEmpty();
    }
    /**
     * 获取值
     */
    private Object getValue(String path, Map<String, Object> context) {
        if (path.startsWith("'") && path.endsWith("'")) {
            return path.substring(1, path.length() - 1);
        }
        String[] parts = path.split("\\.");
        Object value = context.get(parts[0]);
        for (int i = 1; i < parts.length && value != null; i++) {
            if (value instanceof Map) {
                value = ((Map<?, ?>) value).get(parts[i]);
            } else {
                try {
                    String getter = "get" + Character.toUpperCase(parts[i].charAt(0)) + parts[i].substring(1);
                    value = value.getClass().getMethod(getter).invoke(value);
                } catch (Exception e) {
                    return null;
                }
            }
        }
        return value;
    }
    /**
     * 处理变量
     */
    private String processVariables(String template, Map<String, Object> context) {
        Matcher matcher = PATTERNS.get("variable").matcher(template);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String expression = matcher.group(1).trim();
            Object value = getValue(expression, context);
            String replacement = value != null ? value.toString() : "";
            matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
        }
        matcher.appendTail(sb);
        return sb.toString();
    }
}

测试类

import java.util.*;
public class TemplateEngineTest {
    public static void main(String[] args) {
        testSimpleTemplate();
        testAdvancedTemplate();
    }
    private static void testSimpleTemplate() {
        System.out.println("=== 简单模板引擎测试 ===");
        // 创建模板引擎
        SimpleTemplateEngine engine = new SimpleTemplateEngine();
        // 准备数据
        Map<String, Object> context = new HashMap<>();
        context.put("name", "张三");
        context.put("age", 25);
        List<User> users = Arrays.asList(
            new User("李四", 28, "lisi@example.com"),
            new User("王五", 32, "wangwu@example.com"),
            new User("赵六", 22, "zhaoliu@example.com")
        );
        context.put("users", users);
        engine.setVariables(context);
        // 模板字符串
        String template = """
            欢迎,${name}!
            你的年龄是${age}岁。
            {#if age >= 18}
            <h2>你已是成年人</h2>
            {/if}
            <h3>用户列表:</h3>
            {#foreach user in users}
            <p>用户名:${user.name},年龄:${user.age},邮箱:${user.email}</p>
            {/foreach}
            """;
        // 渲染
        String result = engine.render(template);
        System.out.println(result);
    }
    private static void testAdvancedTemplate() {
        System.out.println("\n=== 高级模板引擎测试 ===");
        AdvancedTemplateEngine engine = new AdvancedTemplateEngine();
        // 设置全局变量
        engine.setGlobalVariable("siteName", "MyWebsite");
        engine.setGlobalVariable("version", "1.0.0");
        // 准备数据
        Map<String, Object> context = new HashMap<>();
        context.put("pageTitle", "用户管理");
        context.put("isLoggedIn", true);
        context.put("username", "admin");
        Map<String, Object> settings = new HashMap<>();
        settings.put("itemsPerPage", 10);
        settings.put("showEmail", false);
        context.put("settings", settings);
        List<User> allUsers = Arrays.asList(
            new User("张三", 25, "zhangsan@example.com"),
            new User("李四", 28, "lisi@example.com"),
            new User("王五", 32, "wangwu@example.com")
        );
        context.put("allUsers", allUsers);
        String template = """
            <!-- 页面模板 -->
            <!DOCTYPE html>
            <html>
            <head>
                <title>{{ pageTitle }} - {{ siteName }}</title>
            </head>
            <body>
                {# if isLoggedIn #}
                <h1>欢迎回来,{{ username }}!</h1>
                {# else #}
                <h1>请登录</h1>
                {# endif #}
                {% if settings.showEmail %}
                <p>显示邮箱:是</p>
                {% else %}
                <p>显示邮箱:否</p>
                {% endif %}
                <h2>用户列表(每页显示{{ settings.itemsPerPage }}条):</h2>
                {% for user in allUsers %}
                <div class="user-item">
                    <span>用户名:{{ user.name }}</span>
                    <span>年龄:{{ user.age }}</span>
                    {% if settings.showEmail %}
                    <span>邮箱:{{ user.email }}</span>
                    {% endif %}
                </div>
                {% endfor %}
                <footer>
                    <p>© 2023 {{ siteName }} v{{ version }}</p>
                </footer>
            </body>
            </html>
            """;
        String result = engine.render(template, context);
        System.out.println(result);
    }
}

说明

功能特性

  1. 变量替换:支持 ${variable}{{ variable }} 两种语法
  2. 条件判断:支持 {#if condition}...{/if}{% if condition %} 语法
  3. 循环遍历:支持 {#foreach item in list}...{/foreach}{% for item in list %} 语法
  4. 对象属性访问:支持点号语法 user.name
  5. 条件表达式:支持比较运算符(>, <, >=, <=, , )和逻辑运算符(and, or, not
  6. 模板包含:支持包含其他模板文件
  7. 注释支持:支持 {# comments #} 注释
  8. 模板缓存:对模板文件进行缓存以提高性能

使用示例

// 创建引擎
AdvancedTemplateEngine engine = new AdvancedTemplateEngine();
// 设置数据
Map<String, Object> data = new HashMap<>();
data.put("name", "张三");
data.put("users", userList);
// 渲染模板
String html = engine.render(template, data);

这是一个功能完整的模板引擎实现,您可以在此基础上进行扩展以满足特定需求。

抱歉,评论功能暂时关闭!