论坛首页 Java企业应用论坛

Spring MVC 3.x annotated controller的几点心得体会

浏览 58631 次
该帖已经被评为精华帖
作者 正文
   发表时间:2010-12-17  
话说我都没配那个modelAttribute,form里就写了个POST 在Controller里就直接调用了.一直也奇怪这个问题,binder是怎么做的,难道他会根据form的属性自动匹配POJO吗

PS :modelAttribute 是怎么反射到POJO的
0 请登录后投票
   发表时间:2010-12-17  
homg127 写道
话说我都没配那个modelAttribute,form里就写了个POST 在Controller里就直接调用了.一直也奇怪这个问题,binder是怎么做的,难道他会根据form的属性自动匹配POJO吗

PS :modelAttribute 是怎么反射到POJO的


咱俩的问题估计是一样的,我也不知道怎么可能通过modelAttribute里的CustomerCommand名找到com.command.CustomerCommand并实例化,所以不知道modelAttribute怎么bind到POJO。
0 请登录后投票
   发表时间:2010-12-17  
unsid 写道
itstarting 写道
unsid 写道

这是我页面里东西,我觉得和/xrequirement/addcustomer.do提交到的controller没关系,因为这个页面刚一打开初始化就报错java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'customerComand' available as request attribute,那时候还没有提交呢。是不是要求command要和controller在同一个包下?



你把相关代码贴出来,这个问题不应该是个棘手问题,肯定是哪里犯了低级错误。
代码包括:
1. CustomerComand.java
2. 在controller的addcustomer方法
3. 加上这个jsp的form,就OK了


好的

CustomerComand.java
    public class CustomerCommand {
	
	private String firstname ;
	private String lastname ;
	
	public String getFirstname() {
		return firstname;
	}
	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}
	public String getLastname() {
		return lastname;
	}
	public void setLastname(String lastname) {
		this.lastname = lastname;
	}
    }


在controller的addcustomer方法
@Controller
   public class CustomerController {
	
	private CustomerRepository customerRepository;
	
	@RequestMapping(value="/addcustomer",method = RequestMethod.GET)
	public String addCustomer(CustomerCommand customerCommand) throws Exception {
             //do something
	}
	
	public void setCustomerRepository(CustomerRepository customerRepository) {
		this.customerRepository = customerRepository;
	}
	
   }


加上这个jsp的form
	<form:form method="post" modelAttribute="customerCommand" action="/addcustomer.do">
	FIRSTNAME: <form:input path="firstname"/><br>
	LASTNAME:  <form:input path="lastname"/><br>
	<input type="submit" value="regist"/>
	</form:form>


非常感谢楼主细心解答!



老兄,你form里是post
但你mapping的地方是get(@RequestMapping(value="/addcustomer",method = RequestMethod.GET))
其他我觉得不会有问题,你调整过来看看,直接去掉method的限制好了。
0 请登录后投票
   发表时间:2010-12-17  
unsid 写道
homg127 写道
话说我都没配那个modelAttribute,form里就写了个POST 在Controller里就直接调用了.一直也奇怪这个问题,binder是怎么做的,难道他会根据form的属性自动匹配POJO吗

PS :modelAttribute 是怎么反射到POJO的


咱俩的问题估计是一样的,我也不知道怎么可能通过modelAttribute里的CustomerCommand名找到com.command.CustomerCommand并实例化,所以不知道modelAttribute怎么bind到POJO。



这里涉及Spring大量的conventions,我没细看这部分,我印象中大概的思路会是:
1.找到mapping的方法,然后逐个匹配方法的param
2.如果找到非“内置”的param(有一个列表,十几个这样),就试图去实例化并填充数据
  此时,如果看到一个com.command.CustomerCommand,那就先实例化一个,然后从request取东西出来populate,取啥呢,取名字为“customerCommand”的modelAttribute,这就是convention。

binding部分大概也就是BeanUtils那样的思路,有深度研究的兄弟可以来给大家分享一下
0 请登录后投票
   发表时间:2010-12-17  
itstarting 写道
unsid 写道
homg127 写道
话说我都没配那个modelAttribute,form里就写了个POST 在Controller里就直接调用了.一直也奇怪这个问题,binder是怎么做的,难道他会根据form的属性自动匹配POJO吗

PS :modelAttribute 是怎么反射到POJO的


咱俩的问题估计是一样的,我也不知道怎么可能通过modelAttribute里的CustomerCommand名找到com.command.CustomerCommand并实例化,所以不知道modelAttribute怎么bind到POJO。



这里涉及Spring大量的conventions,我没细看这部分,我印象中大概的思路会是:
1.找到mapping的方法,然后逐个匹配方法的param
2.如果找到非“内置”的param(有一个列表,十几个这样),就试图去实例化并填充数据
  此时,如果看到一个com.command.CustomerCommand,那就先实例化一个,然后从request取东西出来populate,取啥呢,取名字为“customerCommand”的modelAttribute,这就是convention。

binding部分大概也就是BeanUtils那样的思路,有深度研究的兄弟可以来给大家分享一下


呵呵 谢谢你的解答 大概有些理解了  照你的说法 modelAttribute 只是一种写法习惯 用来在VIEW中分辨哪个实体 即使不写也没有关系 是这个意思吗?
0 请登录后投票
   发表时间:2010-12-17  
homg127 写道

呵呵 谢谢你的解答 大概有些理解了  照你的说法 modelAttribute 只是一种写法习惯 用来在VIEW中分辨哪个实体 即使不写也没有关系 是这个意思吗?



