
本文介绍如何通过自定义 visitoradapter 类,在 jsqlparser 解析过程中对未显式支持的 sql 语法(如 insert、group by、having 等)自动抛出异常,从而确保仅允许白名单内的语句执行。
本文介绍如何通过自定义 visitoradapter 类,在 jsqlparser 解析过程中对未显式支持的 sql 语法(如 insert、group by、having 等)自动抛出异常,从而确保仅允许白名单内的语句执行。
JSqlParser 提供了基于 Visitor 模式的灵活解析能力,但其默认的 *VisitorAdapter(如 ExpressionVisitorAdapter、StatementVisitorAdapter)对所有未重写的方法均采用空实现(no-op),导致不支持的语法节点被静默忽略——这对构建轻量级、强约束的嵌入式数据库而言存在严重隐患。
要实现“遇不支持即报错”的行为,核心思路是:编写自定义 Adapter,将所有 visit 方法的默认实现改为抛出 UnsupportedOperationException,再仅对明确支持的节点类型进行有意识的重写。这种方式将“默认拒绝”作为安全基线,显著提升 SQL 兼容性控制的确定性。
以下是一个典型实现示例(以 StatementVisitor 为例):
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
public class StrictStatementVisitor extends StatementVisitorAdapter {
@Override
public void visit(Select select) {
// 显式支持 SELECT
select.getSelectBody().accept(new StrictSelectBodyVisitor());
}
@Override
public void visit(Insert insert) {
throw new UnsupportedOperationException("INSERT statements are not supported");
}
@Override
public void visit(Update update) {
throw new UnsupportedOperationException("UPDATE statements are not supported");
}
@Override
public void visit(Delete delete) {
throw new UnsupportedOperationException("DELETE statements are not supported");
}
// 其他 Statement 子类同理:Drop, Create, With, etc.
}对应地,StrictSelectBodyVisitor 也应继承 SelectBodyVisitorAdapter 并仅重写 PlainSelect,同时为 SetOperationList、WithItem 等非支持结构抛出异常:
public class StrictSelectBodyVisitor extends SelectBodyVisitorAdapter {
@Override
public void visit(PlainSelect plainSelect) {
// 继续深入校验:WHERE、ORDER BY 可选支持;GROUP BY/HAVING 则拒绝
if (plainSelect.getGroupBy() != null) {
throw new UnsupportedOperationException("GROUP BY is not supported");
}
if (plainSelect.getHaving() != null) {
throw new UnsupportedOperationException("HAVING clause is not supported");
}
// 递归访问子节点(如 SelectItem、FromItem、Where)
plainSelect.getSelectItems().forEach(item -> item.accept(new StrictSelectItemVisitor()));
if (plainSelect.getWhere() != null) {
plainSelect.getWhere().accept(new StrictExpressionVisitor());
}
}
}⚠️ 关键注意事项:
- 所有自定义 Visitor 必须继承 *VisitorAdapter(而非直接实现 *Visitor 接口),否则需手动补全全部方法,易遗漏;
- 建议配合单元测试,覆盖各类非法 SQL(如 "INSERT INTO t VALUES (1)"、"SELECT * FROM t GROUP BY x"),验证异常是否如期触发;
- 若需动态调整支持策略(如按用户权限开关功能),可将异常逻辑封装为策略接口,而非硬编码 throw;
- 注意 ExpressionVisitorAdapter 同样需严格定制(例如拒绝 Function、CaseExpression、SubSelect 等高级表达式),否则 WHERE 条件中出现不支持函数仍会静默通过。
总结而言,JSqlParser 本身不提供开箱即用的“严格模式”,但通过主动覆写 Adapter 的默认行为为异常抛出,开发者能以极低侵入性构建出语义精确、防御完备的 SQL 白名单解析器——这正是轻量数据库、配置化查询引擎与 SQL 安全网关的理想实践路径。

















