这是JSF会话作用域验证器的正常行为吗?
实现:org.glassfish 2.2.12 我有以下会话范围的验证器:这是JSF会话作用域验证器的正常行为吗?,jsf,jsf-2.2,Jsf,Jsf 2.2,实现:org.glassfish 2.2.12 我有以下会话范围的验证器: @ManagedBean @SessionScoped public class CreateGroupNameValidator extends LengthValidator implements Serializable{ @ManagedProperty(value="#{myDao}") private MyDao myDao; //Validate methods } 尽管是会话
@ManagedBean
@SessionScoped
public class CreateGroupNameValidator extends LengthValidator implements Serializable{
@ManagedProperty(value="#{myDao}")
private MyDao myDao;
//Validate methods
}
尽管是会话范围和可序列化的,但当回发时,验证程序无法恢复属性myDao的值。我使用了debugger并计算出状态由类StateHolderSaver
保存,该类具有以下构造函数:
public StateHolderSaver(FacesContext context, Object toSave) {
className = toSave.getClass().getName();
if (toSave instanceof StateHolder) {
// do not save an attached object that is marked transient.
if (!((StateHolder) toSave).isTransient()) {
Serializable [] tuple = new Serializable[StateHolderTupleIndices.LastMember.ordinal()];
tuple[StateHolderTupleIndices.StateHolderSaverInstance.ordinal()] =
(Serializable) ((StateHolder) toSave).saveState(context);
if (toSave instanceof UIComponent) {
tuple[StateHolderTupleIndices.ComponentAddedDynamically.ordinal()] = ((UIComponent)toSave).getAttributes().containsKey(DYNAMIC_COMPONENT) ? Boolean.TRUE : Boolean.FALSE;
}
savedState = tuple;
} else {
className = null;
}
} else if (toSave instanceof Serializable) {
savedState = (Serializable) toSave;
className = null;
}
}
因此,由于
LenghtValidator
实现了javax.faces.component.StateHolder
它没有保存我的初始Dao值。这是正常行为吗?这确实是指定的行为。另见a.o.:
验证程序
实现必须具有零参数公共构造函数。此外,如果验证程序类希望在视图中保存和还原配置属性值,则实现还必须实现StateHolder
转换器和验证器可以保存在JSF状态,这样JSF实现就可以确保它们在恢复视图后,与呈现前一个请求的视图时一样,完全具有预期的属性值(例如最小值
和最大值
在长度验证器
的情况下,它们可能引用动态EL表达式)
尽管我必须承认他们在设计JSF 1.0规范(转换器/验证器仍然基于此)时确实考虑过,但他们并没有真正考虑在JSF转换器/验证器中注入业务服务实例的可能性。当然,您不想将其保存在JSF视图状态。如果是托管属性(因此不是EJB/CDI代理),它只会破坏JSF视图状态(在服务器端状态保存的情况下也会破坏HTTP会话)
如果您不需要验证程序是JSF状态感知的,请使用组合而不是继承
public class CreateGroupNameValidator {
private LengthValidator lengthValidator;
public CreateGroupNameValidator() {
lengthValidator = new LengthValidator();
}
// ...
}
尽管如此,将验证器放在会话范围内还是有点可疑。这意味着验证器的行为特定于当前HTTP会话。我想不出有意义的实际用例,因为它们本质上是视图范围(不是验证器实例,而是验证器属性)。通常是会话范围内的数据(例如登录用户)是在线程本地基础上注入/解析的。如果它是有状态的,最好将其设置为请求范围(即每个请求/视图的验证程序属性可能不同),如果它是无状态的,则将其设置为应用程序范围(即验证程序属性在应用程序的整个生命周期内都相同).什么是
MyDao
?这个名字意味着它是一个服务类或EJB,不能使用@ManagedProperty
注入,如果是这样的话(并且需要像@EJB
、@Inject
或@Autowired
)这样的注释)。真正的验证器(或转换器)最多只能有两个作用域中的一个,请求作用域(@FacesValidator
)或者应用程序作用域。其余的作用域没有多大意义。@Tiny它是一个spring bean。无法为此想出合理的现实世界用例,因为它们本身就是视图作用域。实际上,应用程序作用域会更好。您当然不想将其保存在JSF视图状态。实际上,从安全角度来看,这是不安全的。但是如果对象没有实现StateHolder
,但是Serializable
,如果不在javax.faces.viewState
中,它什么时候被保存?仅仅通过savedState=(Serializable)很难说什么toSave;className=null;
或者它是一个依赖于实现的东西,而我们实际上并不关心它?如果它实现了可序列化的,那么它也保存在状态中。JSF规范说,附加到组件实例的对象(转换器、验证器和侦听器)也保存在状态中。但是在客户端视图状态下,我们向客户端公开我们的EJB。它安全吗?数据库实时EJB通常包含DataSource
实现,该实现反过来保存DB url和user/passowrd属性
EJB(和CDI bean)被注入为。