JSF(Java Server Faces)的StateHolder的作用和使用方法
UI控件、转换器和验证器实现了StateHolder接口表示组件具有了状态,可以保存一些组件自身的属性。
下面我们来看一个简单的例子。
这是一个正则表达式验证器的例子:
public
class
RegexValidator
implements
Validator
{
/** *//**
* The message identifier of the Message to be created if
* the validation fails.
*/
public static final String REGEX_INVALID_MESSAGE_ID =
"validator.Regex_Invalid";
private String formatPatterns = null;
/** *//**
* 出错时的提示内容名称,例如邮编
*/
private String errorPatternDisplayName = null;
/** *//**
* 获得样式的配置文件
*/
private static final ResourceBundle bundle = ResourceBundle.getBundle(Const.BUNDLE_ROOT + ".RegexPattern");
/** *//**
* 资源配置文件中对应的样式名称
*/
private String formatPatternName = null;
public RegexValidator()
{
super();
}
public RegexValidator(String formatPatternName)
{
setFormatPatternName(formatPatternName);
}
public void validate(FacesContext context, UIComponent component, Object toValidate)
throws ValidatorException
{
if(context == null || component == null)
throw new NullPointerException();
if(!(component instanceof UIOutput))
return;
if(formatPatterns == null || formatPatterns.length() == 0 || null == toValidate)
return;
String value = toValidate.toString();
Pattern p = Pattern.compile(this.formatPatterns);
Matcher m = p.matcher(value);
boolean b = m.matches();
if(!b)
{
FacesMessage errMsg = MessageFactory.getMessage(context,
this.REGEX_INVALID_MESSAGE_ID,
new Object[]{errorPatternDisplayName});
throw new ValidatorException(errMsg);
}
}
public String getFormatPatternName()
{
return formatPatternName;
}
public void setFormatPatternName(String formatPatternName)
{
this.formatPatternName = formatPatternName;
this.errorPatternDisplayName = bundle.getString(formatPatternName);
this.formatPatterns = bundle.getString(formatPatternName+"_patterns");
}
}
{
/** *//**
* The message identifier of the Message to be created if
* the validation fails.
*/
public static final String REGEX_INVALID_MESSAGE_ID =
"validator.Regex_Invalid";
private String formatPatterns = null;
/** *//**
* 出错时的提示内容名称,例如邮编
*/
private String errorPatternDisplayName = null;
/** *//**
* 获得样式的配置文件
*/
private static final ResourceBundle bundle = ResourceBundle.getBundle(Const.BUNDLE_ROOT + ".RegexPattern");
/** *//**
* 资源配置文件中对应的样式名称
*/
private String formatPatternName = null;
public RegexValidator()
{
super();
}
public RegexValidator(String formatPatternName)
{
setFormatPatternName(formatPatternName);
}
public void validate(FacesContext context, UIComponent component, Object toValidate)
throws ValidatorException
{
if(context == null || component == null)
throw new NullPointerException();
if(!(component instanceof UIOutput))
return;
if(formatPatterns == null || formatPatterns.length() == 0 || null == toValidate)
return;
String value = toValidate.toString();
Pattern p = Pattern.compile(this.formatPatterns);
Matcher m = p.matcher(value);
boolean b = m.matches();
if(!b)
{
FacesMessage errMsg = MessageFactory.getMessage(context,
this.REGEX_INVALID_MESSAGE_ID,
new Object[]{errorPatternDisplayName});
throw new ValidatorException(errMsg);
}
}
public String getFormatPatternName()
{
return formatPatternName;
}
public void setFormatPatternName(String formatPatternName)
{
this.formatPatternName = formatPatternName;
this.errorPatternDisplayName = bundle.getString(formatPatternName);
this.formatPatterns = bundle.getString(formatPatternName+"_patterns");
}
}
它的Tag标签:
public
class
RegexValidatorTag
extends
ValidatorELTag
{
private String formatPatternName;
public RegexValidatorTag()
{
super();
}
/**//* (non-Javadoc)
* @see javax.faces.webapp.ValidatorELTag#createValidator()
*/
@Override
protected Validator createValidator() throws JspException
{
RegexValidator v = new RegexValidator();;
v.setFormatPatternName(formatPatternName);
return v;
}
public String getFormatPatternName()
{
return formatPatternName;
}
public void setFormatPatternName(String formatPatternName)
{
this.formatPatternName = formatPatternName;
}
}
这个验证标签接受一个名称作为参数,通过此名称可以从相关配置文件中查找到相应的正则表达式和其他一些配置信息。
{
private String formatPatternName;
public RegexValidatorTag()
{
super();
}
/**//* (non-Javadoc)
* @see javax.faces.webapp.ValidatorELTag#createValidator()
*/
@Override
protected Validator createValidator() throws JspException
{
RegexValidator v = new RegexValidator();;
v.setFormatPatternName(formatPatternName);
return v;
}
public String getFormatPatternName()
{
return formatPatternName;
}
public void setFormatPatternName(String formatPatternName)
{
this.formatPatternName = formatPatternName;
}
}
但如果你使用这个验证器,你会发现,每次都正确调用了,也都将参数传进去了,但是在调用validate方法的时候却发现自定义的几个验证器的属性的值都为null。这是为什么呢?
因为我们第一次调用的时候初始化了一下,参数都进去了,验证器也被实例化了,但是这个验证器却是瞬时状态的,刚被页面实例化好就被释放了。所以提交表单验证的时候会重新被初始化,但这时只是调用了默认构造函数,没有将我们的正则表达式样式作为参数传进去。
如何保存验证器之前的状态呢?或者说如何让验证器不是瞬时状态呢。
这就需要实现StateHolder接口,并且实现几个方法,让JSF知道,这个验证器有自己的状态需要保存。
新的代码:
public
class
RegexValidator
implements
Validator, StateHolder
{
/** *//**
* The message identifier of the Message to be created if
* the validation fails.
*/
public static final String REGEX_INVALID_MESSAGE_ID =
"validator.Regex_Invalid";
private String formatPatterns = null;
/** *//**
* 出错时的提示内容名称,例如邮编
*/
private String errorPatternDisplayName = null;
/** *//**
* 获得样式的配置文件
*/
private static final ResourceBundle bundle = ResourceBundle.getBundle(Const.BUNDLE_ROOT + ".RegexPattern");
/** *//**
* 资源配置文件中对应的样式名称
*/
private String formatPatternName = null;
public RegexValidator()
{
super();
}
public RegexValidator(String formatPatternName)
{
setFormatPatternName(formatPatternName);
}
public void validate(FacesContext context, UIComponent component, Object toValidate)
throws ValidatorException
{
if(context == null || component == null)
throw new NullPointerException();
if(!(component instanceof UIOutput))
return;
if(formatPatterns == null || formatPatterns.length() == 0 || null == toValidate)
return;
String value = toValidate.toString();
Pattern p = Pattern.compile(this.formatPatterns);
Matcher m = p.matcher(value);
boolean b = m.matches();
if(!b)
{
FacesMessage errMsg = MessageFactory.getMessage(context,
this.REGEX_INVALID_MESSAGE_ID,
new Object[]{errorPatternDisplayName});
throw new ValidatorException(errMsg);
}
}
public String getFormatPatternName()
{
return formatPatternName;
}
public void setFormatPatternName(String formatPatternName)
{
this.formatPatternName = formatPatternName;
this.errorPatternDisplayName = bundle.getString(formatPatternName);
this.formatPatterns = bundle.getString(formatPatternName+"_patterns");
}
private boolean transientValue = false;
public void setTransient(boolean transientValue)
{
this.transientValue = transientValue;
}
public boolean isTransient()
{
return this.transientValue;
}
public void restoreState(FacesContext context, Object state)
{
Object values[] = (Object[]) state;
formatPatterns = (String) values[0];
errorPatternDisplayName = (String) values[1];
}
public Object saveState(FacesContext context)
{
Object[] values = new Object[2];
values[0] = formatPatterns;
values[1] = errorPatternDisplayName;
return values;
}
}
{
/** *//**
* The message identifier of the Message to be created if
* the validation fails.
*/
public static final String REGEX_INVALID_MESSAGE_ID =
"validator.Regex_Invalid";
private String formatPatterns = null;
/** *//**
* 出错时的提示内容名称,例如邮编
*/
private String errorPatternDisplayName = null;
/** *//**
* 获得样式的配置文件
*/
private static final ResourceBundle bundle = ResourceBundle.getBundle(Const.BUNDLE_ROOT + ".RegexPattern");
/** *//**
* 资源配置文件中对应的样式名称
*/
private String formatPatternName = null;
public RegexValidator()
{
super();
}
public RegexValidator(String formatPatternName)
{
setFormatPatternName(formatPatternName);
}
public void validate(FacesContext context, UIComponent component, Object toValidate)
throws ValidatorException
{
if(context == null || component == null)
throw new NullPointerException();
if(!(component instanceof UIOutput))
return;
if(formatPatterns == null || formatPatterns.length() == 0 || null == toValidate)
return;
String value = toValidate.toString();
Pattern p = Pattern.compile(this.formatPatterns);
Matcher m = p.matcher(value);
boolean b = m.matches();
if(!b)
{
FacesMessage errMsg = MessageFactory.getMessage(context,
this.REGEX_INVALID_MESSAGE_ID,
new Object[]{errorPatternDisplayName});
throw new ValidatorException(errMsg);
}
}
public String getFormatPatternName()
{
return formatPatternName;
}
public void setFormatPatternName(String formatPatternName)
{
this.formatPatternName = formatPatternName;
this.errorPatternDisplayName = bundle.getString(formatPatternName);
this.formatPatterns = bundle.getString(formatPatternName+"_patterns");
}
private boolean transientValue = false;
public void setTransient(boolean transientValue)
{
this.transientValue = transientValue;
}
public boolean isTransient()
{
return this.transientValue;
}
public void restoreState(FacesContext context, Object state)
{
Object values[] = (Object[]) state;
formatPatterns = (String) values[0];
errorPatternDisplayName = (String) values[1];
}
public Object saveState(FacesContext context)
{
Object[] values = new Object[2];
values[0] = formatPatterns;
values[1] = errorPatternDisplayName;
return values;
}
}
实现setTransient和isTransient两个方法是为了标明这个验证器不是瞬时状态,需要返回一个false。
实现saveState和restoreState两个方法是为了保存和还原状态,大家可以看下代码,saveState保存了当前验证器需要的几个属性参数,而restoreState将这些参数重新还原给了验证器,这样,我们使用新代码做验证的时候,就会发现它起作用了。
---------------------------------------------------------
专注移动开发
Android, Windows Mobile, iPhone, J2ME, BlackBerry, Symbian