[英]How to create a modular JSF 2.0 application?
I have an application with a well defined interface. 我有一个具有良好定义的界面的应用程序。 It uses CDI for resolution of the modules, (Specifically it uses Instance<> injection points on API interfaces to resolve modules) and passes various data back and fourth via the interfaces without issue.
它使用CDI来解析模块,(特别是它使用API接口上的Instance <>注入点来解析模块)并通过接口传回各种数据而没有问题。 I've intentionally kept the API and implementation separate, and the modules only inherit from the API to avoid tight coupling, and the application only knows of the modules through runtime dependancies, and data passing accomplished via the APIs.
我故意将API和实现分开,并且模块仅从API继承以避免紧密耦合,并且应用程序仅通过运行时依赖性知道模块,并且通过API完成数据传递。 The application runs fine without the modules, which can be added simply by dropping the jar into the WEB-INF/lib folder and restarting the app server.
应用程序在没有模块的情况下运行正常,只需将jar放入WEB-INF / lib文件夹并重新启动应用服务器即可添加。
Where I'm running into issues is that I want the modules to create a portion of the view, and I therefor want to invoke, in a portable way, either a JSF component, or do an include from the module in order to have it render its view. 我遇到问题的地方是我希望模块创建视图的一部分,因此我想以可移植的方式调用JSF组件,或者从模块中执行包含以获取它渲染它的观点。 I already have resolved what module I want to invoke, and have references to the module's interface ready.
我已经解决了我想要调用的模块,并准备好了对模块接口的引用。 The way I initially thought to do this was to do a ui:include that asks the module to supply where it's view template is, but I have no idea how to answer that query in a meaningful way, as view resolution is done from the application root, not the library root.
我最初认为这样做的方法是做一个ui:include要求模块提供它的视图模板的位置,但我不知道如何以有意义的方式回答该查询,因为视图解析是从应用程序完成的root,而不是库根。
The executive summary is that I have no idea how to jump the gap from Application to Library using JSF for .xhtml (template/component) files. 执行摘要是我不知道如何使用JSF为.xhtml(模板/组件)文件从应用程序跳到库。
Using a CC would be nice, but how do I specify that I want a particular CC instance at runtime, instead of having that hard coded into the page? 使用CC会很好,但是如何在运行时指定我想要一个特定的CC实例,而不是将其硬编码到页面中?
I can of course invoke the application code directly and ask it for markup, but this seems really brute force, and once I have the markup, I'm not sure exactly how to tell JSF to evaluate it. 我当然可以直接调用应用程序代码并要求它进行标记,但这似乎是非常强大的,一旦我有了标记,我就不确定如何告诉JSF来评估它。 That said, I can imagine a component that would take the resource path, grab the markup and evaluate it, returning the completed markup, I just don't know how to implement that.
也就是说,我可以想象一个组件可以获取资源路径,获取标记并对其进行评估,返回完成的标记,我只是不知道如何实现它。
I'd rather avoid forcing module developers to go the heavy duty UIComponent approach if possible, which means either a dynamic way of doing ui:include (or some equivalent) or a dynamic way of invoking CCs. 如果可能的话,我宁愿避免强迫模块开发人员采用重型UIComponent方法,这意味着要么采用动态方式执行ui:include(或某些等效方法),要么采用动态方式调用CC。 (I don't mind coding the UIComponent approach ONCE in the application if that's what it takes to make module developers' lives easier)
(我不介意在应用程序中编写UIComponent方法ONCE,如果这是使模块开发人员的生活更轻松的话)
Any suggestions on where I should look to figure this out? 关于我应该在哪里找出这个问题的任何建议? (I'll post the answer here if I find it first)
(如果我先找到答案,我会在这里发布答案)
I understand that your question basically boils down to How can I include Facelets views in a JAR? 我知道您的问题基本上归结为如何在JAR中包含Facelets视图?
You can do this by placing a custom ResourceResolver
in the JAR. 您可以通过在JAR中放置自定义
ResourceResolver
来完成此操作。
public class FaceletsResourceResolver extends ResourceResolver {
private ResourceResolver parent;
private String basePath;
public FaceletsResourceResolver(ResourceResolver parent) {
this.parent = parent;
this.basePath = "/META-INF/resources"; // TODO: Make configureable?
}
@Override
public URL resolveUrl(String path) {
URL url = parent.resolveUrl(path); // Resolves from WAR.
if (url == null) {
url = getClass().getResource(basePath + path); // Resolves from JAR.
}
return url;
}
}
Configure this in webapp's web.xml
as follows: 在webapp的
web.xml
配置如下:
<context-param>
<param-name>javax.faces.FACELETS_RESOURCE_RESOLVER</param-name>
<param-value>com.example.FaceletsResourceResolver</param-value>
</context-param>
Imagine that you've a /META-INF/resources/foo/bar.xhtml
in random.jar
, then you can just include it the usual way 想象一下,你在
random.jar
有一个/META-INF/resources/foo/bar.xhtml
,然后你就可以通常的方式包含它
<ui:include src="/foo/bar.xhtml" />
or even dynamically 甚至是动态的
<ui:include src="#{bean.path}" />
Note: since Servlet 3.0 and newer JBoss/JSF 2.0 versions, the whole ResourceResolver
approach is not necessary if you keep the files in /META-INF/resources
folder. 注意:从Servlet 3.0和更新的JBoss / JSF 2.0版本开始,如果将文件保存在
/META-INF/resources
文件夹中,则不需要整个ResourceResolver
方法。 The above ResourceResolver
is only mandatory in Servlet 2.5 or older JBoss/JSF versions because they've bugs in META-INF
resource resolving. 上述
ResourceResolver
仅在Servlet 2.5或更早的JBoss / JSF版本中是必需的,因为它们在META-INF
资源解析中存在缺陷。
我正在寻找有关同一主题的信息并且遇到了这个链接: 操作方法:带有CDI和PrettyFaces的模块化Java EE应用程序,对我来说非常有用。
By the way.. you can avoid implementing your own resource resolver when you're using seam solder (currently being integrated into apache deltaspike) which is a really useful library complementing CDI (your typical Java EE 6 component model) 顺便说一下..当你使用缝焊(目前正在集成到apache deltaspike中)时,你可以避免实现自己的资源解析器,这是一个非常有用的库补充CDI(典型的Java EE 6组件模型)
I too experimented with modularity in jsf applications. 我也在jsf应用程序中尝试了模块化。 Basically I built a template interface with a toolbar which gets filled with buttons provided by each module.
基本上我构建了一个带有工具栏的模板界面,该工具栏充满了每个模块提供的按钮。 Typically you will do this by providing a List of Strings as a Named Object:
通常,您将通过提供字符串列表作为命名对象来执行此操作:
@Produces
@SomethingScoped
@Named("topMenuItems")
public List<String> getTopMenuItems(){
return Arrays.asList("/button1.xhtml", "/button2.xhtml", "/button3.xhtml");
}
Notice how each of the buttons may come from a different module of the jsf application. 注意每个按钮可能来自jsf应用程序的不同模块。 The template interface contains a panel where
模板界面包含一个面板
you can use it in your markup the following way (at your own risk ;) ) : 您可以通过以下方式在标记中使用它(风险自负;)):
....
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
....
<xy:toolbar>
<xy:toolbarGroup>
<c:forEach items="#{topMenuItems}" var="link">
<ui:include src="#{link}" />
</c:forEach>
</xy:toolbarGroup>
</xy:toolbar>
<xy:panel>
<ui:include src="#{contentPath}"/>
</xy:panel>
This was the toolbar and the content panel. 这是工具栏和内容面板。
a simple button or view definition may look like this: 一个简单的按钮或视图定义可能如下所示:
<ui:composition ...>
<xy:commandButton actionListener="#{topMenuController.switchContent()}"
value="Test" id="testbutton" />
</ui:composition>
lets name this artifact view1.xhtml 让我们为这个工件命名view1.xhtml
When this button is pushed (which doesn't trigger a postback using the actionListener, we want to reload the content using ajax) the switchContentMethod in your controller may change the string returned by getContentPath : 当按下此按钮(不使用actionListener触发回发时,我们希望使用ajax重新加载内容)控制器中的switchContentMethod可能会更改getContentPath返回的字符串:
public void switchContent(){
contentPath = "/view1.xhtml";
}
@Produces
@SomethingScoped
@Named("contentPath")
public String getContentPath(){
return contentPath;
}
now you can change the view displayed in the panel using the button in the menubar which sort of gives you navigation without page reloads. 现在,您可以使用菜单栏中的按钮更改面板中显示的视图,这样可以在不重新加载页面的情况下进行导航。
Some advice ( or 'what I've learned' ) : 一些建议(或“我学到的东西”):
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.