【问题标题】:Accessing and using .jsf files from the database访问和使用数据库中的 .jsf 文件
【发布时间】:2011-06-01 13:47:28
【问题描述】:

使我的 web 应用程序能够使用存储在数据库中的 JSF 文件的最佳方法是什么? 我希望能够动态(在运行时)创建新的 JSF 页面,无需重新部署应用程序即可使用。

换句话说:我想将大部分 JSF 页面存储在数据库中,并希望 JSF 将数据库用作获取 JSF 文件的数据源。

我想了很久的解决方案并找到了一些可能的方法。但是,我无法实现其中任何一个。

  1. 每当需要添加/删除新页面时:操作类路径中的文件(例如删除或添加文件到 .war 文件)
  2. 扩展 Web 应用程序的类路径,使其能够从运行时定义的位置(即 /tmp 或直接使用数据库连接)获取文件
  3. 为 JSF 提供另一种查找资源的方法(这似乎不可能?)

我的环境:

  • Java SE 6
  • Jetty 作为 servlet 容器
  • Mojarra 作为 jsf 实现

现在,我的问题:

是否可以让 JSF 在默认类路径以外的位置(最好是数据库)查找页面?

非常感谢任何回应!

【问题讨论】:

  • 很大程度上依赖于视图技术。 JSF 只是一个 MVC 框架。您是否使用 JSP 或 Facelets 作为视图技术?如果是JSP,算了。如果是 Facelets,您提出的方法 1 和 2 应该可以完美运行。但是,使用 Jetty 可能会对整体情况产生影响。
  • Facelets 就是这样。但是,我不知道如何实现前两种可能性,您能对此发表评论吗?不过,我确实在第三种可能性click 上取得了进展。这是要走的路吗?

标签: java resources jsf-2 runtime


【解决方案1】:

1:每当必须添加/删除新页面时:操作类路径中的文件(例如删除或添加文件到 .war 文件)

如果 WAR 被扩展,这绝对是可能的。我不确定 Jetty,但它适用于我在 Tomcat 7 和 Glassfish 3 上的 Mojarra 2.x。只需将文件写入扩展的 WAR 文件夹,通常的 Java IO 方式就足够了。

File file = new File(servletContext.getRealPath("/foo.xhtml"));

if (!file.exists()) {
    OutputStream output = new FileOutputStream(file);

    try {
        output.write(bytes); // Can be bytes from DB.
    } finally {
        output.close();
    }
}

这需要在FacesServlet 启动之前执行。Filter 是一个完美的地方。另请参阅此相关答案:


2:扩展 web 应用程序的类路径,使其能够从运行时定义的位置(即 /tmp 或直接使用数据库连接)获取文件

您可以将 Facelets 文件打包到 JAR 文件中并将其放在类路径中,并提供一个 Facelets ResourceResolver,当在 WAR 中找不到匹配项时,它会提供来自 JAR 的文件。您可以在以下答案中找到完整的代码示例:


3:为 JSF 提供另一种查找资源的方法(这似乎不可能?)

自定义ResourceResolver 有足够的游戏空间。

【讨论】:

  • 我已经让它与 ResourceResolver 一起工作。感谢您的明确答复!
  • @sdegroot,你能发布你的 ResourceResolver 吗?我正在尝试和您做同样的事情,但是我很难编写从数据库中获得的 xhtml 文件并从 resolveUrl 方法返回正确的 URL。
  • @Felipe:您错过了给定两个链接中的完整代码示例?蓝色的文字是链接。当您将鼠标放在顶部直到它变成一只手时,然后单击左键。它将在您的浏览器中打开链接。
  • 感谢 BalusC。我确实看过这些链接,但由于@sdegroot 案例与我的完全一样,我希望他能分享他的代码。我设法使用了 ResourceResolver,并通过 resolveURL 方法从数据库中获取了文件,但是我很难将文件写入临时文件夹并返回正确的 URL。
  • 最终我可以解决我自己的问题。我使用了 File#createTempFile(),然后使用了 file#toURI#toURL。谢谢 BalusC 和 sdgroot!
【解决方案2】:

好问题。 BalusC 的答案是 - 一如既往 - 完整且正确。

