我正在使用Spring MVC,并尝试保存一个基本调查表,对Map<String, Boolean>
的是/否(是/否)答案,其中String键分别为“ Q1”和“ Q2”。>
在控制器端,它正确绑定,将各自的输入值设置为Map,但是当实体对象传递给服务进行保存时,抛出ClassCastException,抱怨无法保存。数据库(postgres)类型为布尔值。
例外
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean
at org.hibernate.type.descriptor.java.BooleanTypeDescriptor.unwrap(BooleanTypeDescriptor.java:19) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.type.descriptor.sql.BooleanTypeDescriptor$1.doBind(BooleanTypeDescriptor.java:44) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:74) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:280) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:275) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.type.AbstractSingleColumnStandardBasicType.nullSafeSet(AbstractSingleColumnStandardBasicType.java:39) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.persister.collection.AbstractCollectionPersister.writeElement(AbstractCollectionPersister.java:903) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.persister.collection.BasicCollectionPersister.doUpdateRows(BasicCollectionPersister.java:231) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.persister.collection.AbstractCollectionPersister.updateRows(AbstractCollectionPersister.java:1728) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
实体
@Entity
public class Questionnaire {
private static final long serialVersionUID = 1L;
public static final String[] SHORT_QUESTIONS = {"q1", "q2", "q3", "q4", "q5", "q6", "q7"};
@ElementCollection(fetch=FetchType.LAZY)
@MapKeyColumn(name="question")
@Column(name="answer")
private Map<String, Boolean> shortForm = new LinkedHashMap<>();
// constructor, setters and getters here
}
控制器方法:
@PostMapping("/questionnaire/save/{id}")
public String save(@ModelAttribute @Valid Questionnaire questionnaire, BindingResult binder, RedirectAttributes redirectAttrs, Model model) {
if (binder.hasErrors()) {
model.addAttribute("messageDanger", messages.getMessage("general.save.failed", null, LocaleContextHolder.getLocale()));
return "questionnaire/full";
}
// these all bind properly and return true or false accordingly
log.debug("q1: " + questionnaire.getShortForm().get("q1"));
log.debug("q2: " + questionnaire.getShortForm().get("q2"));
log.debug("q3: " + questionnaire.getShortForm().get("q3"));
log.debug("q4: " + questionnaire.getShortForm().get("q4"));
log.debug("q5: " + questionnaire.getShortForm().get("q5"));
log.debug("q6: " + questionnaire.getShortForm().get("q6"));
// Exception occurs here during .save()
questionnaireSvc.save(questionnaire);
redirectAttrs.addFlashAttribute("message", messages.getMessage("general.save.success", null, LocaleContextHolder.getLocale()));
return "redirect:/questionnaire/full/" + questionnaire.getId();
}
HTML(Thymeleaf)
<tr th:each="question : ${T(app.model.Questionnaire).SHORT_QUESTIONS}">
<td headers="question-col" th:utext="#{questionnaire.short.__${question}__}"></td>
<td headers="applicant-col">
<div class="custom-control custom-radio">
<input type="radio" th:field="*{shortForm[__${question}__]}" class="custom-control-input" required value="false" />
<label class="custom-control-label" th:text="#{general.no}" th:for="${#ids.prev('shortForm__${question}__')}"></label>
</div>
<div class="custom-control custom-radio">
<input type="radio" th:field="*{shortForm[__${question}__]}" class="custom-control-input" required value="true" />
<label class="custom-control-label" th:text="#{general.yes}" th:for="${#ids.prev('shortForm__${question}__')}"></label>
</div>
</td>