使用Hibernate进行Spring MVC和bean验证
这解释起来有点复杂,但请耐心听我说。我有一个bean学生,他有几个属性,我注释了所有需要用Hibernate注释验证的属性。当我想搜索一个学生时,我只需要一些注释/验证的属性,但是验证是在所有属性上完成的,这不允许搜索正确执行 这是学生豆:使用Hibernate进行Spring MVC和bean验证,hibernate,spring-mvc,bean-validation,Hibernate,Spring Mvc,Bean Validation,这解释起来有点复杂,但请耐心听我说。我有一个bean学生,他有几个属性,我注释了所有需要用Hibernate注释验证的属性。当我想搜索一个学生时,我只需要一些注释/验证的属性,但是验证是在所有属性上完成的,这不允许搜索正确执行 这是学生豆: @Id @GeneratedValue(strategy = IDENTITY) @Column(name = "STUDENT_ID", unique = true, nullable = false) private In
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "STUDENT_ID", unique = true, nullable = false)
private Integer studentId;
@NotNull(message = "First name is null!")
@NotBlank(message = "Please enter first name!")
@Column(name = "FIRST_NAME", nullable = false, length = 50)
private String firstName;
@NotNull(message = "Last name is null!")
@NotBlank(message = "Please enter last name!")
@Column(name = "LAST_NAME", nullable = false, length = 50)
private String lastName;
@NotNull(message = "MK is null!")
@NotBlank(message = "Please enter MK!")
@Column(name = "MK", nullable = false, length = 2)
private String mk;
@NotNull(message = "Roll number is null!")
@NotBlank(message = "Please enter roll number!")
@Column(name = "ROLL_NUMBER", nullable = false, length = 4)
private String rollNumber;
@NotNull(message = "Roll year is null!")
@NotBlank(message = "Please enter roll year!")
@Column(name = "ROLL_YEAR", nullable = false, length = 4)
private String rollYear;
//not populated by user, no validation needed
@Column(name = "INDEX_NUMBER", unique = true, nullable = false, length = 20)
private String indexNumber;
//for populating MK field only, no validation needed
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch=FetchType.EAGER)
@JoinColumn(name = "PROGRAM_FK", nullable = false)
private Program program;
这是控制器:
@RequestMapping(value="/search", method = RequestMethod.POST)
public String postSearchStudent(
@RequestParam(value = "mk") String programId,
@RequestParam(value = "rollNumber") String rollNumber,
@RequestParam(value = "rollYear") String rollYear,
@RequestParam(value = "indexNumber") String indexNumber,
@Valid @ModelAttribute("searchStudentAttribute") Student student,
BindingResult result,
Model model) {
logger.debug("Received request to search for a student");
if (result.hasErrors()) {
model.addAttribute("programList", programService.getAll());
return "searchStudent";
}
else {
student = studentService.search(indexNumber);
// if student isn't in the db show add student page, else redirect to student page
if (student == null) {
student = new Student();
student.setRollNumber(rollNumber);
student.setRollYear(rollYear);
student.setIndexNumber(indexNumber);
Program program = programService.get(programId);
student.setProgram(program);
model.addAttribute("student", student);
return "addStudent";
}
else {
Integer studentId = student.getStudentId();
model.addAttribute("studentId", studentId);
return "redirect:/essays/main/student/{studentId}";
}
}
}
这是一种观点:
<c:url var="searchUrl" value="/essays/main/student/search" />
<form:form modelAttribute="searchStudentAttribute" method="POST" action="${searchUrl}">
<form:errors path="*" cssClass="errorblock" element="div" />
<form:label path="program">Select program (MK):</form:label>
<form:select path="program" id="programSelect" size="8">
<form:options items="${programList}" itemValue="programId" itemLabel="programDescription" />
</form:select>
<form:label path="mk">MK</form:label>
<form:input path="mk" id="mkInput" size="2" maxlength="2"/>
<form:errors path="mk" cssClass="error"/>
<form:label path="rollNumber">Roll number</form:label>
<form:input path="rollNumber" id="rollNumberInput" size="4"/>
<form:errors path="rollNumber" cssClass="error"/>
<form:label path="rollYear">Roll year</form:label>
<form:input path="rollYear" id="rollYearInput" size="4" maxlength="4"/>
<form:errors path="rollYear" cssClass="error"/>
<form:label path="indexNumber" />
<form:hidden path="indexNumber" id="indexNumberInput" />
<input type="submit" value="Submit" onclick="makeIndexNumber();"/>
</form:form>
选择程序(MK):
迈克科尔斯
卷号
滚动年
如您所见,学生的名字和姓氏与搜索无关,因为搜索是由几个其他属性完成的,这些属性使用javaScript组合成一个属性。但我需要在以后验证名字和姓氏,比如说,添加新学生,所以我不能只删除注释而根本不验证这些字段。有人能告诉我,我应该制作一个单独的bean进行验证,只用于搜索学生,还是有其他合适的解决方案
让我更形象地说:
当我提交所有字段都为空的表单时,会出现这些错误。我如何告诉它在搜索完成时不考虑名字和姓氏属性,而不删除注释进行验证?注释说明您不能将
@NotNull
值分配给带注释的变量。在您提供的代码中,我看不到您在任何地方这样做,但我认为会发生以下情况:
当您将一个对象传递给springmvc
时,它会创建它自己的对象表示形式,而该表示形式又可用于生成的jsp
-类。当您提交表单时,转换会以另一种方式进行,它使用set
-方法重新创建原始对象。因此,当您创建一个新的Student
时,firstName
和lastName
变量将为null
,这很好。然后将其传递给springmvc
,后者也将两个变量值转换为null
。但是,在提交表单时,springmvc
尝试进行反向翻译,并执行setFirstName(null)
,然后出现了问题
有几种方法可以处理这种情况
springmvc
之前,只需将firstName
和lastName
变量设置为“”(空字符串)。然后它将永远不会尝试为它们分配null
-值,它将是空字符串StudentSearchCommand
或类似的东西,它将作为搜索对话框的支持对象。这个类应该有进行搜索所需的字段,所以所有Student
都有,除了名字和姓氏,但没有验证,也没有JPA注释(只是一个普通的Ol'Java对象(POJO))。实例化该类并将其发送到Spring MVC
,提交表单时,从中选择值并填写Student
-对象。通过这种方式,您可以超越springmvc
对域类的要求(比如“必须有一个setter”),并按照您想要的方式保持它们这是一个使用验证组的好方案。要了解验证组,请查看此链接- 标准@Valid注释仍然不支持组。因此,您可以将特定于Spring的@Validated注释与验证组一起使用
谢谢您的回答@Tobb!关于第一个建议:我还用@NotBlank注释了我的bean属性,所以将first和last name设置为空字符串不会仍然导致“Please enter first/last name!”错误吗?关于第二个建议-我会努力回去的。是的,可能会。第二个解决方案可能是可行的。可能没有
@NotNull
和@NotBlank
注释,我以前从未使用过它们。。但是,如果必须包含它们,最好是完全控制类,不要将其传递给第三方(Spring MVC)。此外,您可以尝试将其设置为任意字符串,以查看错误消息是否消失(然后知道它确实是由Spring MVC与对象的交互引起的)