Я нашел решение, но оно работает только потому, что мое приложение больше не является стандартным приложением Roo.В любом случае, я объясню свое решение, может быть, кто-то найдет способ адаптировать его для стандартных приложений Roo.
Идея состоит в том, чтобы добавить пустой выбор в раскрывающемся списке, когда атрибут required
равен false
.Основная проблема заключается в том, что расширение dijti / dojo не будет работать правильно, если в раскрывающемся списке есть одна опция без value
.Поэтому я решил дать им, например, value
"null"
(<option value="null></option>
).На стороне сервера нужно немного изменить преобразователь, который преобразует идентификатор базы данных (то есть нормальное значение) в сущность (путем загрузки его из базы данных), чтобы он преобразовывал строку "null"
в null
вместосущность.
Но это проблема с пружиной Ру.Roo использует org.springframework.core.convert.support.IdToEntityConverter
, который автоматически регистрируется (не документировано https://jira.springsource.org/browse/SPR-7461)) и будет пытаться преобразовать каждый объект в сущность, если класс сущности используется как метод статического поиска. Я не нашел способа изменить его поведение.
Но лично мне очень повезло, потому что некоторое время назад я изменил свое приложение, так как оно не имеет этого статического искателя, поэтому у меня есть свой собственный общий преобразователь Id в сущность, который легко изменить.String to Entity. Если String имеет значение «null», он возвращает ноль, иначе он преобразует String в число и загружает Entity по этому номеру / id.
Для представления он показывает, что нужно расширитьфайл select.tagx
.
Файл select.tagx
содержит 12 различных способов заполнения поля выбора.
- 6 из них предназначены для множественного выбора, поэтому они могут оставаться такими же, как ониis.
- 2, если не несколько из них предназначены для отключенной привязки формы, необходимо добавить этот блок сразу после тега select
, строка 75, 130,
<c:if test="${not required}">
<option value="null"></option>
</c:if>
- остальные 4 немного сложнее
...
<form:select id="_${sec_field}_id" items="${items}" path="${sec_field}" disabled="${disabled}" />
...
<form:select id="_${sec_field}_id" items="${items}" path="${sec_field}" disabled="${disabled}" itemLabel="${sec_itemLabel}"/>
...
<form:select id="_${sec_field}_id" items="${items}" path="${sec_field}" disabled="${disabled}" itemValue="${fn:escapeXml(itemValue)}" />
...
<form:select id="_${sec_field}_id" items="${items}" path="${sec_field}" disabled="${disabled}" itemValue="${fn:escapeXml(itemValue)}" itemLabel="${sec_itemLabel}"/>
Им нужно заменить полный тег на( Я продемонстрирую это только для последних 4, но остальные похожи, за исключением того, что нужно удалить параметр itemVlaue и / или itemLabel )
<form:select id="_${sec_field}_id" path="${sec_field}" disabled="${disabled}">
<c:if test="${not required}">
<option value="null"></option>
</c:if>
<form:options items="${items}" itemValue="${fn:escapeXml(itemValue)}" itemLabel="${sec_itemLabel}"/>
</form:select>
Теперь это должно работать.
Но у него есть небольшой недостаток.Если есть Книга без Издателя, то в пустом раскрывающемся списке не будет атрибута выбора.Это не так уж плохо, потому что это самый верхний вариант и будет отображаться, если не выбран ни один другой вариант.
Если кто-то не может принять этот недостаток, то один из способов решить эту проблему - написать собственныйРасширение тега jsp org.springframework.web.servlet.tags.form.Option
(класс, который делает тег опции весны).Есть только две вещи, которые действительно нужно изменить:
1) метод isSelected(Object resolvedValue)
должен возвращать true, если состояние привязки нулевое (поэтому этот метод становится действительно простым)
private boolean isSelected(Object resolvedValue) {
BindStatus bindStatus = getBindStatus();
return bindStatus == null || bindStatus.getValue() == null || bindStatus.getActualValue() == null;
}
2) если тег отображается без или с пустым телом (метод renderDefaultContent
), содержимое отображаемого html option
должно быть пустым, но не value
.Таким образом, второй параметр метода renderOption (SpecialWay) должен быть установлен на пустую строку.
@Override
protected void renderDefaultContent(TagWriter tagWriter) throws JspException {
Object value = this.pageContext.getAttribute(VALUE_VARIABLE_NAME);
renderOptionSpecialWay(value, "", tagWriter);
}
Но поскольку метод isSelected
является закрытым и не может быть переопределен, необходимо скопировать renderOption
(может переименовать его) и должен изменить его так, чтобы он вызывал «новый» метод isSelected.То же самое должно быть сделано с двумя методами renderDefaultContent
и renderFromBodyContent
, потому что renderOption
тоже является приватным.
Итак, один придумал этот класс:
public class NullOptionTag extends OptionTag {
@Override
protected void renderDefaultContent(TagWriter tagWriter) throws JspException {
Object value = this.pageContext.getAttribute(VALUE_VARIABLE_NAME);
renderOptionSpecialWay(value, "", tagWriter);
}
@Override
protected void renderFromBodyContent(BodyContent bodyContent, TagWriter tagWriter) throws JspException {
Object value = this.pageContext.getAttribute(VALUE_VARIABLE_NAME);
String label = bodyContent.getString();
renderOptionSpecialWay(value, label, tagWriter);
}
private void renderOptionSpecialWay(Object value, String label, TagWriter tagWriter) throws JspException {
tagWriter.startTag("option");
writeOptionalAttribute(tagWriter, "id", resolveId());
writeOptionalAttributes(tagWriter);
String renderedValue = getDisplayString(value, getBindStatus().getEditor());
tagWriter.writeAttribute(OptionTag.VALUE_VARIABLE_NAME, renderedValue);
if (isSelected(value)) {
tagWriter.writeAttribute("selected", "selected");
}
if (isDisabled()) {
tagWriter.writeAttribute("disabled", "disabled");
}
tagWriter.appendValue(label);
tagWriter.endTag();
}
private boolean isSelected(Object resolvedValue) {
BindStatus bindStatus = getBindStatus();
return bindStatus == null || bindStatus.getValue() == null || bindStatus.getActualValue() == null;
}
}
Следующая вещьсделать, это добавить этот класс в определение библиотеки тегов, чтобы его можно было использовать в select.tagx
<form:select id="_${sec_field}_id" path="${sec_field}" disabled="${disabled}">
<c:if test="${not required}">
<formExtension:nulloption value="null"></formExtension:nulloption>
</c:if>
<form:options items="${items}" itemValue="${fn:escapeXml(itemValue)}" itemLabel="${sec_itemLabel}"/>
</form:select>