论坛首页 Java企业应用论坛

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

浏览 58626 次
该帖已经被评为精华帖
作者 正文
   发表时间:2010-12-01  
我还是喜欢用XML来,@用多了太不直观了
0 请登录后投票
   发表时间:2010-12-01  
do77 写道

而且我多视图的情况,我不建议使用@ResponseBody,还是返回自己的对象好

    @RequestMapping(method = POST)
    @ModelAttribute
    @ResponseStatus(HttpStatus.CREATED)
    public MyResponse hello(@Valid MyRequest request) throws MyException {
        myService.hello(request);

        return new MyResponse();
    }


还有在HandlerExceptionResolver中处理异常,指定视图名称就可以了。
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        MyResponse myResponse = new MyResponse();
        return new ModelAndView("error").addObject(myResponse);
    }






老实说,不建议你这样做。
1、没必要搞MyRequest / MyResponse 这一套,我感觉有点多余,原生的就好,自己再封装感觉有点吃力不讨好;
2、不要再返回ModelAndView,这在Spring MVC 3中还是根据需求来。

另外,Spring MVC与Apache Tiles简直是绝配,尤其在大型复杂项目,其整合也非常简单:
	<!-- 
		Resolves logical view names returned by Controllers to Tiles; 
		a view name to resolve is treated as the name of a tiles definition 
	-->
	<bean id="tilesViewResolver" class="org.springframework.js.ajax.AjaxUrlBasedViewResolver">
		<property name="viewClass" value="org.springframework.webflow.mvc.view.FlowAjaxTilesView"/>
	</bean>

	<!-- Configures the Tiles layout system -->
	<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
		<property name="definitions">
			<list>
				<value>/WEB-INF/**/tiles-defs.xml</value>
			</list>
		</property>
	</bean>	


我贴两个例子:
@Controller
@RequestMapping(value = "/hotels")
public class HotelsController extends AbstractController {
...
	@RequestMapping(value = "/search", method = RequestMethod.GET)
	public void search(WebRequest request, Principal currentUser,
			Model model) {
		if (currentUser != null) {
			List<Booking> booking = bookingService.searchBookingsByUser(currentUser.getName());
			model.addAttribute(booking);
		}
	}
...
}

此时返回类型是void,自动使用hotels/search作为Apache Tiles的logical view name

@Controller
@RequestMapping(value = "/hotels")
public class HotelsController extends AbstractController {
...
	@RequestMapping(value = "/{id}", method = RequestMethod.GET)
	public String show(@PathVariable long id, Model model) {
		model.addAttribute(hotelService.findHotelById(id));
		return "hotels/show";
	}
...
}

此时返回类型为String,返回的hotels/show即为Apache Tiles的logical view name
0 请登录后投票
   发表时间:2010-12-07  
请教下楼主,那个acl中的preHandle如何返回是false的话,就会抛出异常。这个异常你是如何捕捉处理的并如何返回给用户的?我想是如果返回为false就返回个用户一个没有权限的提示。这个如何实现好?谢谢。
0 请登录后投票
   发表时间:2010-12-07  
maike 写道
请教下楼主,那个acl中的preHandle如何返回是false的话,就会抛出异常。这个异常你是如何捕捉处理的并如何返回给用户的?我想是如果返回为false就返回个用户一个没有权限的提示。这个如何实现好?谢谢。


返回false会抛出异常?我的验证结果是不会抛出异常,只是中止继续处理而已,表现为白屏。

对于你的情况,我的建议是:
1、确认不满足业务规则时,比如没有对应的权限,这抛出naming exception,比如AccessDeniedException,然后通过ExceptionResolver来处理:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
  <property name="exceptionMappings">
    <props>
	<prop key="com.nec.asia.nric.framework.acl.AccessDeniedException">login</prop>
    </props>
  </property>
</bean>

上述配置表明一旦出现AccessDeniedException,forward到logical name 为login的view,我用的是Apache Tiles。

2、如果不需要那么狠,这可以直接跳转,比如:
public class AclInterceptor extends HandlerInterceptorAdapter {
...
	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		if(...){
		  ...
		}else{
		  response.sendRedirect(ANOTHER_PAGE);
		  return false;
		}
		return true;
	}
...
}

