如何使用 JSF 和导航规则创建带参数的 GET 请求?

2022-01-10 00:00:00 redirect navigation java jsf

有没有办法使用 h:outputLink、其他 JSF 标记或代码创建带有请求参数的非面孔请求 (HTTP GET) 的 html 链接?

Is there a way to create an html link using h:outputLink, other JSF tag or code to create a non faces request (HTTP GET) with request parameters?

例如我有以下导航规则

<navigation-rule>
    <navigation-case>
        <from-outcome>showMessage</from-outcome>
        <to-view-id>/showMessage.jsf</to-view-id>
        <redirect/>
    </navigation-case>
</navigation-rule>

在我的页面中,我想输出以下 html 代码:

In my page I would like to output the following html code:

<a href="/showMessage.jsf?msg=23">click to see the message</a>

我可以只在页面中编写 html 代码,但我想使用导航规则以便将所有 url 定义在一个可配置文件中.

I could just write the html code in the page, but I want to use the navigation rule in order to have all the urls defined in a single configurable file.

推荐答案

这是一个有趣的想法.我很想知道它在实践中的表现如何.

This is an interesting idea. I'd be curious to know how it pans out in practice.

获取导航规则

导航由 处理导航处理程序.掌握 NavigationHandler 并不难,但 API 不会公开它使用的规则.

Navigation is handled by the NavigationHandler. Getting hold of the NavigationHandler isn't difficult, but the API does not expose the rules it uses.

在我看来,你可以:

  1. 在初始化时解析 faces-config.xml 并将规则存储在应用程序上下文中 (easy)
  2. 实现您自己的 NavigationHandler 忽略 faces-config.xml 中的规则或用您自己的规则文件补充它们并以某种方式公开其规则集(可行,但需要一些工作)
  3. 模拟你自己的 FacesContext 并将其传递给现有的导航处理程序(真的很难让两个 FacesContext 对象在同一个线程中共存并且效率极低)
  1. parse faces-config.xml on initialization and store the rules in the application context (easy)
  2. implement your own NavigationHandler that ignores the rules in faces-config.xml or supplements them with your own rules file and exposes its ruleset somehow (workable, but takes a bit of work)
  3. mock your own FacesContext and pass it to the existing navigation handler (really difficult to make two FacesContext object coexist in same thread and extremely inefficient)

现在,您还有另一个问题.您要将映射保存在哪里以查找视图?将它们硬编码在 bean 中?

Now, you have another problem too. Where are you going to keep the mappings to look up the views? Hard-code them in the beans?

使用导航规则

顺便说一句,我可以想到两种方法可以从后端构造包含参数的 URL.两者都涉及定义某种 bean.

Off hand, I can think of two ways you could construct parameter-containing URLs from the back-end. Both involve defining a bean of some kind.

<managed-bean>
    <managed-bean-name>navBean</managed-bean-name>
    <managed-bean-class>foo.NavBean</managed-bean-class>
    <managed-bean-scope>application</managed-bean-scope>
</managed-bean>

来源:

package foo;

import java.io.IOException;
import java.io.Serializable;
import java.net.URLEncoder;

import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;

public class NavBean implements Serializable {

    private String getView() {
        String viewId = "/showMessage.faces"; // or look this up somewhere
        return viewId;
    }

    /**
     * Regular link to page
     */
    public String getUrlLink() {
        FacesContext context = FacesContext.getCurrentInstance();
        ExternalContext extContext = context.getExternalContext();
        String viewId = getView();
        String navUrl = context.getExternalContext().encodeActionURL(
                extContext.getRequestContextPath() + viewId);
        return navUrl;
    }

    /**
     * Just some value
     */
    public String getValue() {
        return "" + System.currentTimeMillis();
    }

    /**
     * Invoked by action
     */
    public String invokeRedirect() {
        FacesContext context = FacesContext.getCurrentInstance();
        ExternalContext extContext = context.getExternalContext();
        String viewId = getView();
        try {
            String charEncoding = extContext.getRequestCharacterEncoding();
            String name = URLEncoder.encode("foo", charEncoding);
            String value = URLEncoder.encode(getValue(), charEncoding);
            viewId = extContext.getRequestContextPath() + viewId + '?' + name
                    + "=" + value;
            String urlLink = context.getExternalContext().encodeActionURL(
                    viewId);
            extContext.redirect(urlLink);
        } catch (IOException e) {
            extContext.log(getClass().getName() + ".invokeRedirect", e);
        }
        return null;
    }

}

获取

对于 GET 请求,您可以使用 UIParameters 设置值并让渲染器构建参数列表.

For a GET request, you can use the UIParameters to set the values and let the renderer build the parameter list.

<h:outputLink value="#{navBean.urlLink}">
    <f:param name="foo" value="#{navBean.value}" />
    <h:outputText value="get" />
</h:outputLink>

发布

如果您想在 POST 操作期间将 URL 设置为视图,您可以在操作中使用重定向(由按钮或 commandLink 调用).

If you want to set the URL to a view during a POST action, you can do it using a redirect in an action (invoked by a button or commandLink).

<h:commandLink id="myCommandLink" action="#{navBean.invokeRedirect}">
    <h:outputText value="post" />
</h:commandLink>

备注

请注意 ExternalContext.encodeActionURL 用于对字符串进行编码.这是生成可跨上下文(portlet 等)移植的代码的良好实践.如果您正在对图像或下载文件的链接进行编码,则可以使用 encodeResourceURL.

Note that ExternalContext.encodeActionURL is used to encode the string. This is good practice for producing code that is portable across contexts (portlets, etcetera). You would use encodeResourceURL if you were encoding a link to an image or download file.

相关文章