但是,如果您的目的是创建一个动态构建 gui 的应用程序,那么有一种方法可能会更好地为您服务(取决于您真正想要实现的目标)。

JSF 视图类似于 Swing 表单——它们只是一堆粘合在一起的 JavaBeans(tm)。最大的区别在于,当一个字段绑定到一个 EL 表达式时,您不使用标准访问器,而是使用特殊方法(setValueExpression)。

这意味着您可以以纯编程方式从对象(具体类可以在 javax.faces.component.html 中找到)构建您的 GUI,然后使用绑定属性在页面上显示它。比如:

<h:form>
    <h:panelGrid binding="#{formBuilder.component}"/>
</h:form>

然后在托管的formBuilder bean中:

@PostConstruct
public void init() {
    HtmlInputText hit = new HtmlInputText();
    // properties are easy:
    hol.setStyle("border: 2px solid red");
    // binding is a bit harder:
    hit.setValueExpression("value", expression("#{test.counter}", String.class));

    HtmlOutcomeTargetLink hol = new HtmlOutcomeTargetLink();
    hol.setValue("link leading to another view");
    hol.setOutcome("whatever");

    component = new UIPanel();
    component.getChildren().add(hit);
    component.getChildren().add(hol);
}

private ValueExpression expression(String s, Class c){
    return FacesContext.getCurrentInstance().getApplication().getExpressionFactory().createValueExpression(
            FacesContext.getCurrentInstance().getELContext(),
            s, c
    );
}

上面的示例构建了一个静态面板,但可以:

  • 为您的 GUI 创建一个对象模型
  • 将模型映射到数据库(使用 hibernate 或其他 orm)
  • 编写某种适配器或桥接器以从您的对象模型构建 JSF 对象
  • 制作一个托管 bean,它接收表单 ID,从数据库中获取相关表单,从中构建一个 JSF 面板并将其呈现为一个属性,准备好被绑定。

这样你就可以只拥有一个带有单个标签的静态 xhtml,并使用它来呈现任意数量的动态表单。

正如我所说,这种方法可能比仅存储文件更好,但不一定。如果您只是想省去重新部署的麻烦,这是一个巨大的矫枉过正(再说一遍,您不需要仅仅为了更改表单而重新部署 JSF 应用程序)。另一方面,如果您的目标是拥有用户定义和编辑的表单,那么拥有一个良好的对象模型并以适当的方式存储它可能是一个好主意。

前面的颠簸将是:

  • 导航(也许自定义导航处理程序就足够了?)
  • 生成纯 html 的问题
  • 视图范围表单的生命周期可能存在一些问题

【讨论】:

  • 感谢您的补充回答!也许我可以用这个做点什么。澄清一下:我希望能够在运行时向 web 应用程序添加新页面/模板。将其视为 CMS:有人可以编写自己的 HTML(在本例中为 JSF/XHTML)。你有什么建议?
  • 我真的不推荐任何东西。如果您的用户应该知道 facelets 和 JSF,那么 BalusC 的解决方案就足够了。但是,您不需要它,因为程序员将 xhtml 文件添加到正在运行的 JSF 应用程序非常容易(服务战通常会解压缩,因此将文件添加到上下文没有问题;xhml 没有编译,因此您可以只需保存其他文件,无需重新启动或其他大惊小怪)。如果您的用户只是普通用户并且您需要某种所见即所得的表单构建器 - 我的解决方案可能会更好一些。但谁知道呢,变数太多了。
  • 在您的示例中,您仍然需要至少一个 facelet,它只提供要解析的 URL 和与某个 GUIBuilder bean 的绑定。如果我想拥有没有 facelet 胶水的完全动态 URL,有没有办法绕过对 facelet 的需求,直接从 facelet 生命周期中调用?
  • @MarkMurfin 这些是分开的:你需要一个“完全动态的 url”还是“没有 facelet 胶水”?
  • 我想我在这里找到了我想要的东西:jdevelopment.nl/authoring-jsf-pages-pure-java。我真的很想在不使用 facelets 的情况下创作人脸资源。
猜你喜欢
  • 2011-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-07
  • 2016-06-18
  • 2011-11-13
  • 1970-01-01
  • 2020-05-15
相关资源
最近更新 更多