0 请登录后投票
   发表时间:2010-12-15   最后修改:2010-12-15
请教一个比较初级的问题annotated controller出现以后,比如simpleFormController已经被废除了,但是我在看官方的reference(资料太少我找到的唯一资料)中,没说怎么把<form:form>中元素生成的command注入到已经为POJO的controller中,另外怎么从表单的<form:元素绑定到具体的command类,有没有例子啊,ref上写的太不清楚了。。

以前没有annotation时候是继承simpleFormController,复写一个方法,方法参数里有command,在没有继承之后怎么传啊?
0 请登录后投票
   发表时间:2010-12-16  
unsid 写道
请教一个比较初级的问题annotated controller出现以后,比如simpleFormController已经被废除了,但是我在看官方的reference(资料太少我找到的唯一资料)中,没说怎么把<form:form>中元素生成的command注入到已经为POJO的controller中,另外怎么从表单的<form:元素绑定到具体的command类,有没有例子啊,ref上写的太不清楚了。。

以前没有annotation时候是继承simpleFormController,复写一个方法,方法参数里有command,在没有继承之后怎么传啊?


ref上其实写了,但你可能一下子没找到,因为他们认为这不仅仅是web部分的技术,你可以找binding/converter之类的部分。

这部分应该说Spring做的还是挺好的,几乎做到了透明转换的程度。

废话少说,看个简单的例子吧:
<form:form modelAttribute="hotel" action="${hotelsUrl}" method="POST">
  <form:input id="name" path="name"/>
</form:form>

这个form tag加上一个modelAttribute,然后在controller中这样写:
@RequestMapping(method = RequestMethod.POST)
public String list(Hotel hotel,Model model) {
...
}


看到上面的参数hotel了吗?Spring MVC这样会自动bind这个form为controller的parameter。


大家可能会进一步问:我一个form涉及多个bean怎么办?
很简单,写一个wrapper即可,比如:
public class MutipleModelWrapper {
	private Hotel hotel;
	private Booking booking;
	
	public Hotel getHotel() {
		return hotel;
	}
	public void setHotel(Hotel hotel) {
		this.hotel = hotel;
	}
	public Booking getBooking() {
		return booking;
	}
	public void setBooking(Booking booking) {
		this.booking = booking;
	}
}

就是说,我我们的form里面可以用到Hotel、Booking两个bean,注意此时form要这样写:
<form:form modelAttribute="mutipleModelWrapper" action="${hotelsUrl}" method="POST">
  <form:input id="name" path="hotel.name"/>
  <form:input id="name" path="booking.xxx"/>
</form:form>
0 请登录后投票
   发表时间:2010-12-16  
itstarting 写道
unsid 写道
请教一个比较初级的问题annotated controller出现以后,比如simpleFormController已经被废除了,但是我在看官方的reference(资料太少我找到的唯一资料)中,没说怎么把<form:form>中元素生成的command注入到已经为POJO的controller中,另外怎么从表单的<form:元素绑定到具体的command类,有没有例子啊,ref上写的太不清楚了。。

以前没有annotation时候是继承simpleFormController,复写一个方法,方法参数里有command,在没有继承之后怎么传啊?


ref上其实写了,但你可能一下子没找到,因为他们认为这不仅仅是web部分的技术,你可以找binding/converter之类的部分。

这部分应该说Spring做的还是挺好的,几乎做到了透明转换的程度。

废话少说,看个简单的例子吧:
<form:form modelAttribute="hotel" action="${hotelsUrl}" method="POST">
  <form:input id="name" path="name"/>
</form:form>

这个form tag加上一个modelAttribute,然后在controller中这样写:
@RequestMapping(method = RequestMethod.POST)
public String list(Hotel hotel,Model model) {
...
}


看到上面的参数hotel了吗?Spring MVC这样会自动bind这个form为controller的parameter。


大家可能会进一步问:我一个form涉及多个bean怎么办?
很简单,写一个wrapper即可,比如:
public class MutipleModelWrapper {
	private Hotel hotel;
	private Booking booking;
	
	public Hotel getHotel() {
		return hotel;
	}
	public void setHotel(Hotel hotel) {
		this.hotel = hotel;
	}
	public Booking getBooking() {
		return booking;
	}
	public void setBooking(Booking booking) {
		this.booking = booking;
	}
}

