Spring MVC 表单与控制器间model对象映射的一些注意事项

本文探讨SpringMVC中表单与控制器间model对象映射的问题,包括表单标签使用、model对象传递及异常处理等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

折腾了一下午Spring MVC 表单与控制器间model对象映射的问题,问题解决后,决定把这些经验分享给大家,有问题的地方,还请指教。

首先,这些问题都是基于你使用了spring的表单标签(标签用sf作为前缀),类如下面代码所示:

	<sf:form method="post" commandName="account" >
		<sf:errors path="*" element="div" cssClass="error"  />
		<sf:label path="loginName" cssErrorClass="error">账号: </sf:label><sf:input path="loginName" cssErrorClass="error"/><br/>
		<sf:label path="name" cssErrorClass="error">姓名: </sf:label><sf:input path="name" cssErrorClass="error"/><br/>
		<sf:label path="password" cssErrorClass="error">密码: </sf:label><sf:password path="password" cssErrorClass="error"/><br/>
		<input type="button" value="注册" id="registerBtn"/>
	</sf:form>


1、假设上面这个页面是个用户注册的JSP页面,你有如下一个controller:

	@RequestMapping(value="/register", method = RequestMethod.GET)
	public String register(Model model) {
		//model.addAttribute(new BaseAccount());
	    model.addAttribute("account", new BaseAccount());
		return "a4/account/register";
	}
通常你会通过GET方式请求这个页面,然后展示开头那个注册页面。这里一定要注意一下红色部分的代码:因为你的注册界面引用了spring的表单标签sf:form,且commanName属性指定了需要从上下文中取出一个key为account的model对象,所以,无论是哪个controller定向到这个视图,都必须返回一个key为account的model对象,这也是上面红色部分代码的意义。(同时,您还需要注意一下controller中model.addAttribute()方法,带key和不带key的区别,不带key,key就为被设置对象的simpleName,首字母小写,如上面的代码中,不设置key的话,spring默认设置的key就为baseAccount,这样返回去就会有问题

如果你不按照上面的要求写代码,你将会得到如下类似的异常信息:

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'account' available as request attribute

2、假设你的用户注册界面,用POST方式到了下面这个Controller中:

	@RequestMapping(value="/register", method = RequestMethod.POST)
	public String registerProcess(Model model, @ModelAttribute("account") @Valid BaseAccount account, Errors errors) {
		if(errors.hasErrors()) {
			return "a4/account/register";
		}
		long newId = this.accountService.registerAccount(account);
		if(newId == -1) {
			model.addAttribute("commonRegisterError", "账户创建失败");
			return "a4/account/register";
		}
		model.addAttribute("accountId", account.getId());
		return "redirect:/accounts/{accountId}";
	}
我们先看第一个if分支,上面代码红色部分,意思是说表单验证失败的时候返回到注册界面。这里一定要注意了:结合第一点中所讲,我们这个地方并没有显示的设置key为account的model对象,因为我们任务request请求过来之后再次返回到那个注册界面,其中的model对象是不会丢的,所以我们不需要显示设置。这个逻辑是正确的,spring也支持,但需要注意的是这个地方有个陷阱,看看我们的注册页面表单的commanName和GET注册页面的model对象KEY都是account,如果你不按照上面代码的方法参数中用蓝色注解@ModelAttribute指定model的Key为account,你也为得到如下的异常信息

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'account' available as request attribute

另外:看看我们注册页面上的表单验证错误提示标签,如<sf:errors/>和<sf:label/>等,如果不按照第2点说的去做,即便后台表单验证有问题,也不会将错误信息显示到页面上的!问题的根源还是在这个Key上面。

最后,为了少出这种莫名其妙的问题,命名规范一致性确实很重要!上面那些代码,如果我们都用baseAccount作为key的话,就不会有那么多坑了。文末附上key都为baseAccount的代码:

	<sf:form method="post" modelAttribute="baseAccount" >
		<sf:errors path="*" element="div" cssClass="error"  />
		<c:if test="${!empty commonRegisterError}">
			<span class="error">${commonRegisterError}</span><br/><br/>
		</c:if>
		<sf:label path="loginName" cssErrorClass="error">账号: </sf:label><sf:input path="loginName" cssErrorClass="error"/><br/>
		<sf:label path="name" cssErrorClass="error">姓名: </sf:label><sf:input path="name" cssErrorClass="error"/><br/>
		<sf:label path="password" cssErrorClass="error">密码: </sf:label><sf:password path="password" cssErrorClass="error"/><br/>
		<br/>
		<input type="button" value="注册" id="registerBtn"/>
	</sf:form>
	@RequestMapping(value="/register", method = RequestMethod.GET)
	public String register(Model model) {
		model.addAttribute(new BaseAccount());
		return "a4/account/register";
	}
	@RequestMapping(value="/register", method = RequestMethod.POST)
	public String registerProcess(Model model, @Valid BaseAccount baseAccount, Errors errors) {
		if(errors.hasErrors()) {
			return "a4/account/register";
		}
		long newId = this.accountService.registerAccount(baseAccount);
		if(newId == -1) {
			model.addAttribute("commonRegisterError", "账户创建失败");
			return "a4/account/register";
		}
		model.addAttribute("accountId", baseAccount.getId());
		return "redirect:/accounts/{accountId}";
	}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值