Связывание является наиболее обсуждаемой проблемой в сообществе 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.