jface databinding:构建一个改进版的通用型数值验证器StringToNumberValidator
2016-12-25 11:13
337 查看
jface已经提供了基于AbstractStringToNumberValidator的基本类型数值验证器IValidator
但是在项目实际使用中发现这些验证器有缺点:
空字符串被视为合法,可以通过验证,而一般情况下,我们会视空字符串为无效输入
数值解析错误时返回的信息为英文而且太详细,用户体验不好。其实如果用户输入了非数字导致解析错误时只要提示输入无效就可以了,没必要太详细,更不能是英文。
如上图每种数据类型验证都对应一个不同的类,这在项目中可能会增加不必要的代码复杂度,如果统一成一个类使用更加方便,也减少写代码的工作量。
针对这些问题,参考AbstractStringToNumberValidator的源码,我构建了一个通用型的数值验证器类StringToNumberValidator,支持Integer,Long,Float,Double,Byte,Short,BigInteger,BigDecimal等Number类型的通用验证器,基本的原理就是尝试用StringToNumberConverter来对字符串进行解析如果解析成功并数值范围符合要求就返回OK,否则返回ERROR,代码下如。
StringToNumberValidator.java
用法示例(以Float为例):
上面的代码同样可以使用create静态方法创建StringToNumberValidator对象,Lambda表达式实现的代码更简洁。
如下图,当输入为空字符串时,提示错误信息
如下图,当输入数值超过允许范围时,提示错误信息
但是在项目实际使用中发现这些验证器有缺点:
空字符串被视为合法,可以通过验证,而一般情况下,我们会视空字符串为无效输入
数值解析错误时返回的信息为英文而且太详细,用户体验不好。其实如果用户输入了非数字导致解析错误时只要提示输入无效就可以了,没必要太详细,更不能是英文。
如上图每种数据类型验证都对应一个不同的类,这在项目中可能会增加不必要的代码复杂度,如果统一成一个类使用更加方便,也减少写代码的工作量。
针对这些问题,参考AbstractStringToNumberValidator的源码,我构建了一个通用型的数值验证器类StringToNumberValidator,支持Integer,Long,Float,Double,Byte,Short,BigInteger,BigDecimal等Number类型的通用验证器,基本的原理就是尝试用StringToNumberConverter来对字符串进行解析如果解析成功并数值范围符合要求就返回OK,否则返回ERROR,代码下如。
StringToNumberValidator.java
package testwb; import java.math.BigDecimal; import java.math.BigInteger; import org.eclipse.core.databinding.conversion.StringToNumberConverter; import org.eclipse.core.databinding.validation.IValidator; import org.eclipse.core.databinding.validation.ValidationStatus; import org.eclipse.core.internal.databinding.validation.NumberFormatConverter; import org.eclipse.core.runtime.IStatus; /** * 通用型数值验证器<br> * 支持Integer,Long,Float,Double,Byte,Short,BigInteger,BigDecimal等Number类型<br> * 可用于beforeSetValidator,afterGetValidator和validateAfterConvert的数值验证器<br> * 自动判断输入数据类型,如为String则调用 {@link #converter}进行类型转换<br> * 空字符串被视为无效输入<br> * 可根据需要重写 {@link #isInRange(Number)}实现数值范围验证<br> * @author guyadong * */ public class StringToNumberValidator implements IValidator { /** * 数据类型转换器 */ private final StringToNumberConverter converter; /** * 根据目标数据类型构造对象 * @param toType 目标数据类型 */ public StringToNumberValidator(Class<? extends Number> toType){ this.converter=createConverter(toType); } /** * 根据目标数据类型创建对应的{@link StringToNumberConverter}对象 * @param toType * @return */ private static final StringToNumberConverter createConverter(Class<? extends Number> toType) { if (Integer.class.equals(toType) || Integer.TYPE.equals(toType)) { return StringToNumberConverter.toInteger(false); } else if (Long.class.equals(toType) || Long.TYPE.equals(toType)) { return StringToNumberConverter.toLong(false); } else if (Float.class.equals(toType) || Float.TYPE.equals(toType)) { return StringToNumberConverter.toFloat(false); } else if (Double.class.equals(toType) || Double.TYPE.equals(toType)) { return StringToNumberConverter.toDouble(false); } else if (Byte.class.equals(toType) || Byte.TYPE.equals(toType)) { return StringToNumberConverter.toByte(false); } else if (Short.class.equals(toType) || Short.TYPE.equals(toType)) { return StringToNumberConverter.toShort(false); }else if (BigInteger.class.equals(toType)) { return StringToNumberConverter.toBigInteger(); }else if (BigDecimal.class.equals(toType)) { return StringToNumberConverter.toBigDecimal(); } throw new IllegalArgumentException("invalid type"); } @Override public final IStatus validate(Object value) { boolean ok=false; try{ // 输入值value为String时,调用converter进行数据类型转换, // 否则直接对value进行强制类型转换 Number number = value instanceof String ?(Number) converter.convert(value) :(Number) value; // 为null时抛出异常,空字符串视为无效输入 if (null==number) throw new IllegalArgumentException("result is null"); if (isInRange(number)) { // 验证通过,返回状态为OK ok=true; return ValidationStatus.ok(); }else // 数值超范围,返回验证状态为ERROR return ValidationStatus.error(getOutOfRangeMessage()); }catch(Exception e){ // 捕获所有Exception(converter转换异常或number为null),返回验证状态为ERROR return ValidationStatus.error(getInvalidNumberMessage(e)); }finally{ result(ok); } } /** * 验证数值有效范围<br> * 被 {@link #validate(Object)}调用 * @param number * @return */ protected boolean isInRange(Number number) { return true;} /** * 方法结束时调用 * @param ok 验证结果,为true时验证通过 */ protected void result(boolean ok){} /** * {@link #isInRange(Number)}为false时,返回错误信息 * @return */ protected String getOutOfRangeMessage(){ return "数值不在允许的范围"; } /** * 数字无效时返回错误信息(converter返回错误或为null) * @param e 异常中包含详细错误信息 * @return */ protected String getInvalidNumberMessage(Exception e){ //return e.getMessage();//使用这一行可以返回详细错误信息 return "无效数字"; } public NumberFormatConverter getConverter() { return converter; } /** * 适合Lambda表达式创建实例的静态方法(需要java1.8支持)<br> * 除toType为null抛出异常外,其他参数为null则调用父类方法 * @param toType 目标数据类型 * @param inRange 数据范围验证 * @param result 数据结果响应 * @param outOfRangeMessage 数值超范围错误信息 * @param invalidNumberMessage 无效数字错误信息 * @return */ public static StringToNumberValidator create(Class<? extends Number> toType, Function<Number, Boolean> inRange, Consumer<Boolean> result, Supplier<String> outOfRangeMessage, Function<Exception, String> invalidNumberMessage) { return new StringToNumberValidator(toType) { @Override protected boolean isInRange(Number number) { return null == inRange ? super.isInRange(number) : inRange.apply(number); } @Override protected void result(boolean ok) { if(null!=result) result.accept(ok); } @Override protected String getOutOfRangeMessage() { return null==outOfRangeMessage?super.getOutOfRangeMessage():outOfRangeMessage.get(); } @Override protected String getInvalidNumberMessage(Exception e) { return null==invalidNumberMessage?super.getInvalidNumberMessage(e):invalidNumberMessage.apply(e); } }; } /** * @param toType * @param inRange * @param result * @param outOfRangeMessage * @param invalidNumberMessage * @return * @see #create(Class, Function, Consumer, Supplier, Function) */ public static StringToNumberValidator create(Class<? extends Number> toType, Function<Number, Boolean> inRange, Consumer<Boolean> result, String outOfRangeMessage,String invalidNumberMessage) { return create(toType, inRange, result, null==outOfRangeMessage?null:()->outOfRangeMessage, null==invalidNumberMessage?null:(e)->invalidNumberMessage); } /** * @param toType * @param inRange * @return * @see #create(Class, Function, Consumer, Supplier, Function) */ public static StringToNumberValidator create(Class<? extends Number> toType, Function<Number, Boolean> inRange) { return create(toType, inRange, null, (Supplier<String>)null, (Function<Exception, String>)null); } }
用法示例(以Float为例):
updateStrategyToModel.setAfterGetValidator(new StringToNumberValidator(Float.class){ // 重写isInRange方法实现自定义数值范围验证 @Override protected boolean isInRange(Number number) { // 输入必须小于100 return number.floatValue()<100; } // 重写getOutOfRangeMessage方法,返回数据范围要求 @Override protected String getOutOfRangeMessage() { return "输入必须<100"; }}); // 重写result方法实现其他控制 @Override protected void result(boolean ok) { // 数据验证无效时 disable OK按钮 getButton(IDialogConstants.OK_ID).setEnabled(ok); }});
上面的代码同样可以使用create静态方法创建StringToNumberValidator对象,Lambda表达式实现的代码更简洁。
updateStrategy.setAfterGetValidator(StringToNumberValidator.create(Float.class, (number)->number.floatValue()<100, (ok)->{getButton(IDialogConstants.OK_ID).setEnabled(ok);}, "输入必须<100",null));
如下图,当输入为空字符串时,提示错误信息
如下图,当输入数值超过允许范围时,提示错误信息
相关文章推荐
- jface databinding:输入无效数值时强制恢复初始值-updateModelToTarget
- jface databinding(数据挷定)中的数据转换(IConverter)和数据验证(IValidator )
- jface databinding:UpdateValueStrategy(数值更新策略)类详解
- eclipse超cool新特性--JFace Data Binding
- Using .NET Databinding to Display Ink from a Database
- Databinding to user Interface controls
- (转)ASP.NET一个页面多个Button按钮事件避免数据验证控件RequiredFieldValidator冲突方法
- 用ObjectDataProvider绑定方法,用IValueConverter实现数据类型转换,重载ValidationRule实现数据验证,BindsDirectlyToSource等
- 在oracel表中的一个datatime字段上建了索引,然后使用to_char函数进行检索,能否使用该索引?
- How to populate the datagrid on background thread with data binding by using Visual C#
- Performing Data Access->Binding to Objects
- 在 Eclipse Workbench 之外使用 Eclipse GUI,第 1 部分: 单独使用 JFace 和 SWT构建一个简单的文件资源管理器应用程序
- Effective STL:Item 16: Know how to pass vector and string data to
- DataTime.ToString 的方法。
- eclipse超cool新特性--JFace Data Binding
- c语言int to string一个比较经典得算法
- 一个友好的.改善的 Object.prototype.toString的实现
- eclipse超cool新特性--JFace Data Binding
- 一个友好的.改善的 Object.prototype.toString的实现
- Binding a Scalar Array to a Data Web Control