Объединение сопоставленных свойств с индексированными свойствами в Struts - PullRequest
1 голос
/ 15 сентября 2010

Я пытаюсь получить динамическую форму и, в зависимости от типа атрибута, я хотел бы отобразить другой стиль ввода (текстовое поле, переключатели, раскрывающийся список, контрольный список, ...).Чтобы получить динамическую форму, я настроил ActionForm с картой.

Map<String, Object> values;
public void setValue(String key, Object value);
public Object getValue(String key);

Моя проблема возникает, когда я пытаюсь настроить контрольный список или мультибокс.ActionForm передает только одно значение, хотя я ожидал, что String [] будет сопоставлен с аргументом Object.

Любая идея о том, как я могу решить эту проблему?JSP:

<input type=checkbox name="value(foo)" />

1 Ответ

1 голос
/ 18 сентября 2010

Я посмотрел на эту проблему и узнал, что происходит.Проблема не в Struts, а в BeanUtils (который Struts использует для заполнения формы параметрами запроса).

Мне удалось продублировать это путем извлечения (только для теста) фрагмента кодаиз фреймворка:

public class MyForm {
  // assume this is your Struts ActionForm
  public void setValue(String key, Object val) {
    System.out.println(key + "=" + val);
  }
}

public class Test {
  public static void main(String[] args) 
      throws IllegalAccessException, InvocationTargetException {
    MyForm s = new MyForm();
    Map<String, Object> properties = new HashMap<String, Object>();
    // Your request should be like yourActionUrl?value(foo)=1&value(foo)=2&value(foo)=3 
    // and Struts calls bean utils with something like:
    properties.put("value(foo)", new String[] {"1", "2", "3"});
    BeanUtils.populate(s, properties);
  }
}

Когда вы запускаете это, вы печатаете только одно значение (так же, как вы его удалили):

foo=1

Дело в том, что BeanUtils считает это сопоставленным свойствомрассматривает это как таковое, переходя к скалярному значению для ключа.Поскольку ваше значение является массивом, оно просто использует первый элемент:

...
} else if (value instanceof String[]) {
  newValue = getConvertUtils().convert(((String[]) value)[0], type);
...

Что вы можете сделать, это изменить JSP и ActionForm для обработки списка значений отдельно.Пример изменен:

public class MyForm {
  private Map<String, Object> map = new HashMap<String, Object>();

  public void setValue(String key, Object val) {
    map.put(key, val);
  }

  public void setPlainValue(String[] values) {
    // this is correctly called; now delegate to what you really wanted 
    setValue("foo", values);
  }
}

public class Test {
  public static void main(String[] args) 
      throws IllegalAccessException, InvocationTargetException {
    MyForm s = new MyForm();
    Map<String, Object> properties = new HashMap<String, Object>();
    // Notice the change to your URL..
    // yourActionUrl?plainValue=1&plainValue=2&plainValue=3
    properties.put("plainValue", new String[] {"1", "2", "3"});
    BeanUtils.populate(s, properties);
  }
}

Вышеприведенный означает, что вы используете

<input type="..." name="value(foo)" ... />

для всех отдельных элементов в вашем JSP, в то время как для ваших флажков (в целом, расширяя его до многозначных элементов) выиспользуйте

<input type="checkbox" name="plainValue" ... />

, и вы делегируете карту один раз в вашей ActionForm.

...