gpt4 book ai didi

java - 如何查找 BindingResult 中的错误原因

转载 作者:行者123 更新时间:2023-12-02 06:23:30 27 4
gpt4 key购买 nike

在 eclipse 和 tomcat 服务器中使用 hibernate 的 spring mvc Web 应用程序中,我更改了 jsp 中的几个文本字段以下拉列表,以便可以从自己的下拉菜单中选择一个人的性别和种族。我小心翼翼地更改了应用程序的其他级别,包括在底层数据库中设置性别和种族的连接表,以及更改模型和存储库级别中的代码。应用程序编译,并且 jsp 加载了每个下拉列表中所选人员的正确选定值,但单击提交/更新按钮会导致 BindingResult.hasErrors() 问题,这无法帮助我定位问题的原因。

有人可以帮我找出无法处理更新的原因吗?

这是在 Controller 类中调用的 processUpdatePatientForm() 方法。请注意,它会触发 System.out.println(),显示 BindingResult.hasErrors() 并返回 jsp:

@RequestMapping(value = "/patients/{patientId}/edit", method = RequestMethod.PUT)
public String processUpdatePatientForm(@Valid Patient patient, BindingResult result, SessionStatus status) {
if (result.hasErrors()) {
System.out.println(":::::::::::::::: in PatientController.processUpdatePatientForm() result.hasErrors() ");
List<ObjectError> errors = result.getAllErrors();
for(int i=0;i<result.getErrorCount();i++){System.out.println("]]]]]]] error "+i+" is: "+errors.get(i).toString());}
return "patients/createOrUpdatePatientForm";}
else {
this.clinicService.savePatient(patient);
status.setComplete();
return "redirect:/patients?patientID=" + patient.getId();
}
}

返回jsp时,包含以下错误信息:

//This is printed out in my jsp below the Sex drop down list:  
Failed to convert property value of type java.lang.String to required type org.springframework.samples.knowledgemanager.model.Gender for property sex; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [org.springframework.samples.knowledgemanager.model.Gender] for property sex: no matching editors or conversion strategy found

//This is printed out in my jsp below the Race drop down list:
Failed to convert property value of type java.lang.String to required type org.springframework.samples.knowledgemanager.model.Race for property race; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [org.springframework.samples.knowledgemanager.model.Race] for property race: no matching editors or conversion strategy found

以下是 eclipse 控制台中打印的全部内容:

Hibernate: select gender0_.id as id1_2_, gender0_.name as name2_2_ from gender gender0_ order by gender0_.name
Hibernate: select race0_.id as id1_7_, race0_.name as name2_7_ from race race0_ order by race0_.name
:::::::::::::::: in PatientController.processUpdatePatientForm() result.hasErrors()
]]]]]]] error 0 is: Field error in object 'patient' on field 'race': rejected value [Hispanic]; codes [typeMismatch.patient.race,typeMismatch.race,typeMismatch.org.springframework.samples.knowledgemanager.model.Race,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [patient.race,race]; arguments []; default message [race]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'org.springframework.samples.knowledgemanager.model.Race' for property 'race'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [org.springframework.samples.knowledgemanager.model.Race] for property 'race': no matching editors or conversion strategy found]
]]]]]]] error 1 is: Field error in object 'patient' on field 'sex': rejected value [Male]; codes [typeMismatch.patient.sex,typeMismatch.sex,typeMismatch.org.springframework.samples.knowledgemanager.model.Gender,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [patient.sex,sex]; arguments []; default message [sex]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'org.springframework.samples.knowledgemanager.model.Gender' for property 'sex'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [org.springframework.samples.knowledgemanager.model.Gender] for property 'sex': no matching editors or conversion strategy found]

请注意,错误消息中显示的值 [西类牙] 和 [男性] 会触发错误。问题可能是 Gender 和 Race 的 name 属性被传递给 Spring MVC,而应该传递 id 属性。但如何在代码中解决这个问题?

