Связывание является наиболее обсуждаемой проблемой в сообществе GWT. У каждого свое решение и разные материалы в поддержку своих аргументов. Когда мы говорим «связывание», мы говорим «связывание на основе POJO». Я из школы мысли, которая любила видеть, что клиентский интерфейс полностью отделен от бизнес-уровня, и передача Business Objects на уровень пользовательского интерфейса разрушит концепцию разделения. Мы можем реализовать концепцию отделения уровня пользовательского интерфейса от бизнес-уровня, если передадим данные на основе карты из бизнес-уровня. Карта — это система пар ключ / значение, в которой мы рассматриваем «ключ» как имя свойства домена, а значением будет «Объект», связанный с этим свойством. В этой статье я объясню механизм создания системы привязки для виджета пользовательского интерфейса с данными на основе карты.Мы создали служебный класс Mab2BeanConvertor, который преобразует POJO в HashMap и наоборот. Этот служебный класс возьмет на себя бремя преобразования HashMap в POJO и POJO в HashMap.
Теперь я объясню, как мы достигли связывания с GWT. Мы придерживаемся стиля JGoodies концепции ValueModel хранения данных и системы Binder, которая связывает ValueModel с компонентом пользовательского интерфейса.
Эта система имеет три (3) числа классов, т.е.
-
(i) GWTMapValueModel (ii) GWTBinding (iii) GWTWidgetDomainSynchronizer
- GWTMapValueModel — это модель значений, которая содержит значение для виджета, связанное с некоторым свойством компонента, т. Е. Ключом Map.
- GWTBinding является основным действующим лицом этой системы, которая будет привязывать виджет к ключу карты.
- GWTWidgetDomainSynchronizer будет служить моделью для синхронизации виджета и карты.
Наша
GWTMapValueModel показана ниже
import java.util.Map; /** * @author Anees * */ public class GWTMapValueModel { private String key; private Map map; private GWTWidgetDomainSynchronizer synchronizer ; public GWTMapValueModel(String key, Map map){ this.key = key; this.map = map; } public void setValue(final Object newValue){ Object oldValue = map.get(key); map.put(key, newValue); firePropertyChange(oldValue, newValue); } public Object getValue(){ return map.get(key); } public Map getMap(){ return map; } protected String getKey(){ return key; } public void createBindableSynch(GWTWidgetDomainSynchronizer synchronizer){ this.synchronizer = synchronizer; } /** * * @param oldValue * @param newValue */ private void firePropertyChange(Object oldValue, Object newValue){ synchronizer.processGWTMapValueModelChange(oldValue, newValue); } }
GWTBinding класс показан ниже с полным исходным кодом для вашего руководства:
package com.eagle.coders.core.web.gwt.client.ui.bindings; import com.eagle.coders.core.web.gwt.client.ui.form.widgets.RadioButtonWidget; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.PasswordTextBox; import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.datepicker.client.DateBox; /** * @author Anees * */ public class GWTBinding { private GWTMapValueModel valueModel; private static GWTWidgetDomainSynchronizer sync ; public static void bindTextBox(TextBox textBox, GWTMapValueModel valueModel, String caseType){ sync = new GWTWidgetDomainSynchronizer(valueModel, textBox); textBox.addValueChangeHandler(new BindingValueChangeHandler(valueModel, caseType)); } public static void bindPasswordBox(PasswordTextBox passwordBox, GWTMapValueModel valueModel){ sync = new GWTWidgetDomainSynchronizer(valueModel, passwordBox); passwordBox.addValueChangeHandler(new BindingValueChangeHandler(valueModel, null)); } public static void bindRadioButton(RadioButtonWidget radioButton, GWTMapValueModel valueModel){ sync = new GWTWidgetDomainSynchronizer(valueModel, radioButton); radioButton.addValueChangeHandler(new BindingValueChangeHandler(valueModel, null)); } public static void bindCheckBox(final CheckBox checkBox, GWTMapValueModel valueModel){ sync = new GWTWidgetDomainSynchronizer(valueModel, checkBox); checkBox.addValueChangeHandler(new BindingValueChangeHandler(valueModel, null)); } public static void bindComboBox(final ListBox listBox, GWTMapValueModel valueModel){ sync = new GWTWidgetDomainSynchronizer(valueModel, listBox); listBox.addChangeHandler(new BindingChangeHandler(valueModel)); } public static void bindTextAreaWidget(final TextArea textArea, GWTMapValueModel valueModel){ sync = new GWTWidgetDomainSynchronizer(valueModel, textArea); textArea.addValueChangeHandler(new BindingValueChangeHandler(valueModel, null)); } public static void bindDateBoxWidget(final DateBox dateBox, GWTMapValueModel valueModel){ sync = new GWTWidgetDomainSynchronizer(valueModel, dateBox); dateBox.addValueChangeHandler(new BindingValueChangeHandler(valueModel, null)); } /** * @help for ListBox Binding * @author Anees * * @param */ private static class BindingChangeHandler implements ChangeHandler{ private T valueModel; public BindingChangeHandler(T valueModel){ this.valueModel = valueModel; } @Override public void onChange(ChangeEvent event) { if(event.getSource() instanceof ListBox){ int index = ((ListBox)event.getSource()).getSelectedIndex(); String value = ((ListBox)event.getSource()).getItemText(index); processListBox(value, valueModel); } } } /** * * @author Anees * * @param */ private static class BindingValueChangeHandler implements ValueChangeHandler{ private T valueModel; private String caseType; public BindingValueChangeHandler(T valueModel, String caseType){ this.valueModel = valueModel; this.caseType = caseType; } @Override public void onValueChange(ValueChangeEvent event) { if(event.getSource() instanceof TextBox && !(event.getSource() instanceof PasswordTextBox)) sync.processTextBox(event.getValue(), caseType ,valueModel); else if(event.getSource() instanceof PasswordTextBox) sync.processPasswordTextBox(event.getValue(), valueModel); else if(event.getSource() instanceof RadioButtonWidget) sync.processRadioButton(event.getValue(),(RadioButtonWidget)event.getSource() ,valueModel); else if(event.getSource() instanceof CheckBox) sync.processCheckBox(event.getValue(), valueModel); else if(event.getSource() instanceof DateBox) sync.processDateBox(event.getValue(), valueModel); } } }
Теперь класс модератора, который будет синхронизировать состояние HashMap и Widgets, т.е. GWTWidgetDomainSynchronizer :
package com.eagle.coders.core.web.gwt.client.ui.bindings; import java.util.List; import com.eagle.coders.core.web.gwt.client.ui.form.widgets.RadioButtonWidget; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.PasswordTextBox; import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.Widget; /** * @author Anees * */ public class GWTWidgetDomainSynchronizer { private String propertyName; private GWTMapValueModel valueModel; private Widget widget; public GWTWidgetDomainSynchronizer(GWTMapValueModel valueModel, Widget widget){ this.propertyName = valueModel.getKey(); this.valueModel = valueModel; this.widget = widget; this.valueModel.createBindableSynch(this); synchOnBinding(); } private void synchOnBinding(){ processGWTMapValueModelChange(null, valueModel.getValue()); } /** * * @param valueModel * @param property */ public void processGWTMapValueModelChange(Object oldValue, Object newValue){ if(!(widget instanceof PasswordTextBox) && widget instanceof TextBox){ ((TextBox)widget).setText(newValue.toString()); }else if(!(widget instanceof RadioButtonWidget)&& widget instanceof CheckBox){ CheckBox checkBox = (CheckBox)widget; if(!newValue.equals(checkBox.getValue())){ checkBox.setValue(Boolean.valueOf(newValue.toString())); } }else if(widget instanceof ListBox){ // TODO: as listbox can have multiple selected data if(newValue instanceof List){ } }else if(widget instanceof RadioButtonWidget){ RadioButtonWidget radioButton =(RadioButtonWidget)widget; if(radioButton.getChoice().equals(newValue)){ radioButton.setValue(true); }else radioButton.setValue(false); }else if(widget instanceof TextArea){ ((TextArea)widget).setText(newValue.toString()); }else if(widget instanceof PasswordTextBox){ ((PasswordTextBox)widget).setText(newValue.toString()); } } /** * * @param * @param value * @param valueModel */ public void processTextBox(Object value,String caseType ,T valueModel ){ String cValue = ""; if(null != caseType){ if(caseType.equals("upper")){ cValue = value.toString().toUpperCase(); }else if (caseType.equals("lower")){ cValue = value.toString().toLowerCase(); }else if (caseType.equals("mixed")){ cValue = value.toString(); } valueModel.setValue(cValue); }else { valueModel.setValue(value); } } /** * * @param * @param value * @param valueModel */ public void processPasswordTextBox(Object value, T valueModel ){ valueModel.setValue(value); } /** * * @param * @param value * @param valueModel */ public void processRadioButton(Object value, RadioButtonWidget radioButton ,T valueModel ){ valueModel.setValue(radioButton.getChoice()); } /** * * @param * @param value * @param valueModel */ public void processCheckBox(Object value, T valueModel ){ valueModel.setValue(value); } /** * * @param * @param value * @param valueModel */ public void processListBox(Object value, T valueModel ){ valueModel.setValue(value); } /** * * @param * @param value * @param valueModel */ public void processDateBox(Object value, T valueModel ){ valueModel.setValue(value); } }
Мы протестировали со всеми видами виджетов, предоставляемых GWT1.6.x +. У этого подхода есть один недостаток: мы можем использовать GWT1.6 + совместимые предоставленные виджеты, так как они основаны на новой EventModel, то есть на Handler, а не на Listeners.
Map map = new HashMap(); map.put("firstName",""); GWTMapValueModel valueModel = new GWTMapValueModel("firstName", map); TextBox firstNameWidget = new TextBox(); GWTBinding.bindTextBox(firstNameWidget, valueModel);Надеемся, что этот подход решит многие проблемы связывания в Google Web Toolkit.