提交表单时出现String转Long失败的400错误请求求助
我一眼就看出问题所在了——你的上传请求根本没走到你写的updateUserProfileImage方法,而是被Spring MVC错误地匹配到了另一个带有Long类型路径变量的控制器方法上,导致它试图把update(或者你后来改的updateImage)这个字符串转成Long类型,直接抛出了NumberFormatException。
问题根源分析
你控制器类上有@RequestMapping("/users"),所以上传方法的完整请求路径是/users/update。如果你的项目里存在另一个类似这样的方法:
@RequestMapping("/users/{userId}") public SomeResponse getUser(@PathVariable Long userId) { // ... 业务逻辑 }
Spring MVC的请求匹配规则是:宽泛的路径变量映射会优先匹配和它格式兼容的请求。当你请求/users/update时,Spring会把update当作路径变量userId的取值,尝试将其转换为Long类型,这就触发了你看到的400错误。而你改路径为updateImage后错误提示变成转updateImage失败,完全坐实了这个冲突。
解决方法
这里有几个可行的方案,按推荐程度排序:
1. 给上传请求加更具体的路径,避免冲突
把上传方法的路径改得更独特,比如加上profile前缀,让它的映射比路径变量的更具体:
// 控制器类上已有@RequestMapping("/users") @RequestMapping( value = "/profile/update", params = {"new_profile_image"}, method = RequestMethod.POST) public ModelAndView updateUserProfileImage( @RequestParam(value = "new_profile_image") CommonsMultipartFile newProfileImage, ModelMap model) { System.out.println("controller executed!"); if(newProfileImage != null && !newProfileImage.isEmpty()) { updateService.updateUserProfileImage(newProfileImage.getBytes()); } return new ModelAndView("redirect:/users/my_profile"); }
对应的JSP表单action也要同步修改:
<form action="<c:url value='/users/profile/update?${_csrf.parameterName}=${_csrf.token}' />" method="post" enctype="multipart/form-data"> <input name="new_profile_image" type="file" id="new_profile_image"> <button type="submit" class="btn btn-primary">Update</button> </form>
2. 给路径变量添加正则约束,限制仅匹配数字
如果那个带Long路径变量的方法是你维护的,可以给路径变量加上正则表达式,让它只接受纯数字的取值:
@RequestMapping("/users/{userId:\\d+}") // 加了:\\d+正则,仅匹配数字 public SomeResponse getUser(@PathVariable Long userId) { // ... 业务逻辑 }
这样Spring就只会把像/users/123这样的请求匹配到这个方法,而/users/update这类字符串结尾的请求就会跳过它,找到你的上传方法。
3. 调整控制器类的映射结构
如果允许的话,你可以把上传相关的方法单独放到一个带有更具体前缀的控制器类里,比如:
@RequestMapping("/users/profile") public class UserProfileController { @RequestMapping(value = "/update", params = {"new_profile_image"}, method = RequestMethod.POST) public ModelAndView updateUserProfileImage(...) { // ... } }
这样完整路径是/users/profile/update,彻底和/users/{userId}的映射划清界限。
验证步骤
你可以先在项目里搜索@PathVariable Long或者@RequestMapping("/users/{,找到那个冲突的方法,确认它的存在后再用上面的方案解决,应该就能看到控制台输出controller executed!了。
内容的提问来源于stack exchange,提问作者Alejandor Garcia