有人可以帮我弄清楚这个问题的真相吗?第一步是如何获得更有用的错误消息,该消息可以找到代码中触发问题的位置。

<小时/>

编辑:

根据 Sotirios 的请求,以下是我在 jsp 中的表单:

<form:form modelAttribute="patient" method="${method}" class="form-horizontal" id="add-patient-form">
<petclinic:inputField label="First Name" name="firstName"/>
<petclinic:inputField label="Middle Initial" name="middleInitial"/>
<petclinic:inputField label="Last Name" name="lastName"/>

<div class="control-group">
<petclinic:selectField label="Sex" name="sex" names="${genders}" size="5"/>
</div>

<petclinic:inputField label="Date of Birth" name="dateOfBirth"/>

<div class="control-group">
<petclinic:selectField label="Race" name="race" names="${races}" size="5"/>
</div>

<div class="form-actions">
<c:choose>
<c:when test="${patient['new']}">
<button type="submit">Add Patient</button>
</c:when>
<c:otherwise>
<button type="submit">Update Patient</button>
</c:otherwise>
</c:choose>
</div>
</form:form>

Patient.java 类是:

@Entity
@Table(name = "patients")
public class Patient extends BaseEntity {

@OneToMany(cascade = CascadeType.ALL, mappedBy = "patient", fetch=FetchType.EAGER)
private Set<Document> documents;

@OneToMany(cascade = CascadeType.ALL, mappedBy = "patient", fetch=FetchType.EAGER)
private Set<Address> addresses;

@OneToMany(cascade = CascadeType.ALL, mappedBy = "patient", fetch=FetchType.EAGER)
private Set<PhoneNumber> phonenumbers;

@Column(name = "first_name")
@NotEmpty
protected String firstName;

@Column(name = "middle_initial")
protected String middleInitial;

@Column(name = "last_name")
@NotEmpty
protected String lastName;

@ManyToOne
@JoinColumn(name = "sex_id")
protected Gender sex;

@Column(name = "date_of_birth")
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
@DateTimeFormat(pattern = "yyyy/MM/dd")
protected DateTime dateOfBirth;

@ManyToOne
@JoinColumn(name = "race_id")
protected Race race;

////////////// Document methods
protected void setDocumentsInternal(Set<Document> documents) {this.documents = documents;}

public Set<Document> getFaxes() {
Set<Document> faxes = new HashSet<Document>();
for (Document doc : getDocumentsInternal()) {if (doc.getType().getName().equals("ScannedFaxes")) {faxes.add(doc);}}
return faxes;
}
public Set<Document> getForms() {
Set<Document> forms = new HashSet<Document>();
for (Document doc : getDocumentsInternal()) {if (doc.getType().getName().equals("ScannedPatientForms")) {forms.add(doc);}}
return forms;
}

protected Set<Document> getDocumentsInternal() {
if (this.documents == null) {this.documents = new HashSet<Document>();}
return this.documents;
}

public List<Document> getDocuments() {
List<Document> sortedDocuments = new ArrayList<Document>(getDocumentsInternal());
PropertyComparator.sort(sortedDocuments, new MutableSortDefinition("name", true, true));
return Collections.unmodifiableList(sortedDocuments);
}

public void addDocument(Document doc) {
getDocumentsInternal().add(doc);
doc.setPatient(this);
}

public Document getDocument(String name) {return getDocument(name, false);}

/** Return the Document with the given name, or null if none found for this Patient.
* @param name to test
* @return true if document name is already in use
*/
public Document getDocument(String name, boolean ignoreNew) {
name = name.toLowerCase();
for (Document doc : getDocumentsInternal()) {
if (!ignoreNew || !doc.isNew()) {
String compName = doc.getName();
compName = compName.toLowerCase();
if (compName.equals(name)) {
return doc;
}
}
}
return null;
}
//////////// Address methods
protected void setAddressesInternal(Set<Address> addresses) {this.addresses = addresses;}

protected Set<Address> getAddressesInternal() {
if (this.addresses == null) {this.addresses = new HashSet<Address>();}
return this.addresses;
}

public List<Address> getAddresses() {
List<Address> sortedAddresses = new ArrayList<Address>(getAddressesInternal());
PropertyComparator.sort(sortedAddresses, new MutableSortDefinition("address", true, true));
return Collections.unmodifiableList(sortedAddresses);
}

public void addAddress(Address addr) {
getAddressesInternal().add(addr);
addr.setPatient(this);
}

public Address getAddress(String address) {return getAddress(address, false);}

/** Return the Address with the given name, or null if none found for this Patient.
* @param name to test
* @return true if document name is already in use
*/
public Address getAddress(String addr, boolean ignoreNew) {
addr = addr.toLowerCase();
for (Address address1 : getAddressesInternal()) {
if (!ignoreNew || !address1.isNew()) {
String compName = address1.getAddress();
compName = compName.toLowerCase();
if (compName.equals(addr)) {
return address1;
}
}
}
return null;
}
//////////// PhoneNumber methods
protected void setPhoneNumbersInternal(Set<PhoneNumber> phonenumbers) {this.phonenumbers = phonenumbers;}

protected Set<PhoneNumber> getPhoneNumbersInternal() {
if (this.phonenumbers == null) {this.phonenumbers = new HashSet<PhoneNumber>();}
return this.phonenumbers;
}

public List<PhoneNumber> getPhoneNumbers() {
List<PhoneNumber> sortedPhoneNumbers = new ArrayList<PhoneNumber>(getPhoneNumbersInternal());
PropertyComparator.sort(sortedPhoneNumbers, new MutableSortDefinition("phonenumber", true, true));
return Collections.unmodifiableList(sortedPhoneNumbers);
}

public void addPhoneNumber(PhoneNumber pn) {
getPhoneNumbersInternal().add(pn);
pn.setPatient(this);
}

public PhoneNumber getPhoneNumber(String pn) {return getPhoneNumber(pn, false);}

/** Return the PhoneNumber with the given name, or null if none found for this Patient.
* @param name to test
* @return true if phone number is already in use
*/
public PhoneNumber getPhoneNumber(String pn, boolean ignoreNew) {
pn = pn.toLowerCase();
for (PhoneNumber number : getPhoneNumbersInternal()) {
if (!ignoreNew || !number.isNew()) {
String compName = number.getPhonenumber();
compName = compName.toLowerCase();
if (compName.equals(pn)) {
return number;
}
}
}
return null;
}

public String getFirstName(){return this.firstName;}
public void setFirstName(String firstName){this.firstName = firstName;}

public String getMiddleInitial() {return this.middleInitial;}
public void setMiddleInitial(String middleinitial) {this.middleInitial = middleinitial;}

public String getLastName() {return this.lastName;}
public void setLastName(String lastName) {this.lastName = lastName;}

public Gender getSex() {return this.sex;}
public void setSex(Gender sex) {this.sex = sex;}

public void setDateOfBirth(DateTime birthDate){this.dateOfBirth = birthDate;}
public DateTime getDateOfBirth(){return this.dateOfBirth;}

public Race getRace() {return this.race;}
public void setRace(Race race) {this.race = race;}

@Override
public String toString() {
return new ToStringCreator(this)
.append("id", this.getId())
.append("new", this.isNew())
.append("lastName", this.getLastName())
.append("firstName", this.getFirstName())
.append("middleinitial", this.getMiddleInitial())
.append("dateofbirth", this.dateOfBirth)
.toString();
}
}
<小时/>

