当托管 bean 构造函数发送 404 错误代码时 JSF 调用方法

Wel*_*ula 5 jsf jsf-2

在 JSF 托管 bean 构造函数中,我使用请求参数从数据库加载实体。有时,实体不在数据库中,我想显示带有 404 消息的其他 JSF (.xhtml) 页面。
这是托管 bean 的示例:

@ManagedBean(name = "someBean")
@RequestScoped
public class SomeBean implements Serializable {

    private static final long serialVersionUID = 1L;

    private SomeData someData;

    public SomeBean() throws IOException {
        someData = ... loads from database using JPA features
        if(someData == null){
              HttpServletResponse response = (HttpServletResponse) FacesContext
                    .getCurrentInstance().getExternalContext().getResponse();
              response.sendError(404);
        }
    }

    public SomeData getSomeData(){
        return someData;
    }
}
Run Code Online (Sandbox Code Playgroud)

我配置了类似这样的 web.xml 文件:

<error-page>
   <error-code>404</error-code>
   <location>/404.xhtml</location>
</error-page>
Run Code Online (Sandbox Code Playgroud)

我有一个 JSF 页面来处理托管 bean 加载的实体。当实体存在时,我将在页面中使用它。像那样:

<h1>#{someBean.someEntity.name}</h1>
<h2>#{someBean.someEntity.description}</h2>
<ui:repeat value="#{someBean.someEntity.books}" var="book">
// ..........
</ui:repeat>
Run Code Online (Sandbox Code Playgroud)

当托管成功加载数据时,上面的页面工作。

问题

当实体不存在并且我发送 404 ERROR CODE 时,JSF 仍然处理在第一页的表达式语言中定义的方法。
此行为使托管 bean 抛出 NullPointerException 和 HTTP 500 错误代码。
我的 404 错误页面没有被调用。我不知道为什么。

即使在数据库中找到实体并且 404 错误页面有效,我也会尝试发送 404 错误。

任何人都可以将这种 JSF 行为解释为这种幸福吗?或者提供某种无需更改 URL 即可显示 404 错误页面的方法?

Bal*_*usC 5

您基本上是在渲染视图时尝试执行前端控制器逻辑。您应该渲染视图之前执行此操作。因为,一旦您开始渲染视图,将视图更改为不同的目的地(例如您的情况中的错误页面)已经太晚了。您即不能从客户端取回已经发送的响应。

在 JSF 2.2 中,您可以使用<f:viewAction>它。

<f:metadata>
    <f:viewAction action="#{bean.init}" />
</f:metadata>
Run Code Online (Sandbox Code Playgroud)
<f:metadata>
    <f:viewAction action="#{bean.init}" />
</f:metadata>
Run Code Online (Sandbox Code Playgroud)

(请注意,每当您需要将javax.servlet.*类导入 JSF 支持 bean 时,您绝对应该停下来看看该功能是否已经可用,ExternalContext或者如果您以正确的方式做事,请三思,例如,也许您需要一个 servlet过滤器;还要注意,你需要明确告诉 JSF 你已经完成了响应,否则它仍然会尝试呈现视图)

在 JSF 2.0/2.1 中,您可以使用<f:event type="preRenderView">它。另请参见<f:metadata>、<f:viewParam> 和 <f:viewAction> 可以用来做什么?

如果您实际上尝试验证 HTTP 请求参数并且您也碰巧使用 OmniFaces,您可以考虑使用<f:viewParam>真正的 JSF 验证器并sendError使用 OmniFaces控制<o:viewParamValidationFailed>