使用Java编写HTML文件

52

我希望我的Java应用程序能够将HTML代码写入文件中。目前,我正在使用java.io.BufferedWriter类硬编码HTML标签。例如:

BufferedWriter bw = new BufferedWriter(new FileWriter(file));
bw.write("<html><head><title>New Page</title></head><body><p>This is Body</p></body></html>");
bw.close();

有没有更简便的方法做这个,因为我需要创建表格,但这样做变得很不方便?

11个回答

51

如果您想自己完成这个任务,而不使用任何外部库,一个干净的方法是创建一个 template.html 文件,其中包含所有静态内容,例如:

如果您想自己完成这个任务,而不使用任何外部库,一个干净的方法是创建一个 template.html 文件,其中包含所有静态内容,例如:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>$title</title>
</head>
<body>$body
</body>
</html>

在任何动态内容上放置标签 $tag,然后执行以下操作:

File htmlTemplateFile = new File("path/template.html");
String htmlString = FileUtils.readFileToString(htmlTemplateFile);
String title = "New Page";
String body = "This is Body";
htmlString = htmlString.replace("$title", title);
htmlString = htmlString.replace("$body", body);
File newHtmlFile = new File("path/new.html");
FileUtils.writeStringToFile(newHtmlFile, htmlString);
注意:我出于简单起见使用了org.apache.commons.io.FileUtils

4
对于 Java8,应额外传递 Charset.forName("UTF-8"),因为未指定字符集的 readFileToString 已被弃用。 - Jitesh Sojitra
2
也可以使用MessageFormat进行替换:String template = FileUtils.readFileToString(htmlTemplateFile); String title = "New Page"; String body = "This is Body"; String htmlString = MessageFormat.format(template, title, body); 然后, template 应该包含 {0} 用于 title{1} 用于 body - Sergey Ushakov

13
几个月前我遇到了同样的问题,我发现所有我找到的库都提供了过多的功能和复杂性,这不符合我的最终目标。因此,我最终开发了自己的库 - HtmlFlow - 它提供了一个非常简单和直观的API,使我可以采用流畅的方式编写HTML。请查看这里:https://github.com/fmcarvalho/HtmlFlow(它还支持将动态绑定到HTML元素)。
以下是将 Task 对象的属性绑定到 HTML 元素的示例。假设有一个 Java 类 Task,它有三个属性:TitleDescriptionPriority,我们可以按照以下方式为 Task 对象生成 HTML 文档:
import htmlflow.HtmlView;

import model.Priority;
import model.Task;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;

public class App {

    private static HtmlView<Task> taskDetailsView(){
        HtmlView<Task> taskView = new HtmlView<>();
        taskView
                .head()
                .title("Task Details")
                .linkCss("https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css");
        taskView
                .body().classAttr("container")
                .heading(1, "Task Details")
                .hr()
                .div()
                .text("Title: ").text(Task::getTitle)
                .br()
                .text("Description: ").text(Task::getDescription)
                .br()
                .text("Priority: ").text(Task::getPriority);
        return taskView;
    }

    public static void main(String [] args) throws IOException{
        HtmlView<Task> taskView = taskDetailsView();
        Task task =  new Task("Special dinner", "Have dinner with someone!", Priority.Normal);

        try(PrintStream out = new PrintStream(new FileOutputStream("Task.html"))){
            taskView.setPrintStream(out).write(task);
            Desktop.getDesktop().browse(URI.create("Task.html"));
        }
    }
}

1
一个好的想法,一个好的工具,但不幸的是许可证并不那么好,无法鼓励广泛使用... ;) - Sergey Ushakov
抱歉,@s-n-ushakov,我不是关于许可协议的专家。GPL v3.0有什么问题? - Miguel Gamboa
5
GPL的问题在于它太过严格。如果你使用了任何一段GPL许可的代码,它要求你也必须将你的整个项目公开使用GPL。这对于业余或大学编程可能没有问题,但对于商业相关的编程来说可能会带来相当大的问题。因此,为了使您的库更适合商业用途,我建议至少将许可证更改为LGPL,它不需要你开源整个项目,而只需要披露你对库的改进。其他许可证(例如BSD、MIT、Apache、Eclipse)可能更适合商业用途。 - Sergey Ushakov
1
@s-n-ushakov,我会将许可证更改为MIT。感谢您的建议。 - Miguel Gamboa
很酷,知道了 :) - Sergey Ushakov
7
完成。刚刚发布了1.1版本,使用 MIT 许可证并进行了一些小修复。 - Miguel Gamboa

8
您可以使用 jsoupwffweb(基于HTML5)。
jsoup 的示例代码如下:
Document doc = Jsoup.parse("<html></html>");
doc.body().addClass("body-styles-cls");
doc.body().appendElement("div");
System.out.println(doc.toString());

打印件
<html>
 <head></head>
 <body class=" body-styles-cls">
  <div></div>
 </body>
</html>

wffweb 的示例代码:

Html html = new Html(null) {{
    new Head(this);
    new Body(this,
        new ClassAttribute("body-styles-cls"));
}};

Body body = TagRepository.findOneTagAssignableToTag(Body.class, html);
body.appendChild(new Div(null));

System.out.println(html.toHtmlString());
//directly writes to file
html.toOutputStream(new FileOutputStream("/home/user/filepath/filename.html"), "UTF-8");

打印(以缩小格式):-
<html>
<head></head>
<body class="body-styles-cls">
    <div></div>
</body>
</html>

7

Velocity 是编写此类内容的不错选择。
它允许您尽可能地将html和数据生成代码分开。


7

我强烈建议您使用非常简单的模板语言,例如Freemarker


4

这要看你创建的HTML文件类型。

对于这样的任务,我会创建一个对象,将其序列化为XML,然后使用XSL进行转换。这种方法的优点是:

  • 源代码与HTML模板之间有严格的分离,
  • 无需重新编译应用程序即可编辑HTML,
  • 可以基于相同的XML在不同情况下提供不同的HTML,甚至在需要时直接提供XML(例如进一步反序列化),
  • 需要编写的代码较少。

缺点是:

  • 必须了解XSLT并知道如何在Java中实现它。
  • 必须编写XSLT(对许多开发人员来说是一种折磨)。
  • 使用XSLT将XML转换为HTML时,某些部分可能会很棘手。几个例子:<textarea/>标记(使页面无法使用),XML声明(可能会导致IE出现问题),空格(带有<pre></pre>标记等),HTML实体(&nbsp;)等。
  • 性能会降低,因为序列化到XML会浪费大量CPU资源,而XSL转换也非常昂贵。

现在,如果你的HTML非常短或者非常重复,或者HTML具有动态更改的易变结构,则不应考虑使用此方法。另一方面,如果您提供具有相似结构的HTML文件并希望减少Java代码量并使用模板,则此方法可能有效。


4
我在寻找满足我的需求的简单东西时也遇到了问题,所以我决定自己编写一个库(使用MIT许可证)。 它主要基于组合和构建者模式。
一个基本的声明性示例是:
import static com.github.manliogit.javatags.lang.HtmlHelper.*;

html5(attr("lang -> en"),
  head(
    meta(attr("http-equiv -> Content-Type", "content -> text/html; charset=UTF-8")),
    title("title"),
    link(attr("href -> xxx.css", "rel -> stylesheet"))
  )
).render();

一个流利的例子是:
ul()
  .add(li("item 1"))
  .add(li("item 2"))
  .add(li("item 3"))     

你可以在这里查看更多例子。
我还创建了一个在线转换器,可以实时将每个HTML片段(从复杂的Bootstrap模板到简单的单个片段)转换为Java标签。

工作得很好,非常优雅! - Yu Jiaao
attr("href -> xxx.css",...) 给人的印象是,这个库会产生解析开销来进行写入。为什么不使用 attrs(attr("href", "xxx.css"), ...) 呢? - haui

2

基于在内存中预先创建文档的模板和其他方法可能会对生成的文档大小施加一定限制。

同时,基于SAX处理程序和默认XSLT转换器的简单可靠的即时写入纯HTML创建方法存在,后者具有HTML输出的固有能力:

String encoding = "UTF-8";
FileOutputStream fos = new FileOutputStream("myfile.html");
OutputStreamWriter writer = new OutputStreamWriter(fos, encoding);
StreamResult streamResult = new StreamResult(writer);

SAXTransformerFactory saxFactory =
    (SAXTransformerFactory) TransformerFactory.newInstance();
TransformerHandler tHandler = saxFactory.newTransformerHandler();
tHandler.setResult(streamResult);

Transformer transformer = tHandler.getTransformer();
transformer.setOutputProperty(OutputKeys.METHOD, "html");
transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
transformer.setOutputProperty(OutputKeys.INDENT, "yes");

writer.write("<!DOCTYPE html>\n");
writer.flush();
tHandler.startDocument();
    tHandler.startElement("", "", "html", new AttributesImpl());
        tHandler.startElement("", "", "head", new AttributesImpl());
            tHandler.startElement("", "", "title", new AttributesImpl());
                tHandler.characters("Hello".toCharArray(), 0, 5);
            tHandler.endElement("", "", "title");
        tHandler.endElement("", "", "head");
        tHandler.startElement("", "", "body", new AttributesImpl());
            tHandler.startElement("", "", "p", new AttributesImpl());
                tHandler.characters("5 > 3".toCharArray(), 0, 5); // note '>' character
            tHandler.endElement("", "", "p");
        tHandler.endElement("", "", "body");
    tHandler.endElement("", "", "html");
tHandler.endDocument();
writer.close();

请注意,XSLT转换器会为您减轻转义特殊字符(如>)的负担,因为它会自行处理这些问题。
而且,将SAX方法(例如startElement()characters())封装成更方便的形式也很容易。

使用标准工具的想法不错。不幸的是,编写tHandler.startElement("", "", "p", new AttributesImpl())非常繁琐 - 更糟糕的是,如果想在元素上设置CSS类... - haui
@haui 嗯,那只是一个想法。可以定义一些简写包装器来保存打字或复制粘贴... :) - Sergey Ushakov

1

0

如果你觉得工作变得重复了,我认为你应该进行代码重用!为什么不编写函数来“编写”HTML的小构建块呢?明白我的意思吗?例如,你可以有一个函数,你可以向它传递一个字符串,它会自动将其放入段落标签中并呈现出来。当然,你还需要编写一些基本解析器来完成这个任务(函数如何知道在哪里附加段落!)。我不认为你是初学者...所以我不会详细解释...如果你不理解,请告诉我。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接