我有一个控制器映射用于处理上传的文件
控制器
@RequestMapping(value = "/careers/pursue", method = RequestMethod.POST)
public Callable<String> pursue(
final @RequestParam("g-recaptcha-response") String captchaResponse,
final @RequestParam("file") MultipartFile file,
final @ModelAttribute("jobapplication") @Valid JobApplication application, final BindingResult bindingResult,
final Model model)
形式
<form name="jobsForm" id="jobsForm" novalidate="novalidate" action="#" th:action="@{/careers/pursue}"
th:object="${jobapplication}" method="post" enctype="multipart/form-data">
<div class="control-group form-group">
<div class="controls">
<label>First Name:</label>
<input type="text" class="form-control" id="firstName" th:field="*{firstName}" required="required" data-validation-required-message="Please enter your name." />
<p class="help-block"></p>
</div>
</div>
<div class="control-group form-group">
<div class="controls">
<label>Last Name:</label>
<input type="text" class="form-control" id="lastName" th:field="*{lastName}" required="required" data-validation-required-message="Please enter your name." />
<p class="help-block"></p>
</div>
</div>
<div class="control-group form-group">
<div class="controls">
<label>Phone Number:</label>
<input type="tel" class="form-control" id="phone" th:field="*{phone}" required="required" data-validation-required-message="Please enter your phone number." />
</div>
</div>
<div class="control-group form-group">
<div class="controls">
<label>Email Address:</label>
<input type="email" class="form-control" id="email" th:field="*{email}" required="required" data-validation-required-message="Please enter your email address."/>
</div>
</div>
<div class="control-group form-group">
<div class="controls">
<label>Role:</label>
<input type="email" class="form-control" id="role" th:field="*{role}" required="required" data-validation-required-message="Please enter your email address."/>
</div>
</div>
<div class=" control-group form-group">
<div class="g-recaptcha" data-sitekey="ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"></div>
</div>
<div class=" control-group form-group">
<span class="btn btn-primary btn-file">
Add your Resumé <input type="file" name="file" id="file" required="required"/>
</span>
</div>
<div id="success"></div>
<!-- For success/fail messages -->
<button type="submit" class="btn btn-primary">Apply!</button>
</form>
现在,如果某人在提交之前未将文件附加到表单,
-----------------------------749526091303082321866336941
Content-Disposition: form-data; name="firstName"
Anadi
-----------------------------749526091303082321866336941
Content-Disposition: form-data; name="lastName"
Misra
-----------------------------749526091303082321866336941
Content-Disposition: form-data; name="phone"
9845420420
-----------------------------749526091303082321866336941
Content-Disposition: form-data; name="email"
foo@bar.com
-----------------------------749526091303082321866336941
Content-Disposition: form-data; name="role"
open.project
-----------------------------749526091303082321866336941
Content-Disposition: form-data; name="g-recaptcha-response"
03AHJ_Vuv9i7WQ_4zCipfnyrLNl6467l_cZgGIhkdpLjS1M0YmWvwQMOWQeRcrAHFh8s3-jO13NQs7019lzI7UobwNeHKIhBmcLMiVGPk38Iy8BjrEi2glI4QGjE4VTvRhV_-WWYsmlzV_7PRPE5Y8L0NboPXYoG9JSabMOL8V958w74pOzkxabsoR4wouCSa0gzo0EbOsLiCWjd0MAvZiCcKJGdwIlMp0WIjxcufB-RfG2F0rwv65yrgL-By0bdMewkWULY_aRvC-FRSqOEM9X5Qg4gviA-cvc5IY2XnRtaUALOPlR_QbwjgUKl2mJEFNab6Pks3MlsivuEZFkba4isDFlrJ4jXwBBQ
-----------------------------749526091303082321866336941
Content-Disposition: form-data; name="file"; filename=""
Content-Type: application/octet-stream
-----------------------------749526091303082321866336941--
或尝试提交而不验证验证码,我得到此异常
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor' (jobs:91)
....
....
Caused by: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'jobapplication' available as request attribute
at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:144)
at org.thymeleaf.spring4.util.FieldUtils.getBindStatusFromParsedExpression(FieldUtils.java:396)
at org.thymeleaf.spring4.util.FieldUtils.getBindStatus(FieldUtils.java:323)
at org.thymeleaf.spring4.util.FieldUtils.getBindStatus(FieldUtils.java:289)
at org.thymeleaf.spring4.processor.attr.AbstractSpringFieldAttrProcessor.processAttribute(AbstractSpringFieldAttrProcessor.java:98)
at org.thymeleaf.processor.attr.AbstractAttrProcessor.doProcess(AbstractAttrProcessor.java:87)
at org.thymeleaf.processor.AbstractProcessor.process(AbstractProcessor.java:212)
... 66 common frames omitted
我期望的是,我获取验证码响应和文件的空值,然后我的控制器方法应该能够处理它,并将用户返回到具有特定错误消息的表单。它在没有多部分数据的表单上工作如此,即我没有得到绑定错误,而是控制器参数中的空值。我只在使用多部分表单数据时才会看到此问题,如果填充了所有数据,即用户验证验证码并附加文件,则绑定会很好。
使这些参数可选或使用RequestPart也没有帮助(我承认我真的没有得到RequestPart
注释的目的)所以,将控制器改为此(膝跳反复实验;-))
@RequestMapping(value = "/careers/pursue", method = RequestMethod.POST)
public Callable<String> pursue(
final @RequestPart(value = "g-recaptcha-response", required = false) String captchaResponse,
final @RequestPart(value = "file", required = false) MultipartFile file,
final @ModelAttribute("jobapplication") @Valid JobApplication application, final BindingResult bindingResult,
final Model model)
也没有帮助。我是否必须延长StandardServletMultipartResolver或者是否需要更改/修复SpringInputGeneralFieldAttrProcessor,或者我在这里错过了一些细节?
更新
添加控制器方法
@RequestMapping(value = "/careers/pursue", method = RequestMethod.POST)
public Callable<String> pursue(final @ModelAttribute("jobapplication") @Valid JobApplication application,
final BindingResult bindingResult, final Model model,
final @RequestParam(value = "g-recaptcha-response", required = false) String captchaResponse,
final @RequestPart(value = "file", required = false) MultipartFile file) {
return new Callable<String>() {
@Override
public String call() throws Exception {
try {
model.asMap().clear();
GoogleCaptchaResponseData response = captchaVerifier.isCaptchaResponseValid(captchaResponse).get();
model.addAttribute("recaptcha", response.isSuccess());
model.addAttribute("recaptchamessage", response.getErrorCodes());
if (response.isSuccess() && !file.isEmpty()) {
byte[] bytes = file.getBytes();
LOGGER.info("Found file of type {}", file.getOriginalFilename());
ByteArrayInputStream inputBytes = new ByteArrayInputStream(bytes);
mailApi.sendMail(mailApi.buildJobApplicationEmail(application, new BufferedInputStream(inputBytes)));
model.asMap().clear();
model.addAttribute("uploadsuccess", true);
model.addAttribute("resource_host", resourceHost);
model.addAttribute("jobapplication", new JobApplication());
}
} catch (InterruptedException | ExecutionException e) {
LOGGER.error(e.getMessage(), e);
model.asMap().clear();
model.addAttribute("jobapplication", application);
model.addAttribute("resource_host", resourceHost);
model.addAttribute("uploadsuccess", false);
}
return "jobs";
}
};
}
答案 0 :(得分:3)
@RequestPart依赖于HttpMessageConvertors和content-type将多部分数据绑定到方法参数,而@RequestParam依赖注册的转换器来进行转换。 Spring mvc默认提供某些转换器。您可以使用@RequestParam或@RequestPart绑定文件数据。大多数应用程序使用commons文件上传来上传文件和注册
org.springframework.web.multipart.commons.CommonsMultipartResolver
用于多部分解析。注册后,弹出检查每个多部件数据的请求,并使用它来解决方法arg。点击这里
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-multipart
您可以尝试几种物品。确保您的验证码和文件参数都是可选的,如下图所示。我切换到@RequestParam进行验证码。
@RequestMapping(value = "/careers/pursue", method = RequestMethod.POST)
public Callable<String> pursue(
final @RequestParam(value = "g-recaptcha-response", required = false) String captchaResponse,
final @RequestPart(value = "file", required = false) MultipartFile file,
final @ModelAttribute("jobapplication") @Valid JobApplication application, final BindingResult bindingResult,
final Model model)
希望这有帮助。
答案 1 :(得分:2)
@RequestMapping
未映射到与表单@RequestParam
@RequestParam
未通过空通知我正在寻找length() == 0
和file.isEmpty()
另外,您可能需要查看spring guide for file upload
<强>控制器强>
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String pursue(
final @RequestParam("g-recaptcha-response") String captchaResponse,
final @RequestParam("file") MultipartFile file,
final @ModelAttribute("jobapplication") @Valid JobApplication application, final BindingResult bindingResult,
final Model model)
{
if (bindingResult.hasErrors() || captchaResponse.length() == 0 || file.isEmpty())
{
return "form";
}
return "redirect:/";
}
<强>表格强>
<form name="jobsForm" id="jobsForm" novalidate="novalidate" action="#" th:action="@{/upload}"
th:object="${jobapplication}" method="post" enctype="multipart/form-data">
<span>First Name: </span>
<input id="firstname" th:field="*{firstName}" type="text"/><br/>
<span>Last Name: </span>
<input id="lastname" th:field="*{lastName}" type="text"/><br/>
<span>Phone: </span>
<input id="phone" th:field="*{phone}" type="text"/><br/>
<span>Email: </span>
<input id="email" th:field="*{email}" type="text"/><br/>
<span>Role: </span>
<input id="role" th:field="*{role}" type="text"/><br/>
<span></span>
<input type="text" name="g-recaptcha-response"/><br/>
<span>File: </span>
<input type="file" name="file"/><br/>
<input id="submit" type="submit"/>
</form>