Spring MVC форма: тег опций не подключается к моим объектам Id? - PullRequest
4 голосов
/ 18 декабря 2009

Я пытаюсь отобразить поле коллекции объектов моей команды в списке. Внутри указанной коллекции находится поле, идентификатор и имя. Я хочу использовать идентификатор в качестве значения параметра HTML и имя в качестве текста параметра. Смотрите код ниже;

<form:select id="customCollection" path="customCollection" size="10">
    <form:options items="${command.customCollection}" itemValue="id" itemLabel="name"/>
</form:select>

Имя печатается нормально, но значение остается пустым. Вот вывод HTML;

<option selected="selected" value="">name-value</option>


Сначала я предполагал, что мои данные неверны, но после размещения на моей странице следующего кода:

<c:forEach items="${command.customCollection}" var="c">
    ${c.id} : ${c.name} <br>
</c:forEach>

Идентификатор и имя правильно распечатаны. Таким образом, мои данные правильно доставляются на мой взгляд. Это заставляет меня предположить, что я либо использую форму: параметры неправильно, либо пытаюсь исправить ошибку в форме: параметры.

Может кто-нибудь помочь мне здесь?

EDIT:
Благодаря помощи BacMan и delfuego я смог сузить эту проблему до своего переплета.

Ранее я присваивал значение в своем элементе имени строки, вот мой начальный переплет;

binder.registerCustomEditor(Collection.class, "customCollection",
        new CustomCollectionEditor(Collection.class) {

    @Override
    protected Object convertElement(Object element) {
        String name = null;

        if (element instanceof String) {
            name = (String) element;
        }
        return name != null ? dao.findCustomByName(name) : null;
    }
});

Когда я удаляю этот код из моего метода initBinder, значение строки правильно вставляется в форму, но мне нужен customEditor для преобразования указанного значения в объект базы данных.

Так что это моя новая попытка связующего;

binder.registerCustomEditor(Collection.class, "customCollection",
        new CustomCollectionEditor(Collection.class) {

    @Override
    protected Object convertElement(Object element) {
        Integer id = null;

        if (element instanceof Integer) {
            id = (Integer) element;
        }
        return id != null ? dao.find(Custom.class, id) : null;
    }
});

Однако это приводит к тому же поведению, что и предыдущий переплет, и делает значение не отображаемым. Есть идеи о том, что я здесь делаю неправильно?

РЕДАКТИРОВАТЬ 2:
Как я уже упоминал выше, если я закомментирую свой пользовательский механизм связывания, тогда объект Custom действительно правильно загружает его идентификатор и имя для части представления формы, но затем никогда не связывается с родительским объектом, когда я пытаюсь его сохранить. Так что я действительно думаю, что проблема с моим переплетом.

Я разместил отладочные операторы внутри моего метода convertElement. Все выглядит так, как будто все должно работать, дао правильно извлекает объекты из базы данных. Единственное поведение, которое вызывает у меня подозрение, это то, что метод convertElement вызывается дважды для каждого элемента Custom.

Ответы [ 3 ]

4 голосов
/ 08 января 2010

Это одна из тех проблем, когда я понимаю, что происходит, я не понимаю, как это вообще сработало.

Я использовал CustomCollectionEditor совершенно неправильно. Согласно сообщению Мартена Дейна в этой теме,

Как я уже говорил в другом потоке, CustomCollectionEditor должен создавать Коллекции (List, Set,?). Таким образом, он будет заполнять желаемую коллекцию элементами нужного типа.

Однако он не предназначен для преобразования отдельных элементов в значение. Он предназначен для работы с коллекциями, а не с одним экземпляром роли. Вы хотите, чтобы 1 PropertyEditor выполнил за вас 2 задания.

Таким образом, он создавал уникальную коллекцию для каждого элемента, который в конечном итоге обнулялся в коде Spring при попытке сгенерировать HTML.

Это то, что я закончил,

binder.registerCustomEditor(Custom.class,
        new PropertyEditorSupport() {

            @Override
            public void setAsText(String text) {
                Custom custom = dao.find(Custom.class,
                        Integer.parseInt(text));
                setValue(Custom);
            }
        });

Понятия не имею, почему мой предыдущий CustomCollectionEditor когда-либо работал с именами в качестве значений.

2 голосов
/ 18 декабря 2009

Я попытаюсь предоставить рабочий образец, который может помочь отладить возникшую проблему:

<form:form commandName="client" method="post" action="${edit_client}">
    <form:select path="country">
        <form:options items="${requestScope.countries}" itemValue="id" itemLabel="name"/>
    </form:select>
</form:form>

Вот мой класс Country, который является переменной-членом в моем объекте команды.

public class Country {

    private Integer id;
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(final Object anObject) {
        if (anObject == null) {
            return false;
        } else if (this == anObject) {
            return true;
        } else if (anObject instanceof Country) {
            final Country aCountry = (Country) anObject;
            Integer aCountryId = aCountry.getId();
            if (aCountryId != null) {
                return aCountry.getId().equals(id);
            }
        }
        return false;
    }

    @Override
    public int hashCode() {
        return id;
    }
}

Я использую пользовательский редактор свойств в методе initBinder моего контроллера. Я опущу реализацию, потому что она использует универсальную реализацию.

binder.registerCustomEditor(Country.class, "country", editorServiceFactory.getPropertyEditor(Country.class, CustomPropertyEditor.class));

Вот справочные данные (этот метод вызывается из метода referenceData Контроллера):

public Map<String, List<?>> getDemographicReferenceData() {
    Map<String, List<?>> referenceData = new HashMap<String, List<?>>();
    referenceData.put("countries", countryDAO.findAll());
    return referenceData;
}

Я использую Spring 2.5

1 голос
/ 18 декабря 2009

Одной вещью, которая мне не кажется правильной, является то, что command.customCollection используется как для заполнения возможных значений для ввода выбора вашей формы И для привязки к конечным значениям, выбранным пользователем с этим выбором ввода , Это не имеет смысла, по крайней мере для меня ... например, если бы у меня была форма выбора для выбора штата США для адреса, я бы заполнил этот выбор набором допустимых состояний, но я бы связал значение состояния select до состояния one , которое в конечном итоге выбрал пользователь.

Попробуйте: создайте объект customCollection вне контекста объекта command. Другими словами, сейчас ваш customCollection является собственностью вашего command объекта; вместо этого вытащите этот объект из объекта command и сделайте его собственным атрибутом страницы. В модели Spring MVC такие вещи, которые будут использоваться в качестве источников данных для раскрывающихся списков, и тому подобное, обычно называются справочными данными; в SimpleFormController эти данные заполняются методом с соответствующим именем SipleFormController#referenceData. Это разделяет две разные концепции - возможные значения для выбора в реальном времени в опорных данных и окончательное значение (я), выбранное пользователем, в реальном времени в объекте команды, связанном с формой и / или входом выбора.

Итак, предполагая, что это в SimpleFormController, попробуйте добавить (или соответствующим образом изменить) referenceData следующим образом:

@Override
protected Map<?, ?> referenceData(HttpServletRequest request, Object command, Errors errors) throws Exception {
  CustomCollection customCollection = new CustomCollection();
  // ...populate your custom collection
  request.setAttribute("customCollection", customCollection);
  return super.referenceData(request, command, errors);
}

А затем измените на:

<form:select id="customCollection" path="command" size="10">
  <form:options items="${customCollection}" itemValue="id" itemLabel="name"/>
</form:select>

Имеет ли это смысл?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...