Spring 2.5发行版本中,开始相对比较全面的支持注解,通过注解可以大大简化Java EE应用开发的配置、精简开发人员的工作量从而提高开发效率。对于Spring MVC而言,我认为注解带来的好处更多:
1. 开发人员对Controller的代码实现变得更加灵活,不需要继承任何AbstractController等Controller。
2. 可以通过@Controller注解声明将该类的实例添加到Spring 容器中管理,而无需通过Spring MVC的配置文件来配置,大大简化了Spring MVC相关的配置量
3. 细粒度处理各种request请求,针对最基本的统一请求的GET/POST方式进行不同处理自然不在话下,还可以对拥有不同请求参数的同一request请求分别用不同的方法处理,总之就是两个字:灵活!
4. 更加丰富的参数绑定机制,你可以在你的Controller方法定义中,通过注解将某个或者某些参数直接绑定到Controller方法的参数上,从而在方法体内,你可以完全对HttpServletRequest视而不见,直接使用已经绑定好的参数。
Spring 2.5 中Web MVC的新特性带来的全新感觉还是让我们到真刀真枪的项目实践中去体会吧,这里我只做一个抛砖引玉,各位看官请跟着在下去体验一下2.5种的Controller开发流程吧。
首先,我们需要告诉Spring容器,让他知道需要把我们的Controller类加载到容器中,那么怎么做到呢?
第一, 通过以下配置启用注解
Java代码
<context:annotation-config />
<context:annotation-config />
第二, 在我们的Controller类定义之前加上@Controller注解
Java代码
@Controller
public class SimpleController {}
@Controller
public class SimpleController {}
第三, 在配置文件中添加一个类路径配置,让Spring 容器知道需要扫描该类路径下所有可以加载到容器中的类。
Java代码
<context:component-scan base-package="com.test.web" />
<context:component-scan base-package="com.test.web" />
然后,我们需要配置相应的HandlerMapping来处理类型级别的注解,例如@Controller,以及HandlerAdapter来处理方法级别的注解:
Java代码
<bean id="urlMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors" ref="interceptors" />
</bean>
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<bean id="urlMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors" ref="interceptors" />
</bean>
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
到这里,我们的准备工作已经就绪,让我们进入Controller的开发。
以下是一个简单的Controller例子,让我们跟着这个例子来了解一下如何开发Controller:
Java代码
@Controller //注释1
@RequestMapping("/menu_creator.do") //注释2
public class MenuCreaterController {
@Autowired(required = false) //注释3
private IJMSService jmsService;
@Autowired
private IMenuManager manager;
@ModelAttribute("treenodes") //注释4
public List<Menu> getMenuList() {
return manager.getMenuList();
}
/**
* Show the menu creator form page
*
* @param menu
* menu object
* @return menu_creator_view
*/
@RequestMapping(method = { RequestMethod.GET }) //注释5
public String handleShow(@ModelAttribute("menu") Menu menu) {//注释6
// menu.setParent(new Menu());
return "menu_creator_view";
}
/**
* Process the menu creating
*
* @param menu
* the menu object
* @param bindingResult
* the binding errors result
* @return a redirect view to menu_show.do
*/
@RequestMapping(method = { RequestMethod.POST })
public ModelAndView handleProcess(Menu menu, Errors bindingResult,
@RequestParam("parentid") Long parentId) { //注释7
Menu parent = new Menu();
parent.setId(parentId);
menu.setParent(parent);
manager.createMenu(menu);
if (jmsService != null)
jmsService.send();
return new ModelAndView(new RedirectView("menu_show.do"));
}
}
@Controller //注释1
@RequestMapping("/menu_creator.do") //注释2
public class MenuCreaterController {
@Autowired(required = false) //注释3
private IJMSService jmsService;
@Autowired
private IMenuManager manager;
@ModelAttribute("treenodes") //注释4
public List<Menu> getMenuList() {
return manager.getMenuList();
}
/**
* Show the menu creator form page
*
* @param menu
* menu object
* @return menu_creator_view
*/
@RequestMapping(method = { RequestMethod.GET }) //注释5
public String handleShow(@ModelAttribute("menu") Menu menu) {//注释6
// menu.setParent(new Menu());
return "menu_creator_view";
}
/**
* Process the menu creating
*
* @param menu
* the menu object
* @param bindingResult
* the binding errors result
* @return a redirect view to menu_show.do
*/
@RequestMapping(method = { RequestMethod.POST })
public ModelAndView handleProcess(Menu menu, Errors bindingResult,
@RequestParam("parentid") Long parentId) { //注释7
Menu parent = new Menu();
parent.setId(parentId);
menu.setParent(parent);
manager.createMenu(menu);
if (jmsService != null)
jmsService.send();
return new ModelAndView(new RedirectView("menu_show.do"));
}
}
注释1:@Controller注解标明该类需要Spring容器自动加载
注释2:@RequestMapping注解标识该Controller处理来自/menu_creator.do的请求
注释3:@Autowired告知Spring容器在实例化加载该Controller的时候,需要自动注入该类的jmsSevice属性值,这里默认是根据类型自动注入,也就是说在容器中查找是和该属性相同类型的实例,注入到该属性上来。而required=false表示,如果没有找到类型匹配的实例,那么就不注入这个属性的值,因为Spring 2.5中默认是required=true也就是必须找到相应的值来完成注入,否则会报异常。
注释4:@ModelAttribute属性,会将该属性标示的方法返回值作为一个Model Attribute放到Model中以供页面使用,假设一个用户注册页面中有一项选择国家,那么我们可以将国家列表通过一个单独的方法来获取,再通过@ModelAttribute注解来将其置入Model中供页面使用。这样做的好处,是将一些比较共用的页面数据,从Controller方法中分离出来,从而达到通用的目的。
注释5:此处又用了一个@RequestMapping注解,这里的这个注解是为了细粒度区分各个Controller方法,该例中针对Request的POST和GET两种方式分别通过两个方法来处理。以GET形式请求menu_creator.do那么我们返回给客户端一个用户填写交互数据的页面,而当用户点击提交按钮,则是通过POST方式提交到相同的menu_creator.do,只不过此时处理这个请求的方法变成了另外一个处理用户提交数据的Controller方法。
此外,我们注意到此处返回值是一个String类型,Spring MVC会认为这是你告诉他返回的视图名称,当然此处你也可以返回一个ModelAndView类型,假若你什么也不返回-void,那么Spring会试图查找和你的请求URL同名的视图进行匹配。
注释6:@ModelAttribute同样可以用在Controller方法的参数上,标明该参数经过处理之后,需要添加到Model数据模型中,以供View层使用。
注释7:此处参数中有一个Menu参数,Spring MVC会对Request中的Parameter参数进行绑定处理,将匹配的参数赋值到Menu的某些属性上,比如有一个参数叫做country,那么会通过Menu类中的secCountry()方法绑定到Menu参数实例中,以供方法体内使用。而@RequestParam注解标明将Request中具有某个名称的参数绑定到方法参数上,以供方法体内使用。