JSF 2.2中<f:viewAction>初始化Bean仅首次触发的问题
<f:viewAction>在表单转发后不触发的问题 首先得明确问题的核心原因:你用<h:commandButton>返回不带&faces-redirect=true的页面路径时,JSF执行的是服务器端转发(Forward),而非客户端重定向(Redirect)。<f:viewAction>的onPostback="true"属性只会响应客户端发起的POST回传请求(比如点击提交按钮时的POST),但服务器内部转发属于同一个请求的延续,不会重新触发视图元数据(<f:metadata>)的处理逻辑,所以initialize()方法自然不会被调用。
而且你用的是ViewScope Bean,转发时Bean实例会被保留,这也是页面静态内容能正常显示,但需要initialize()刷新的nameOfUser这类属性无法更新的原因。
下面给你几个可行的解决方案:
方案一:在uploadFile()方法中手动调用initialize()
这是最直接的办法,既然转发后Bean还是同一个实例,那在文件上传完成后直接手动触发初始化逻辑即可:
public String uploadFile() { // 你的文件上传处理代码 // ... // 上传完成后手动调用初始化方法刷新数据 initialize(); System.out.println(nameOfUser.size()); return "/myJsfPage.xhtml"; }
- 优点:简单直接,无需修改页面代码,也不会丢失ViewScope的状态
- 缺点:如果有多个类似的提交方法,需要重复调用
initialize(),存在一定冗余
方案二:利用JSF系统事件统一触发初始化
可以给Bean添加一个带@PostInvokeAction注解的方法,在每个Action方法执行完成后自动触发初始化逻辑:
import javax.faces.event.PostInvokeEvent; import javax.faces.bean.ViewScoped; import javax.inject.Named; import javax.faces.context.FacesContext; @Named @ViewScoped public class MyBean implements Serializable { // 你的其他代码... public void initialize() { setAllFilesOfUser(myDatabaseFunction()); } public String uploadFile() { // 上传处理逻辑 return "/myJsfPage.xhtml"; } // 添加该方法,在每个Action执行后自动触发 @PostInvokeAction public void postInvoke() { // 可判断当前请求的页面,避免不必要的调用 if ("/myJsfPage.xhtml".equals(FacesContext.getCurrentInstance().getViewRoot().getViewId())) { initialize(); } } }
注意:如果你的Bean用的是JSF原生的@ManagedBean而非CDI的@Named,2.2.10版本的Mojarra也支持@PostInvokeAction注解。
- 优点:不用在每个Action方法里重复调用,统一管理初始化逻辑
- 缺点:需要额外的事件处理代码,对新手来说有一定学习成本
方案三:改用客户端重定向(需注意ViewScope状态)
如果可以接受ViewScope Bean被销毁重建,你可以修改uploadFile()的返回值,加上&faces-redirect=true:
public String uploadFile() { // 上传处理逻辑 return "/myJsfPage.xhtml?faces-redirect=true"; }
同时调整<f:viewAction>的属性,因为重定向后是GET请求,属于初始请求,不需要onPostback="true":
<f:metadata> <f:viewAction action="#{myBean.initialize}"/> </f:metadata>
- 优点:符合RESTful风格,页面URL会更新,避免刷新页面重复提交
- 缺点:ViewScope Bean会被销毁重建,之前的状态会丢失,若需保留上传前的状态则不适用
额外注意点
- 你提到移除
onPostback="true"无效,因为转发既不属于客户端回传,也不属于新的初始请求,所以无论有没有这个属性,<f:viewAction>都不会触发 - Mojarra 2.2.10存在一些
<f:viewAction>的小bug,如果上述方案都不生效,可以考虑升级到Mojarra 2.2.x的最新版本(比如2.2.20),可能解决兼容性问题
你可以根据业务需求选择最合适的方案,优先推荐方案一,能快速解决问题。
内容的提问来源于stack exchange,提问作者gogogaga