第二次编辑:

根据 Alexey 的评论,以下是 Controller 类中始终具有 @InitBinder 注释的方法。它与类似模块的 Controller 中的方法相同,其工作原理:

@InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {dataBinder.setDisallowedFields("id");}
<小时/>

第三次编辑:

PatientController.java:

@Controller
@SessionAttributes(types = Patient.class)
public class PatientController {

private final ClinicService clinicService;

@Autowired
public PatientController(ClinicService clinicService) {this.clinicService = clinicService;}

@ModelAttribute("genders")
public Collection<Gender> populateGenders() {return this.clinicService.findGenders();}

@ModelAttribute("races")
public Collection<Race> populateRaces() {return this.clinicService.findRaces();}

@InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {dataBinder.setDisallowedFields("id");}

@RequestMapping(value = "/patients/new", method = RequestMethod.GET)
public String initCreationForm(Map<String, Object> model) {
Patient patient = new Patient();
model.put("patient", patient);
return "patients/createOrUpdatePatientForm";
}

@RequestMapping(value = "/patients/new", method = RequestMethod.POST)
public String processCreationForm(@Valid Patient patient, BindingResult result, SessionStatus status) {
if (result.hasErrors()) {return "patients/createOrUpdatePatientForm";}
else {
this.clinicService.savePatient(patient);
status.setComplete();
return "redirect:/patients?patientID=" + patient.getId();
}
}

@RequestMapping(value = "/patients", method = RequestMethod.GET)
public String processFindForm(@RequestParam("patientID") String patientId, Patient patient, BindingResult result, Map<String, Object> model) {
Collection<Patient> results = this.clinicService.findPatientByLastName("");
model.put("selections", results);
int patntId = Integer.parseInt(patientId);
Patient sel_patient = this.clinicService.findPatientById(patntId);//I added this
model.put("sel_patient",sel_patient);
return "patients/patientsList";
}

@RequestMapping(value = "/patients/{patientId}/edit", method = RequestMethod.GET)
public String initUpdatePatientForm(@PathVariable("patientId") int patientId, Model model) {
Patient patient = this.clinicService.findPatientById(patientId);
model.addAttribute(patient);
return "patients/createOrUpdatePatientForm";
}

@RequestMapping(value = "/patients/{patientId}/edit", method = RequestMethod.PUT)
public String processUpdatePatientForm(@Valid Patient patient, BindingResult result, SessionStatus status) {
if (result.hasErrors()) {
System.out.println(":::::::::::::::: in PatientController.processUpdatePatientForm() result.hasErrors() ");
List<ObjectError> errors = result.getAllErrors();
for(int i=0;i<result.getErrorCount();i++){System.out.println("]]]]]]] error "+i+" is: "+errors.get(i).toString());}
return "patients/createOrUpdatePatientForm";}
else {
this.clinicService.savePatient(patient);
status.setComplete();
return "redirect:/patients?patientID=" + patient.getId();
}
}
}
<小时/>

第四次编辑:

性别.java

@Entity
@Table(name = "gender")
public class Gender extends NamedEntity {}

NamedEntity.java:

@MappedSuperclass
public class NamedEntity extends BaseEntity {

@Column(name = "name")
private String name;

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

public String getName() {return this.name;}

@Override
public String toString() {return this.getName();}

}

BaseEntity.java:

@MappedSuperclass
public class BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Integer id;

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

public Integer getId() {return id;}

public boolean isNew() {return (this.id == null);}

}

最佳答案

您需要添加转换器或适当的编辑器。我更喜欢第一个。请参阅第 6.5 节。上this page了解详情。

您的转换器必须从数据库中获取具有给定名称的实体并返回它。代码会是这样的:

class StringToGender implements Converter<String, Gender> {
@Autowired
private GenderRepository repository;

public Gender convert(String name) {
return repository.getGenderByName(name);
}
}

在您的应用程序上下文 xml 中(如果您使用 xml):

    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="org.example.StringToGender"/>
</set>
</property>

关于java - 如何查找 BindingResult 中的错误原因,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20792988/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com