把ExtJS的组件包装成 JSF 组件(2)

(续)Ext 的 DateField 输入日期很方便,因此决定把它做成 JSF 组件来使用。

写一个 JSF 组件比较麻烦,至少要写Component 类和一个 Tag 类,这种情况下,Component 负责 render  工作。
但通常我们都会写多一个 Renderer,负责 encode 、decode 及 转换客户端提交的数值。
btw,Renderer 其实是通过 component 来调用的,因此,Renderer 中有什么方法,都可在UIComponent 中找到。

这个组件叫 ExtInputDate,Component 代码:

java 代码
  1. public class ExtInputDate extends ExtInput {   
  2.        
  3.     public final static String COMPONENT_TYPE = "example.ExtInputDate";   
  4.     public final static String COMPONENT_FAMILY = "example.ExtInputDate";   
  5.        
  6.     public final static String DEFAULT_FORMAT = "yyyy-MM-dd";   
  7.        
  8.     private String format;   
  9.        
  10.     private Integer width;   
  11.        
  12.     private Boolean readonly;   
  13.        
  14.     private Boolean disabled;   
  15.        
  16.     private String styleClass;   
  17.        
  18.     @Override  
  19.     public String getFamily() {   
  20.         return COMPONENT_FAMILY;   
  21.     }   
  22.   
  23.     @Override  
  24.     public String getEndingScript() {   
  25.         // 输出 JavaScript 代码,略。注意转换 Java 的日期格式为 Ext 的日期格式   
  26.         // ...   
  27.     }   
  28.   
  29.     public String getFormat() {   
  30.         if (format == null) {   
  31.             ValueExpression ve = getValueExpression("format");   
  32.             if (ve != null) {   
  33.                 format = (String) FacesUtils.getExpressionValue(ve, getFacesContext().getELContext());   
  34.             }   
  35.                
  36.             if (format == null) {   
  37.                 format = DEFAULT_FORMAT;   
  38.             }   
  39.         }   
  40.            
  41.         return format;   
  42.     }   
  43.   
  44.     public void setFormat(String format) {   
  45.         this.format = format;   
  46.     }   
  47.   
  48.     // 其他 getter / setter, 略   
  49.     // TODO: ...   
  50.   
  51.     @Override  
  52.     public void restoreState(FacesContext context, Object state) {   
  53.         Object values[] = (Object[]) state;   
  54.         super.restoreState(context, values[0]);   
  55.         format = (String)values[1];   
  56.         width = (Integer)values[2];   
  57.         readonly = (Boolean)values[3];   
  58.         disabled = (Boolean)values[4];   
  59.         styleClass = (String)values[5];   
  60.     }   
  61.   
  62.     @Override  
  63.     public Object saveState(FacesContext context) {   
  64.         Object values[] = new Object[6];   
  65.         values[0] = super.saveState(context);   
  66.         values[1] = format;   
  67.         values[2] = width;   
  68.         values[3] = readonly;   
  69.         values[4] = disabled;   
  70.         values[5] = styleClass;   
  71.   
  72.         return ((Object) (values));   
  73.     }   
  74.   
  75. }   

Component 必须有 restoreState 和 saveState 方法,而且在这两个方法里面必须调用 super 的同名方法。
这一点,感觉很不爽...


UIInput 类的组件,有个变量叫 submittedValue,这个是客户端提交的值,
在 Apply Request Value 阶段 decode 的时候被设置,可以转换为String 类型;
另外有个 value 变量,存放 value 表达式的值。
那么,在 render 的时候,显示哪个值呢?
一般的做法是,如果 submittedValue 不为null,显示 submittedValue;否则显示 value。

Renderer类:

java 代码
  1. public class ExtInputDateRenderer extends Renderer {   
  2.   
  3.     public final static String RENDERER_TYPE = "example.ExtInputDateRenderer";   
  4.   
  5.     @Override  
  6.     public void encodeBegin(FacesContext context, UIComponent component)   
  7.             throws IOException {   
  8.   
  9.         if (component.isRendered()) {   
  10.             ResponseWriter writer = context.getResponseWriter();   
  11.             String clientId = component.getClientId(context);   
  12.             writer.startElement("div", component);   
  13.             writer.writeAttribute("id", clientId, "clientId");   
  14.             String styleClass = (String) component.getAttributes().get("styleClass");   
  15.                
  16.             if (StringUtils.isNotEmpty(styleClass)) {   
  17.                 writer.writeAttribute("class", styleClass, null);   
  18.             }   
  19.             writer.endElement("div");   
  20.         }   
  21.     }   
  22.   
  23.   
  24.     @Override  
  25.     public void decode(FacesContext context, UIComponent component) {   
  26.         if (component.isRendered() && component instanceof ExtInputDate) {   
  27.             Map paramMap = context.getExternalContext()   
  28.                     .getRequestParameterMap();   
  29.             String clientId = component.getClientId(context);   
  30.   
  31.             // 允许 readonly   
  32.             if (RendererUtils.isDisabled(component))   
  33.                 return;   
  34.   
  35.             if (paramMap.containsKey(clientId)) {   
  36.                 ((EditableValueHolder) component).setSubmittedValue(paramMap.get(clientId));   
  37.             }   
  38.   
  39.         } else {   
  40.             throw new IllegalArgumentException("Unsupported component class "  
  41.                     + component.getClass().getName());   
  42.         }   
  43.     }   
  44.   
  45.     @SuppressWarnings("unchecked")   
  46.     public Object getConvertedValue(FacesContext context,   
  47.             UIComponent component, Object submittedValue)   
  48.             throws ConverterException {   
  49.   
  50.         ValueExpression valueExpression = component.getValueExpression("value");   
  51.            
  52.         if (valueExpression == null)   
  53.             return null;   
  54.   
  55.         Class converterType = valueExpression.getType(context.getELContext());   
  56.   
  57.         if (converterType == String.class) {   
  58.                
  59.             return submittedValue;   
  60.                
  61.         } else if (converterType == Date.class  
  62.                 || converterType == java.sql.Date.class) {   
  63.             String s = (String) submittedValue;   
  64.             if (StringUtils.isEmpty(s))   
  65.                 return null;   
  66.                
  67.             ExtInputDate inputDate = (ExtInputDate) component;   
  68.             SimpleDateFormat df = new SimpleDateFormat(inputDate.getFormat());   
  69.             try {   
  70.                 return df.parse(s);   
  71.             } catch (ParseException e) {   
  72.                 throw new ConverterException(e);   
  73.             }   
  74.         } else {   
  75.             throw new ConverterException();   
  76.   
  77.         }   
  78.     }   
  79. }   

这个组件里面,decode 所做的事情只是设置 submittdValue,
getConvertedValue() 函数把客户端提交的值,转换为相应的类型。
这个函数在 Update Model Value阶段由 Component 调用,
更新 managed-bean 的值。
一般来说,需要考虑是否有 converter。
不过这个组件中,自己负责日期转换的工作,因此不需要 converter。
此外,这个组件只支持 String, java.util.Date, java.sql.Date 三种类型的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值