no

modelAttribute是form tag的属性,其实说白了就是用来构造类似于EL的path.
比如,modelAttribute="hotel",而<form:input path="name" .../>,这binding的时候就是

hotel.name


而如果需要多个bean在一个form里,就要modelAttribute="someWrapperBean",而
<form:input就要写:
<form:input path="beanA.name".../>
<form:input path="beanB.title".../>

此时:

someWrapperBean.beanA.name,someWrapperBean.beanB.title,。。。

如此而已
0 请登录后投票
   发表时间:2010-12-17  
itstarting 写道
unsid 写道
itstarting 写道
unsid 写道

这是我页面里东西,我觉得和/xrequirement/addcustomer.do提交到的controller没关系,因为这个页面刚一打开初始化就报错java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'customerComand' available as request attribute,那时候还没有提交呢。是不是要求command要和controller在同一个包下?



你把相关代码贴出来,这个问题不应该是个棘手问题,肯定是哪里犯了低级错误。
代码包括:
1. CustomerComand.java
2. 在controller的addcustomer方法
3. 加上这个jsp的form,就OK了


好的

CustomerComand.java
    public class CustomerCommand {
	
	private String firstname ;
	private String lastname ;
	
	public String getFirstname() {
		return firstname;
	}
	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}
	public String getLastname() {
		return lastname;
	}
	public void setLastname(String lastname) {
		this.lastname = lastname;
	}
    }


在controller的addcustomer方法
@Controller
   public class CustomerController {
	
	private CustomerRepository customerRepository;
	
	@RequestMapping(value="/addcustomer",method = RequestMethod.GET)
	public String addCustomer(CustomerCommand customerCommand) throws Exception {
             //do something
	}
	
	public void setCustomerRepository(CustomerRepository customerRepository) {
		this.customerRepository = customerRepository;
	}
	
   }


加上这个jsp的form
	<form:form method="post" modelAttribute="customerCommand" action="/addcustomer.do">
	FIRSTNAME: <form:input path="firstname"/><br>
	LASTNAME:  <form:input path="lastname"/><br>
	<input type="submit" value="regist"/>
	</form:form>


非常感谢楼主细心解答!



老兄,你form里是post
但你mapping的地方是get(@RequestMapping(value="/addcustomer",method = RequestMethod.GET))
其他我觉得不会有问题,你调整过来看看,直接去掉method的限制好了。



我改成一样的了,还是不行,报customerCommand没有绑定。
0 请登录后投票
   发表时间:2010-12-17  
unsid 写道

我改成一样的了,还是不行,报customerCommand没有绑定。



服了:

action="/addcustomer.do"

but

@RequestMapping(value="/addcustomer",method = RequestMethod.GET)


9成9是低级错误所致
0 请登录后投票
   发表时间:2010-12-20  
itstarting 写道
unsid 写道

我改成一样的了,还是不行,报customerCommand没有绑定。



服了:

action="/addcustomer.do"

but

@RequestMapping(value="/addcustomer",method = RequestMethod.GET)


9成9是低级错误所致


现在有了一点进展,事情是这样的,我一上来访问的helloController,并返回输入customer信息的页面hello.jsp。
	@RequestMapping(value="/hello",method = RequestMethod.GET)
	public String hello(Model model) {
		model.addAttribute("hello","helloworld!");
		return "hello";
	}


hello.jsp
	<form:form method="get" modelAttribute="customerCommand" action="/xrequirement/addcustomer">
	${hello}<br>
	FIRSTNAME: <form:input path="firstname"/><br>
	LASTNAME:  <form:input path="lastname"/><br>
	<input type="submit" value="regist"/>
	</form:form>


customerController

@RequestMapping(value="/addcustomer",method = RequestMethod.GET)
	public String addCustomer(@ModelAttribute("customerCommand") CustomerCommand customerCommand) throws Exception {
   .......
}


此时会报customerCommand找不到绑定的异常,但是如果我把helloController改成这样
	@RequestMapping(value="/hello",method = RequestMethod.GET)
	public String hello(@ModelAttribute("customerCommand") CustomerCommand customerCommand,Model model) {
		model.addAttribute("hello","helloworld!");
		return "hello";
	}

参数里增加了@ModelAttribute("customerCommand") CustomerCommand customerCommand 就正常显示了,我很纳闷我hello这个方法根本用不到CustomerCommand customerCommand难道必须要在这声明?
0 请登录后投票
   发表时间:2010-12-20  
unsid 写道

参数里增加了@ModelAttribute("customerCommand") CustomerCommand customerCommand 就正常显示了,我很纳闷我hello这个方法根本用不到CustomerCommand customerCommand难道必须要在这声明?


其实你的hello方法的执行终点是渲染hello.jsp,此时hello.jsp会试图在request获取modelAttribute,但如果你按原来的写法,显然没有名字为customerCommand的modelAttribute,所以会有绑定异常,而你加上就可以了。

另外,你也可以直接new一个然后put到request里去,也是OK的,此时方法上可以不要这个参数(@ModelAttribute("customerCommand") CustomerCommand customerCommand)了:
model.addAttribute("customerCommand",new CustomerCommand ());



BTW:也许显式的写@ModelAttribute也是一种好习惯,但我一般懒得写,放在方法上即可,此时Spring能处理好,即使你没put到request去:
	@RequestMapping(value="/hello",method = RequestMethod.GET)
	public String hello(CustomerCommand customerCommand,Model model) {
		model.addAttribute("hello","helloworld!");
		return "hello";
	}
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics