本文目录导读:

这是一个关于 JEditorPane、HTMLEditorKit 和 HTML 解析时出现未捕获异常的问题,这类问题通常与 Swing 的 HTML 渲染引擎在处理特定 HTML 内容时崩溃有关。
常见原因
- 无效的 HTML 结构 - 某些标签或属性不符合预期格式
- 特殊的 Unicode 字符 - 某些字符集无法被解析器正确处理
- 过大的 HTML 内容 - 超出解析器的处理能力
- 线程安全问题 - 在非 EDT(事件调度线程)上修改组件内容
- 已知的 JDK bug - 某些 Java 版本存在特定的 HTML 解析错误
解决方案
全局异常捕获
// 设置未捕获异常处理器
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
System.err.println("未捕获异常: " + throwable.getMessage());
throwable.printStackTrace();
// 可以在这里设置恢复逻辑
});
安全的 HTML 设置
// 使用 try-catch 包裹
try {
jEditorPane.setContentType("text/html");
jEditorPane.setText(htmlContent);
} catch (Exception e) {
System.err.println("HTML 设置失败: " + e.getMessage());
// 使用纯文本作为后备
jEditorPane.setContentType("text/plain");
jEditorPane.setText("无法显示 HTML 内容");
}
自定义 HTMLEditorKit
class SafeHTMLEditorKit extends HTMLEditorKit {
@Override
public Document createDefaultDocument() {
HTMLDocument doc = (HTMLDocument) super.createDefaultDocument();
doc.setAsynchronousLoadPriority(-1); // 禁用异步加载
return doc;
}
@Override
public ViewFactory getViewFactory() {
return new SafeViewFactory(super.getViewFactory());
}
}
// 使用自定义的 EditorKit
jEditorPane.setEditorKit(new SafeHTMLEditorKit());
预验证 HTML 内容
public static String sanitizeHTML(String html) {
if (html == null || html.isEmpty()) {
return "";
}
// 移除可能导致问题的元素
html = html.replaceAll("<!\\[CDATA\\[.*?\\]\\]>", "");
html = html.replaceAll("<script[^>]*>.*?</script>", "");
html = html.replaceAll("onerror|onclick|onload", "");
return html;
}
使用 SwingWorker 在后台处理
SwingWorker<Void, Void> worker = new SwingWorker<>() {
@Override
protected Void doInBackground() {
// 在后台线程中处理 HTML
return null;
}
@Override
protected void done() {
try {
get(); // 获取可能的异常
// 在 EDT 中更新 UI
jEditorPane.setText(processedHTML);
} catch (Exception e) {
System.err.println("HTML 处理异常: " + e.getMessage());
jEditorPane.setText("加载失败");
}
}
};
worker.execute();
完整的异常处理示例
import javax.swing.*;
import javax.swing.text.html.*;
import java.awt.*;
public class SafeHTMLEditor {
private JEditorPane editorPane;
public SafeHTMLEditor() {
editorPane = new JEditorPane();
editorPane.setEditable(false);
// 设置自定义异常处理器
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
if (throwable instanceof RuntimeException) {
// 尝试恢复
SwingUtilities.invokeLater(() -> {
editorPane.setText("<html><body>内容加载错误</body></html>");
});
}
});
}
public void setHTML(String html) {
SwingUtilities.invokeLater(() -> {
try {
String safeHTML = sanitizeHTML(html);
editorPane.setText(safeHTML);
editorPane.revalidate();
} catch (Exception e) {
System.err.println("HTML 设置失败: " + e.getMessage());
editorPane.setContentType("text/plain");
editorPane.setText("HTML 渲染失败");
}
});
}
private String sanitizeHTML(String html) {
// 实现 HTML 清理逻辑
return html;
}
}
调试建议
-
添加详细的日志记录
System.setProperty("sun.awt.exception.handler", "com.example.MyExceptionHandler"); -
使用 JVM 参数捕获更多信息
java -Xcheck:jni -Dswing.debug=true -jar yourapp.jar
-
检查 Java 版本,某些版本存在已知的 HTML 解析 bug
如果问题持续存在,考虑使用替代方案:
- JEditorPane 替代:
JTextPane或第三方 HTML 渲染器(如 Flying Saucer) - 使用 WebView(JavaFX)替代 Swing 组件