在JSF托管bean构造函数中,我从数据库usint加载一个实体请求参数。有时,实体不在数据库中,我想显示其他带有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;
}
}
我将web.xml文件配置为:
<error-page>
<error-code>404</error-code>
<location>/404.xhtml</location>
</error-page>
我有一个JSF页面来处理托管bean加载的实体。当实体存在时,我将在页面中使用它。像那样:
<h1>#{someBean.someEntity.name}</h1>
<h2>#{someBean.someEntity.description}</h2>
<ui:repeat value="#{someBean.someEntity.books}" var="book">
// ..........
</ui:repeat>
当托管成功加载数据时,上面的页面有效。
当实体不存在且我发送404 ERROR CODE时,JSF仍处理第一页表达语言中定义的方法。
此行为使托管bean抛出NullPointerException和HTTP 500 ERRO CODE
我的404错误页面未被调用。我不知道为什么。
即使在数据库中找到实体并且404错误页面正常工作,我也会尝试发送404错误。
Enyone可以解释这个JSF行为给这个幸福吗?或提供某种显示404错误页面而不更改URL?
答案 0 :(得分:4)
您基本上是在渲染视图时尝试执行前端控制器逻辑。您应该在呈现视图之前执行此操作。因为,一旦开始渲染视图,将视图更改为其他目的地已经太晚了,例如您的情况下的错误页面。您无法从客户端收回已发送的响应。
在JSF 2.2中,您可以使用<f:viewAction>
。
<f:metadata>
<f:viewAction action="#{bean.init}" />
</f:metadata>
public void init() {
// ...
if (someCondition) {
context.getExternalContext().responseSendError(404, "some message");
context.responseComplete();
}
}
(请注意,无论何时需要将javax.servlet.*
类导入JSF辅助bean,都应该绝对停下来查看ExternalContext
中是否已有功能,或者另外三思而后行如果你正在以正确的方式做事,例如,你可能需要一个servlet过滤器;还要注意你需要明确地告诉JSF你已经完成了响应,否则它仍然会尝试渲染视图) < / p>
在JSF 2.0 / 2.1中,您可以使用<f:event type="preRenderView">
。另见其他What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
如果您实际上尝试验证HTTP请求参数并且您也碰巧使用OmniFaces,您可以考虑将<f:viewParam>
与真正的JSF验证程序一起使用,并使用OmniFaces控制sendError
{{ 3}}