标题:Java Servlet 动态渲染 HTML 模板教程(基于占位符替换)

12次阅读

标题:Java Servlet 动态渲染 HTML 模板教程(基于占位符替换)

本文介绍如何使用 java servlet 读取 `.tpl` 模板文件,解析 url 参数(如 `id`),查询数据对象(如 pet),执行简单占位符替换(如 `{pet.name}`),并返回渲染后的 html 响应。无需第三方模板引擎,适合初学者快速上手。

要实现基于 .tpl 文件的轻量级服务端模板渲染,核心思路是:读取静态模板 → 提取请求参数 → 加载业务数据 → 替换占位符 → 输出 html 响应。下面以 index.tpl 为例,逐步构建一个完整、可运行的 Servlet 示例。

✅ 步骤一:准备模板文件与项目结构

将 index.tpl 放置于 Web 应用的 WEB-INF/templates/ 目录下(推荐,确保不被直接访问):

        

Pet profile - {pet.name}

Age: {pet.age}

Type: {pet.type}

立即学习Java免费学习笔记(深入)”;

⚠️ 注意:切勿将模板放在 webapp/ 根目录下(如 webapp/index.tpl),否则用户可绕过 Servlet 直接访问原始模板,造成信息泄露或 xss 风险。

✅ 步骤二:编写 Servlet(支持路径匹配与占位符替换)

假设你使用注解方式映射 /index.tpl 请求(Servlet 3.0+):

@WebServlet("/index.tpl") public class TemplateServlet extends httpServlet {     private static final String TEMPLATE_BASE_PATH = "/WEB-INF/templates/";      @Override     protected void doGet(HttpServletRequest request, HttpServletResponse response)             throws ServletException, IOException {          // 1. 解析请求参数         String idParam = request.getParameter("id");         if (idParam == null || idParam.trim().isEmpty()) {             response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing 'id' parameter");             return;         }          long petId;         try {             petId = Long.parseLong(idParam.trim());         } catch (NumberFormatException e) {             response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid 'id'");             return;         }          // 2. 查询宠物数据(此处模拟数据库查询)         Pet pet = findPetById(petId);         if (pet == null) {             response.sendError(HttpServletResponse.SC_NOT_FOUND, "Pet not found");             return;         }          // 3. 读取模板内容(使用 ServletContext 获取资源流,更安全可靠)         ServletContext ctx = getServletContext();         Inputstream is = ctx.getResourceAsStream(TEMPLATE_BASE_PATH + "index.tpl");         if (is == null) {             throw new ServletException("Template not found: index.tpl");         }         String templateContent;         try (Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {             templateContent = IOUtils.toString(reader); // 使用 apache Commons IO(推荐)             // 若不用第三方库,可用 StringBuilder + BufferedReader 手动读取         }          // 4. 占位符替换(注意:生产环境建议用正则或专用模板引擎)         String renderedHtml = templateContent                 .replace("{pet.name}", escapeHtml(pet.getName()))                 .replace("{pet.age}", String.valueOf(pet.getAge()))                 .replace("{pet.type}", escapeHtml(pet.getType()));          // 5. 设置响应头并输出         response.setContentType("text/html;charset=UTF-8");         response.setCharacterEncoding("UTF-8");         response.setStatus(HttpServletResponse.SC_OK);         response.getWriter().write(renderedHtml);         response.getWriter().flush();     }      // 模拟数据查询(实际中应调用 DAO 或 Service)     private Pet findPetById(long id) {         // 示例:返回硬编码数据,可根据需要对接数据库         if (id == 1) return new Pet("Buddy", 3, "Dog");         if (id == 2) return new Pet("Luna", 2, "Cat");         return null;     }      // 简单 HTML 转义(防御 XSS)     private String escapeHtml(String input) {         if (input == null) return "";         return input.replace("&", "&")                     .replace("<", "zuojiankuohaophpcn")                     .replace(">", "youjiankuohaophpcn")                     .replace(""", """)                     .replace("'", "'");     } }

? 关键说明

  • 使用 ServletContext.getResourceAsStream() 比 Files.readAllBytes(Paths.get(…)) 更规范,能正确处理 WAR 包内路径;
  • IOUtils.toString() 来自 commons-io(maven 依赖 commons-iocommons-io2.11.0),若不想引入依赖,可用标准 BufferedReader 替代;
  • 所有动态插入的字段必须进行 HTML 转义(如 escapeHtml()),否则用户输入 将导致 XSS 漏洞;
  • 当前为线性字符串替换,仅适用于简单场景;复杂逻辑(条件、循环)请升级至 ThymeleafFreemarkerJSP

✅ 步骤三:定义 Pet 模型类(java Bean)

public class Pet {     private final String name;     private final int age;     private final String type;      public Pet(String name, int age, String type) {         this.name = name;         this.age = age;         this.type = type;     }      // getters only     public String getName() { return name; }     public int getAge() { return age; }     public String getType() { return type; } }

✅ 最终效果

访问:http://localhost:8080/your-app/index.tpl?id=1
→ Servlet 加载 index.tpl,查得 Pet(“Buddy”, 3, “Dog”),渲染后返回:

        

Pet profile - Buddy

Age: 3

Type: Dog

✅ 总结:本方案以最小依赖实现模板驱动的动态页面,兼顾安全性(路径隔离 + HTML 转义)与可维护性。随着业务增长,建议平滑迁移至成熟模板引擎——但对学习 Servlet 生命周期与基础 I/O 处理而言,这是极佳的入门实践。

text=ZqhQzanResources