ワンクリックで
html-control
Use when: 需要使用 EWA HtmlControl 类动态渲染 HTML 页面、编写 JSP/Java 页面渲染代码、或查询 HtmlControl API 用法和参数规范。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Use when: 需要使用 EWA HtmlControl 类动态渲染 HTML 页面、编写 JSP/Java 页面渲染代码、或查询 HtmlControl API 用法和参数规范。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
EWA RESTful handler 开发/调试时,与 Frame 路径 (ServletUpload/ActionFrame) 对照确保参数映射和 SQL 执行一致性
How to write DataConnection tests using SQLite — driver version, pool setup (HikariCP/Druid), path expressions, concurrency, and API patterns
Use when: 调用 EWA Servlet API、查询数据库表结构与数据、读取或修改 EWA XML 配置项、生成业务 XML(自动创建容器)、查看配置存储路径(showScriptPaths)、直接读取 XML 文件(getXmlFile)、校验 SQL 语法(validateSql)、需要脚本化执行 login/getTables/getTable/getTableData/getConfItem/previewBusinessXml/createBusinessXml/showScriptPaths/getXmlFile/validateSql。
Use when: 通过 EWA API 查看存储过程、函数或触发器的完整定义文本。INFORMATION_SCHEMA.ROUTINES 会截断,需用 sys.sql_modules 获取完整内容。
Use when: 编写 EWA 表单前端 JS 代码、表单提交与验证、表单与列表联动、对话框中表单操作、动态字段控制、合并单元格、分组向导。按任务组织,含完整代码示例。
Use when: 编写 EWA ListFrame 列表前端 JS 代码、行数据操作、选中行、翻页排序、检索过滤、展开行详情、动态列、底部汇总、行内编辑。按任务组织,含完整代码示例。
| name | html-control |
| description | Use when: 需要使用 EWA HtmlControl 类动态渲染 HTML 页面、编写 JSP/Java 页面渲染代码、或查询 HtmlControl API 用法和参数规范。 |
EWA 框架核心渲染类 com.gdxsoft.easyweb.script.HtmlControl 的使用指南。
项目中大量 JSP 和 Java 文件使用了 HtmlControl,典型用法见:
src/main/webapp/ewa.jsp # EWA 通用入口(AJAX 分支 + frameset 检测)
src/main/webapp/project/project-data.jsp # 动态切换 item(20+ 分支)
src/main/webapp/customer/survey/survey_info.jsp # 多实例组合(7+ HtmlControl)
src/main/java/pf2023/HandleEwaImpl.java # WebSocket 渲染(clone RV 模式)
src/main/java/pf2023/HandleChatImpl.java # WebSocket 工厂方法 + 参数合并
自动触发:当用户要求编写 HtmlControl 相关代码时,先读取对应场景的参考文件。
遇到 HtmlControl 初始化流程、页面渲染机制等概念不确定时,读取框架文档获取权威解释:
| 文档 | 说明 |
|---|---|
framework/emp-script/docs/zhcn/EXECUTION_FLOW.md | HTTP 请求到 XML 的完整执行流程 |
framework/emp-script/docs/zhcn/FRAME_EXECUTION.md | Frame 表单执行流程(init/渲染/ACL) |
自动触发:当对 HtmlControl 的 init 流程、页面渲染机制等概念不确定时,先 read_file 对应框架文档再操作。
| 方法 | 说明 | 使用场景 |
|---|---|---|
init(xmlName, itemName, paras, request, session, response) | Servlet 原生对象初始化 | JSP 标准 HTTP 上下文(最常用) |
init(xmlName, itemName, paras, rv, null) | RequestValue 初始化 | WebSocket / 后台任务(非 HTTP 上下文) |
init(xmlName, itemName, paras, rv, response) | RequestValue + response | JSP 中已有 RequestValue 对象时(~13 处使用) |
| 方法 | 说明 | 使用频率 |
|---|---|---|
getHtml() | 裁剪后 HTML(<!--INC_TOP--> 到 <!--INC_END--> 之间),含脚本 | 最高 |
getAllHtml() | 完整未裁剪 HTML(this.Html 原值) | 高(34+ 处) |
getHtmlMin() | 精简内容片段,含脚本 | 中(80 处) |
getHtmlFrameMin() | 纯内容片段,不含脚本(按 <!-- START: FRAME CONTENT--> 标记截取) | 低 |
| 场景 | 方法 |
|---|---|
| 独立新页面、iframe、弹窗 | getHtml() |
| 需要完整内容(含隐藏字段、签证/询价等复杂页面) | getAllHtml() |
| 页面内嵌入、AJAX 返回、Tab 面板 | getHtmlMin() |
| 纯内容片段、不需要脚本(如移动端嵌入) | getHtmlFrameMin() |
| 方法 | 说明 | 使用频率 |
|---|---|---|
getLastTable() | 获取 init 时最后一次查询的 DTTable | 高(127 处) |
getTables() | 获取 init 时所有查询的 DTTable 数组 | 低 |
getRequestValue() | 获取内部 RequestValue 对象(含 sys_frame_unid 等) | 高(65 处) |
getTitle() | 获取页面标题 | 高(70 处) |
getFrameUnid() | 获取当前帧唯一标识符 | 中 |
| 方法 | 说明 |
|---|---|
setFrameUnidPrefix(String) / getFrameUnidPrefix() | FrameUnid 前缀修正,同一页面渲染多个相同模块实例时必需,避免 frame_unid 冲突 |
setAjaxCallUrl(String) / getAjaxCallUrl() | 设置 Ajax 调用 URL |
setSkipAcl(boolean) / isSkipAcl() | 控制是否跳过 ACL 权限校验(后台任务/WebSocket 场景设为 true) |
isError() | 判断上一次 init 是否发生错误 |
getHtmlCreator() | 获取底层 HtmlCreator 对象(高级用法:isErrOut()、getItemValues() 等) |
getDebugInfo() | 获取调试信息对象 |
<%
HtmlControl ht = new HtmlControl();
ht.init(xmlName, itemName, paras, request, session, response);
out.println(ht.getHtml());
%>
HtmlControl ht = new HtmlControl();
ht.init(xmlName, itemName, paras, rv, null);
String html = ht.getHtml();
注意:长连接场景中需克隆 RequestValue 避免并发问题。
HtmlControl ht = new HtmlControl();
ht.setSkipAcl(true);
ht.init(xmlName, itemName, paras, rv, null);
String html = ht.getHtml();
遵循 模块名.类型.操作 三段式:
| 类型标识 | 含义 | 操作后缀 | 含义 |
|---|---|---|---|
F | Form 表单 | V | 查看 |
Lf / LF | List 列表 | N | 新增 |
T | Table 表格 | M | 修改 |
Frame | 框架页 |
示例:ADM_USER.F.V(用户表单-查看)、BBS_TOPIC.LF.relay(话题列表-转播)
| 参数 | 说明 |
|---|---|
EWA_AJAX=JSON | AJAX JSON 模式 |
EWA_ACTION=OnPageLoad | 页面加载 |
EWA_ACTION=OnPagePost | 表单提交 |
EWA_MTYPE=M | 手动模式 |
EWA_MTYPE=N | 自动模式 |
EWA_PAGECUR=1 | 当前页码 |
EWA_PAGESIZE=20 | 每页条数 |
ewa_mobile=1 | 移动端模式 |
见 ewa.jsp。先判断 ewa_ajax 参数走 AJAX 分支,再检测 frameset 输出:
<%
HtmlControl ht = new HtmlControl();
String xmlName = g_rv.s("xmlname");
String itemName = g_rv.s("itemname");
ht.init(xmlName, itemName, "", request, session, response);
// AJAX 分支
if (g_rv.s("ewa_ajax") != null) {
out.println(ht.getHtml());
return;
}
// frameset 检测
String html = ht.getHtml();
if (html.indexOf("<frameset") > 0) {
out.println(html);
return;
}
// 正常页面
%>
<y2019:header title="<%=ht.getTitle()%>"></y2019:header>
<%=html%>
见 project/project-data.jsp。一个 HtmlControl 实例根据参数反复 init() 渲染不同 item:
<%
HtmlControl ht = new HtmlControl();
String xmlName = "/business/project/project.xml";
if ("nm".equals(gantt_mode)) {
ht.init(xmlName, "OA_REQ.F.NM", paras, request, session, response);
out.print(ht.getHtml());
} else if ("bat_add_subs".equals(gantt_mode)) {
ht.init(xmlName, "OA_REQ.F.SubBat", paras, request, session, response);
out.print(ht.getHtml());
}
// ... 更多分支
%>
见 customer/survey/survey_info.jsp。单页面创建多个 HtmlControl 实例渲染不同模块:
<%
HtmlControl ht = new HtmlControl(); // 主表单
ht.init(xml1, item1, paras, request, session, response);
out.println(ht.getAllHtml());
HtmlControl ht1 = new HtmlControl(); // 考题定义
ht1.init(xml2, item2, paras, request, session, response);
out.println(ht1.getHtmlMin());
HtmlControl htAtts = new HtmlControl(); // 附件
htAtts.init(xml3, item3, paras, request, session, response);
out.println(htAtts.getHtmlMin());
%>
同一页面循环渲染多个相同模块实例时,必须设置 setFrameUnidPrefix 避免 frame_unid 冲突:
<%
for (int i = 0; i < list.size(); i++) {
HtmlControl ht = new HtmlControl();
ht.setFrameUnidPrefix("M" + i + "_");
ht.init(xmlName, itemName, paras, request, session, response);
out.println(ht.getHtmlMin());
}
%>
见 HandleEwaImpl.java 和 HandleChatImpl.java。非 HTTP 上下文中必须克隆 RequestValue 并重置系统变量:
// HandleEwaImpl 模式
HtmlControl ht = new HtmlControl();
RequestValue newRv = this.socket_.getRv().clone();
newRv.resetDateTime(); // 重置日期时间
newRv.resetSysUnid(); // 重置唯一标识
ht.init(xmlName, itemName, params, newRv, null);
String html = ht.getHtml();
// HandleChatImpl 模式 — 工厂方法 + 参数合并
private HtmlControl getHtmlControl(String itemName, String params) {
HtmlControl ht = new HtmlControl();
RequestValue rv_clone = this.getCloneRv();
ht.init(defaultXmlName, itemName, params, rv_clone, null);
return ht;
}
private RequestValue getCloneRv() {
RequestValue rv_clone = this.socket_.getRv().clone();
// 合并 command 参数
Iterator<?> it = this.command_.keys();
while (it.hasNext()) {
String key = it.next().toString();
rv_clone.getPageValues().remove(key);
rv_clone.addValue(key, this.command_.optString(key));
}
rv_clone.resetDateTime();
rv_clone.resetSysUnid();
return rv_clone;
}
getLastTable() 获取 SQL 查询结果,常用于判空、取值、转 JSON:
<%
ht.init(xmlName, itemName, paras, request, session, response);
// 判空
if (ht.getLastTable().getCount() == 0) {
// 无数据处理
}
// 取值
int grpId = ht.getLastTable().getCell(0, "GRP_ID").toInt();
String title = ht.getLastTable().getCell(0, "GRP_NAME").toString();
// 转 JSON 输出
out.println(ht.getLastTable().toJSONArray());
// 遍历
for (int i = 0; i < ht.getLastTable().getCount(); i++) {
String sql = ht.getLastTable().getCell(i, "EXAM_SQL").toString();
}
%>
getRequestValue() 常用于获取 init 过程中系统生成的值(如 sys_frame_unid、新 ID 等):
ht.init(xmlName, itemName, paras, rv, null);
String frameUnid = ht.getRequestValue().s("sys_frame_unid");
int newId = ht.getRequestValue().getInt("NEW_ADM_ID");
HtmlControl 不是线程安全的,每个请求应创建独立实例init() 复用(模式 B 就是利用这一点)getLastTable() 返回最近一次 init() 的最后一个 SQL 查询结果;如有多个查询,用 getTables() 获取数组RequestValue 并调用 resetDateTime() + resetSysUnid()setFrameUnidPrefix() 避免 frame_unid 冲突getHtml() 会裁剪 <!--INC_TOP--> / <!--INC_END--> 标记之间的内容;如需完整输出用 getAllHtml()完整文档见项目根目录 HTMLCONTROL.md。