JSF 2.3:ViewScoped Bean能否继承另一个并按权限在xhtml引用?
JSF 2.3中ViewScoped Bean的继承与条件引用方案
一、是否支持ViewScoped Bean继承?
完全可以。不管是使用JSF原生的@ViewScoped(javax.faces.view.ViewScoped)还是结合CDI的方式,ViewScoped Bean之间的继承都不受限制。子类会默认继承父类的作用域注解,也可以显式声明相同的作用域来增强代码可读性。
二、实现继承的具体代码示例
1. 父类ViewScoped Bean(通用逻辑封装)
import javax.faces.view.ViewScoped; import javax.inject.Named; import java.io.Serializable; @Named @ViewScoped public class BaseViewBean implements Serializable { // 通用属性,比如权限标记、基础数据 protected boolean hasAdminAccess; // 通用方法,比如初始化公共数据 public void initCommonData() { // 这里写所有视图都需要的初始化逻辑 } }
2. 子类ViewScoped Bean(角色专属逻辑)
管理员专属Bean:
import javax.faces.view.ViewScoped; import javax.inject.Named; @Named("adminView") @ViewScoped public class AdminViewBean extends BaseViewBean { // 管理员专属属性 private String adminOnlyData; // 管理员专属方法 public void executeAdminOperation() { // 管理员特有的业务逻辑 } // Getter/Setter public String getAdminOnlyData() { return adminOnlyData; } }
普通用户专属Bean:
import javax.faces.view.ViewScoped; import javax.inject.Named; @Named("userView") @ViewScoped public class UserViewBean extends BaseViewBean { // 普通用户专属属性 private String userOnlyData; // 普通用户专属方法 public void executeUserOperation() { // 普通用户特有的业务逻辑 } // Getter/Setter public String getUserOnlyData() { return userOnlyData; } }
三、在XHTML中根据条件引用不同Bean
可以通过JSF的rendered属性或者JSTL标签,结合权限判断逻辑来动态渲染对应Bean的内容。
方式1:直接用rendered属性切换
<!-- 假设有一个用于权限判断的securityBean,提供isAdmin()方法 --> <h:panelGroup rendered="#{securityBean.isAdmin}"> <h:outputText value="管理员专属区域" /> <h:commandButton value="执行管理员操作" action="#{adminView.executeAdminOperation}" /> <p>管理员数据:#{adminView.adminOnlyData}</p> </h:panelGroup> <h:panelGroup rendered="#{!securityBean.isAdmin}"> <h:outputText value="普通用户区域" /> <h:commandButton value="执行用户操作" action="#{userView.executeUserOperation}" /> <p>用户数据:#{userView.userOnlyData}</p> </h:panelGroup>
方式2:通过路由Bean统一引用
如果希望在XHTML中只用一个统一的变量名引用Bean,可以创建一个路由Bean动态返回对应实例:
import javax.faces.view.ViewScoped; import javax.inject.Inject; import javax.inject.Named; import javax.enterprise.inject.Instance; import java.io.Serializable; @Named @ViewScoped public class ViewRouterBean implements Serializable { @Inject private SecurityBean securityBean; @Inject private Instance<AdminViewBean> adminViewInstance; @Inject private Instance<UserViewBean> userViewInstance; public BaseViewBean getCurrentView() { if (securityBean.isAdmin()) { return adminViewInstance.get(); } else { return userViewInstance.get(); } } }
然后在XHTML中统一调用:
<!-- 注意:父类BaseViewBean需要定义抽象方法,子类实现 --> <h:commandButton value="执行操作" action="#{viewRouter.currentView.executeOperation}" /> <p>当前视图数据:#{viewRouter.currentView.commonData}</p>
四、关键注意事项
- 作用域一致性:子类必须保持和父类相同的
@ViewScoped作用域,不能切换为其他作用域(如@RequestScoped),否则会导致Bean生命周期冲突。 - 序列化要求:所有ViewScoped Bean必须实现
Serializable接口,因为JSF在视图保存阶段会序列化Bean实例。 - CDI管理标记:确保所有Bean都用
@Named或其他CDI管理注解标记,否则无法被注入或通过EL访问。 - 避免名称歧义:子类最好显式指定
@Named的value属性(如@Named("adminView")),防止父类和子类的EL名称冲突。
内容的提问来源于stack exchange,提问作者Alex Mi
相关产品推荐
相关产品推荐

