本文目录导读:

我来详细解释一下 JEditorPane、HTMLEditorKit 和 ParserFilter 在 Java Swing 中的使用和实现。
基本概念
JEditorPane
- Swing 中的文本组件,可以显示和编辑多种格式的文本
- 支持 HTML、RTF 等格式
HTMLEditorKit
- 负责解析和渲染 HTML 内容
- 提供自定义解析和渲染的能力
ParserFilter
- 用于过滤和修改 HTML 解析过程中的内容
- 可以在解析器处理 HTML 标签时进行干预
完整示例代码
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
import javax.swing.text.html.parser.*;
import java.awt.*;
import java.io.*;
public class HtmlParserFilterExample {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("HTML Parser Filter Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 400);
// 创建 JEditorPane
JEditorPane editorPane = new JEditorPane();
editorPane.setEditable(false);
// 创建自定义 HTMLEditorKit
CustomHtmlEditorKit kit = new CustomHtmlEditorKit();
editorPane.setEditorKit(kit);
// 设置 HTML 内容
String htmlContent = "<html><body>" +
"<h1>测试标题</h1>" +
"<p>这是一个段落。</p>" +
"<p><b>加粗文本</b></p>" +
"<p><i>斜体文本</i></p>" +
"<a href='http://example.com'>链接示例</a>" +
"<img src='test.jpg' alt='测试图片'>" +
"</body></html>";
editorPane.setText(htmlContent);
// 添加到滚动面板
JScrollPane scrollPane = new JScrollPane(editorPane);
frame.add(scrollPane, BorderLayout.CENTER);
// 添加控制按钮
JPanel controlPanel = new JPanel();
JButton filterButton = new JButton("应用过滤器");
JButton resetButton = new JButton("重置");
filterButton.addActionListener(e -> {
// 重新设置以触发过滤
editorPane.setText(htmlContent);
});
resetButton.addActionListener(e -> {
// 重置为默认编辑器
editorPane.setEditorKit(new HTMLEditorKit());
editorPane.setText(htmlContent);
});
controlPanel.add(filterButton);
controlPanel.add(resetButton);
frame.add(controlPanel, BorderLayout.SOUTH);
frame.setVisible(true);
});
}
}
// 自定义 HTMLEditorKit
class CustomHtmlEditorKit extends HTMLEditorKit {
@Override
public Document createDefaultDocument() {
HTMLDocument doc = (HTMLDocument) super.createDefaultDocument();
// 设置自定义解析器
doc.setParser(new CustomHtmlParser(doc, doc.getParser()));
return doc;
}
}
// 自定义 HTML 解析器
class CustomHtmlParser extends HtmlParser {
private HTMLDocument doc;
private HtmlParser originalParser;
public CustomHtmlParser(HTMLDocument doc, HtmlParser originalParser) {
this.doc = doc;
this.originalParser = originalParser;
}
@Override
public void parse(Reader reader, HTMLReader callback, boolean ignoreCharSet)
throws IOException {
// 使用自定义的读取器来过滤内容
CustomHTMLReader customReader = new CustomHTMLReader(doc);
// 调用原始解析器的 parse 方法
originalParser.parse(reader, callback, ignoreCharSet);
}
}
// 自定义 HTML 读取器
class CustomHTMLReader extends HTMLEditorKit.ParserCallback {
private HTMLDocument doc;
private StringBuilder filteredContent = new StringBuilder();
public CustomHTMLReader(HTMLDocument doc) {
this.doc = doc;
}
@Override
public void handleText(char[] data, int pos) {
// 过滤文本内容
String text = new String(data);
// 移除所有数字
text = text.replaceAll("\\d+", "");
// 限制文本长度为50个字符
if (text.length() > 50) {
text = text.substring(0, 50) + "...";
}
filteredContent.append(text);
System.out.println("过滤文本: " + text);
}
@Override
public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
System.out.println("开始标签: " + t.toString() +
", 属性: " + a);
// 过滤 img 标签
if (t == HTML.Tag.IMG) {
System.out.println("过滤掉图片标签");
return; // 不处理 img 标签
}
// 修改链接属性
if (t == HTML.Tag.A) {
// 添加 target="_blank" 属性
a.addAttribute("target", "_blank");
}
}
@Override
public void handleEndTag(HTML.Tag t, int pos) {
System.out.println("结束标签: " + t.toString());
}
@Override
public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) {
System.out.println("简单标签: " + t.toString());
}
@Override
public void handleComment(char[] data, int pos) {
// 过滤注释
System.out.println("过滤注释: " + new String(data));
}
@Override
public void handleError(String errorMsg, int pos) {
System.err.println("解析错误: " + errorMsg + " at position " + pos);
}
public String getFilteredContent() {
return filteredContent.toString();
}
}
// 使用 ParserFilter 的另一种实现方式
class CustomParserFilter extends HTMLEditorKit.ParserCallback {
private StringBuilder output = new StringBuilder();
private boolean filterActive = true;
// 过滤配置
private boolean filterLinks = true;
private boolean filterImages = true;
private boolean filterScripts = true;
private int maxTextLength = 100;
public CustomParserFilter() {
}
public void setFilterActive(boolean active) {
this.filterActive = active;
}
@Override
public void handleText(char[] data, int pos) {
if (filterActive) {
String text = new String(data);
// 文本过滤规则
text = removeScript(text);
text = truncateText(text);
text = removeSensitiveInfo(text);
output.append(text);
} else {
output.append(data);
}
}
@Override
public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
if (filterActive) {
// 过滤不需要的标签
if (shouldFilterTag(t)) {
return;
}
// 修改标签属性
modifyAttributes(t, a);
}
// 构建输出
output.append("<").append(t.toString());
// 添加修改后的属性
output.append(">");
}
@Override
public void handleEndTag(HTML.Tag t, int pos) {
if (filterActive && shouldFilterTag(t)) {
return;
}
output.append("</").append(t.toString()).append(">");
}
private boolean shouldFilterTag(HTML.Tag tag) {
// 判断是否需要过滤该标签
if (tag == HTML.Tag.SCRIPT && filterScripts) {
return true;
}
if (tag == HTML.Tag.IMG && filterImages) {
return true;
}
if (tag == HTML.Tag.A && filterLinks) {
return true;
}
return false;
}
private void modifyAttributes(HTML.Tag tag, MutableAttributeSet attributes) {
// 修改标签属性
if (tag == HTML.Tag.A) {
// 为链接添加安全属性
attributes.addAttribute("rel", "noopener noreferrer");
}
if (tag == HTML.Tag.IMG) {
// 添加图片安全处理
attributes.addAttribute("loading", "lazy");
}
}
private String removeScript(String text) {
// 移除潜在的脚本内容
return text.replaceAll("<script[^>]*>.*?</script>", "")
.replaceAll("javascript:", "")
.replaceAll("onerror=", "")
.replaceAll("onclick=", "");
}
private String truncateText(String text) {
// 截断过长的文本
if (text.length() > maxTextLength) {
return text.substring(0, maxTextLength) + "...";
}
return text;
}
private String removeSensitiveInfo(String text) {
// 移除敏感信息(示例)
return text.replaceAll("\\b\\d{17}[\\dXx]\\b", "[ID被隐藏]") // 身份证号
.replaceAll("\\b1[3-9]\\d{9}\\b", "[手机号被隐藏]") // 手机号
.replaceAll("\\b\\d{16,19}\\b", "[银行卡号被隐藏]"); // 银行卡号
}
@Override
public String toString() {
return output.toString();
}
}
// 更高级的示例:使用过滤器链
class FilterChainExample {
public static void main(String[] args) {
JEditorPane editorPane = new JEditorPane();
// 创建过滤器链
FilterChain filterChain = new FilterChain();
filterChain.addFilter(new XssFilter());
filterChain.addFilter(new TextLengthFilter());
filterChain.addFilter(new LinkModifierFilter());
// 设置自定义编辑器套件
FilteredHtmlEditorKit kit = new FilteredHtmlEditorKit(filterChain);
editorPane.setEditorKit(kit);
}
}
// 过滤器接口
interface HtmlFilter {
String filter(String html);
}
// 过滤器链
class FilterChain {
private java.util.List<HtmlFilter> filters = new java.util.ArrayList<>();
public void addFilter(HtmlFilter filter) {
filters.add(filter);
}
public String applyFilters(String html) {
String result = html;
for (HtmlFilter filter : filters) {
result = filter.filter(result);
}
return result;
}
}
// XSS 过滤器
class XssFilter implements HtmlFilter {
@Override
public String filter(String html) {
// 过滤 XSS 攻击代码
return html.replaceAll("<script[^>]*>.*?</script>", "")
.replaceAll("on\\w+\\s*=", "")
.replaceAll("javascript\\s*:", "");
}
}
// 文本长度过滤器
class TextLengthFilter implements HtmlFilter {
private int maxLength = 100;
@Override
public String filter(String html) {
// 限制文本长度
StringBuilder sb = new StringBuilder();
String[] parts = html.split("(?<=\\>)|(?=\\<)");
for (String part : parts) {
if (!part.startsWith("<")) {
if (part.length() > maxLength) {
part = part.substring(0, maxLength) + "...";
}
}
sb.append(part);
}
return sb.toString();
}
}
// 链接修改过滤器
class LinkModifierFilter implements HtmlFilter {
@Override
public String filter(String html) {
// 为所有链接添加 target="_blank"
return html.replaceAll("<a\\s+([^>]*)>",
"<a $1 target=\"_blank\" rel=\"noopener noreferrer\">");
}
}
// 使用过滤器的编辑器套件
class FilteredHtmlEditorKit extends HTMLEditorKit {
private FilterChain filterChain;
public FilteredHtmlEditorKit(FilterChain filterChain) {
this.filterChain = filterChain;
}
@Override
public void read(InputStream in, Document doc, int pos)
throws IOException, BadLocationException {
// 读取并过滤内容
String content = new String(in.readAllBytes());
content = filterChain.applyFilters(content);
super.read(new ByteArrayInputStream(content.getBytes()), doc, pos);
}
@Override
public void read(Reader in, Document doc, int pos)
throws IOException, BadLocationException {
// 读取并过滤内容
StringBuilder sb = new StringBuilder();
char[] buffer = new char[1024];
int length;
while ((length = in.read(buffer)) != -1) {
sb.append(buffer, 0, length);
}
String filteredContent = filterChain.applyFilters(sb.toString());
super.read(new StringReader(filteredContent), doc, pos);
}
}
使用场景
安全过滤
- 防止 XSS 攻击
- 移除恶意脚本
- 验证链接安全性
内容控制
- 限制文本长度
- 过滤敏感信息
- 修改链接行为
格式处理
- 自定义标签渲染
- 修改属性值
- 添加额外样式
最佳实践
// 1. 使用线程安全的过滤
public class ThreadSafeFilter extends HTMLEditorKit.ParserCallback {
private final Object lock = new Object();
@Override
public void handleText(char[] data, int pos) {
synchronized (lock) {
// 线程安全的过滤操作
}
}
}
// 2. 性能优化
public class PerformanceFilter extends HTMLEditorKit.ParserCallback {
private StringBuilder buffer = new StringBuilder();
private static final int MAX_BUFFER_SIZE = 1024 * 1024; // 1MB
@Override
public void handleText(char[] data, int pos) {
if (buffer.length() > MAX_BUFFER_SIZE) {
// 清空缓冲区以防止内存溢出
buffer.setLength(0);
}
// 过滤操作
}
}
// 3. 可配置的过滤器
public class ConfigurableFilter extends HTMLEditorKit.ParserCallback {
private Properties config = new Properties();
public ConfigurableFilter(String configFile) throws IOException {
config.load(new FileInputStream(configFile));
}
}
注意事项
- 性能考虑: 复杂的过滤可能会影响渲染性能
- 兼容性: 确保过滤后的 HTML 仍然有效
- 安全性: 始终优先考虑安全过滤
- 维护性: 使用过滤器链模式提高代码可维护性
这个示例展示了 JEditorPane 中 HTMLEditorKit 和 ParserFilter 的完整使用方式,包括自定义解析、内容过滤和安全性处理。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播