我在使用 Spring Boot 验证表单时遇到问题。我已经找到了问题的原因(并且知道可能的解决方案),但我想了解为什么会发生这种情况。
在 post 方法到达的控制器中我有:
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String processAddNewEvent(@Valid @ModelAttribute("newEvent") EventDto newEvent, @ModelAttribute("imageFile") MultipartFile imageFile, BindingResult result, HttpServletRequest request) {
if(result.hasErrors()) {
return "addEvent";
}
return "redirect:/events";
}
我想要的只是验证 newEvent 对象。如果有错误,我会再次显示“addEvent”表单并显示错误消息。
但是在这个方法中,我从表单接收两个参数:newEvent 对象和一个文件(imageFile)。在这种情况下,一旦调用此函数,我就会收到 MethodArgumentNotValidException。但是,如果我删除 imageFile 并仅接收 newEvent 对象,则不会引发异常并且验证可以正常工作。
也就是说,如果我的控制器看起来像这样,则验证有效并且我没有例外:
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String processAddNewEvent(@Valid @ModelAttribute("newEvent") EventDto newEvent, BindingResult result, HttpServletRequest request) {
if(result.hasErrors()) {
return "addEvent";
}
return "redirect:/events";
}
所以,我的问题是,验证可以在一个对象上进行,而不是在另一个对象上进行吗?我不应该从表单中收到两个不同的对象吗?正确的做法是什么?
感谢并抱歉我的英语!
我解决这个问题的想法是将图像文件放入 newEvent 类中,从而只接收一个对象。我仍然不知道它是否会起作用。我只是想好好理解这个问题
出现您的问题是因为 Spring 尝试验证两个对象(
newEvent
和 imageFile
),因为 @Valid
上存在 newEvent
,但只有 newEvent
符合验证条件。 MultipartFile
并不意味着使用标准 bean 验证机制(如 @Valid
或 @NotNull
)进行验证,因此会导致 MethodArgumentNotValidException
。
是否可以对一个对象进行验证而不对另一个对象进行验证? 是的,验证只能应用于 newEvent 对象。您正确地在
@Valid
上使用 newEvent
,这会触发该特定对象的验证。 MultipartFile
,但是,应该单独处理,而不应用验证注释。
我不应该从表单中接收两个不同的对象吗?是的,您可以接收两个单独的对象:
newEvent
(DTO)和MultipartFile
(文件)。只要您不尝试以与 MultipartFile
相同的方式验证 newEvent
对象,就可以单独处理它们。
解决方案 更改参数顺序,如下所示:
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String processAddNewEvent(
@Valid @ModelAttribute("newEvent") EventDto newEvent,
BindingResult result,
@ModelAttribute("imageFile") MultipartFile imageFile,
HttpServletRequest request) {
if (result.hasErrors()) {
return "addEvent"; // Return the form view with error messages
}
// Handle the imageFile separately (e.g., save the file, validate its size/type)
// Validate the imageFile
if (!imageFile.isEmpty()) {
// Example: Check the file size (e.g., max 2MB)
long maxFileSize = 2 * 1024 * 1024; // 2 MB
if (imageFile.getSize() > maxFileSize) {
result.rejectValue("imageFile", "error.imageFile", "File size exceeds the 2MB limit.");
return "addEvent";
}
// Example: Check the file type (e.g., only accept JPEG and PNG)
String contentType = imageFile.getContentType();
if (!"image/jpeg".equals(contentType) && !"image/png".equals(contentType)) {
result.rejectValue("imageFile", "error.imageFile", "Only JPEG and PNG files are accepted.");
return "addEvent";
}
// Save the image file to a specific directory
try {
String uploadDirectory = "/path/to/upload/directory"; // Replace with actual path
String fileName = imageFile.getOriginalFilename();
Path path = Paths.get(uploadDirectory + File.separator + fileName);
Files.copy(imageFile.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
result.rejectValue("imageFile", "error.imageFile", "Failed to save the file. Please try again.");
return "addEvent";
}
}
return "redirect:/events";
}