就是说,我我们的form里面可以用到Hotel、Booking两个bean,注意此时form要这样写:
<form:form modelAttribute="mutipleModelWrapper" action="${hotelsUrl}" method="POST">
  <form:input id="name" path="hotel.name"/>
  <form:input id="name" path="booking.xxx"/>
</form:form>

那这样的话,原来与simpleFormController配合使用的validator怎么弄呢?
还有,前面littcai问的问题好像没有被证明解答,我也有同样疑问:
littcai 写道
请教:
与此同时出现的问题就是异常处理,好像SpringMVC在这方面支持的不够,尤其是Controller方法直接抛出异常的情况,在HTML的情况下应跳转到error页面;而在JSON请求时应返回异常的JSON格式数据。我都是扩展了源码才达到了效果
这方面你是怎么处理的?
ExceptionHandler似乎只能处理普通请求(处理方式是跳转到特定错误页面),但是对ajax请求就不行了,无法返回包含错误信息的json。
0 请登录后投票
   发表时间:2010-12-16  
itstarting 写道
unsid 写道
请教一个比较初级的问题annotated controller出现以后,比如simpleFormController已经被废除了,但是我在看官方的reference(资料太少我找到的唯一资料)中,没说怎么把<form:form>中元素生成的command注入到已经为POJO的controller中,另外怎么从表单的<form:元素绑定到具体的command类,有没有例子啊,ref上写的太不清楚了。。

以前没有annotation时候是继承simpleFormController,复写一个方法,方法参数里有command,在没有继承之后怎么传啊?


ref上其实写了,但你可能一下子没找到,因为他们认为这不仅仅是web部分的技术,你可以找binding/converter之类的部分。

这部分应该说Spring做的还是挺好的,几乎做到了透明转换的程度。

废话少说,看个简单的例子吧:
<form:form modelAttribute="hotel" action="${hotelsUrl}" method="POST">
  <form:input id="name" path="name"/>
</form:form>

这个form tag加上一个modelAttribute,然后在controller中这样写:
@RequestMapping(method = RequestMethod.POST)
public String list(Hotel hotel,Model model) {
...
}


看到上面的参数hotel了吗?Spring MVC这样会自动bind这个form为controller的parameter。


大家可能会进一步问:我一个form涉及多个bean怎么办?
很简单,写一个wrapper即可,比如:
public class MutipleModelWrapper {
	private Hotel hotel;
	private Booking booking;
	
	public Hotel getHotel() {
		return hotel;
	}
	public void setHotel(Hotel hotel) {
		this.hotel = hotel;
	}
	public Booking getBooking() {
		return booking;
	}
	public void setBooking(Booking booking) {
		this.booking = booking;
	}
}

就是说,我我们的form里面可以用到Hotel、Booking两个bean,注意此时form要这样写:
<form:form modelAttribute="mutipleModelWrapper" action="${hotelsUrl}" method="POST">
  <form:input id="name" path="hotel.name"/>
  <form:input id="name" path="booking.xxx"/>
</form:form>

感谢楼主回复,按照上面的配置方法
<form:form method="post" modelAttribute="CustomerCommand" action="/xrequirement/addcustomer.do">
我出了一个错误,说没有绑定'CustomerCommand'
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'CustomerCommand' available as request attribute
我突然想到一个问题,如果我的CustomerCommand.class在com.command.CustomerCommand,modelAttribute怎么知道去这个路径找到并实例化CustomerCommand?是不是哪还少配置了什么?
0 请登录后投票
   发表时间:2010-12-16  
to楼上,springmvc框架通过反射找到你的方法中名为CustomerCommand的参数,然后实例化、填充之
0 请登录后投票
   发表时间:2010-12-16  
daquan198163 写道
to楼上,springmvc框架通过反射找到你的方法中名为CustomerCommand的参数,然后实例化、填充之

呵呵,这个确实没这么用过。我只知道在了解CustomerCommand的全限定名com.command.CustomerCommand的时候能通过反射实例化对象,但是没听过在不知道包名com.command只知道类名CustomerCommand的情况下还能找到包名。。
0 请登录后投票
论坛首页 Java企业应用版

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