4.2.2.3.2 注解控制器
上一小结中,我们剖析了简单控制器的实现体系结构。事实上,自从Spring 2.5引进了注解方法控制器, 已经不推荐使用简单控制器的实现体系结构中的基于Form的实现类。
注解控制器是通过在一个简单的Java对象上声明具有元信息的注解来实现的。所以,注解控制器并没有接口,抽象类或者实体类的实现体系结构。然而,声明在简单的Java对象上的注解则扮演着至关重要的角色。
下面我们根据不同类型的注解进行剖析,
1. 标识控制器和控制器方法的注解
@Controller
一个注解控制器是通过注解@Controller标识的。注解@Controller比注解@Component具有更具体的语义,代表它不仅是应用程序环境中的一个Bean,而且还是一个注解控制器类型。注解@Component还有两个其他具有更具体语义的注解,@Repository和@Service。
注解@Componet和它具有更具体语义的注解都是通过XML环境中的标记<context:component-scan/>加载进入应用程序环境的。
@RequestMapping
注解控制器的处理器方法是通过注解@RequestMapping映射到一个适当的HTTP请求的。在注解@RequestMapping中,可以声明HTTP方法,HTTP参数,HTTP头信息以及更加重要的URL Pattern信息。这些信息全部是用来匹配一个HTTP请求的,如果匹配成功,则用当前声明注解@RequestMapping的处理器方法来处理当前HTTP请求。
注解@RequestMapping既能够声明在注解控制器类级别也能生命在注解控制器的处理器方法中。如果存在类级别的注解@RequestMapping,它将会结合方法级别的注解@RequestMapping一起参与匹配HTTP请求。
2. 声明初始化数据绑定方法的注解
@InitBinder
注解@InitBinder用于声明一个初始化数据绑定对象的方法,数据绑定对象用于对一个业务逻辑对象进行赋值的辅助对象。在一个处理器方法参数没有任何注解声明的时候,它就是一个需要绑定的业务逻辑对象,在调用处理器方法之前,需要使用Web数据绑定对象对此业务逻辑对象进行绑定,注解@InitBinder就是用来给Web数据绑定进行初始化的。
3. 声明模型属性相关注解
@SessionAttribute
注解@SessionAttribute可以声明保存某些模型对象到Session范围内。这些Session范围内的对象可以在接下来的请求中继续可得。
@ModelAttribute
注解@ModelAttribute有两个用途,它可以用来声明一个方法的返回值作为模型属性。它也能用来声明某个处理器方法参数能够从某个模型属性中得到期望的值。
4. 注解控制器处理器方法参数和返回值注解
前面我们已经在基于流程的剖析的章节中,对注解控制器的处理器方法的参数和返回值的注解进行了详细的分析和代码注释。这里将不再重复分析。
最后我们对一个典型的注解控制器进行分析,如下代码注释,
// 声明作为注解控制器组件
@Controller
// 映射带有模板参数的URL到所有的当前控制器的处理器方法中
@RequestMapping("/owners/{ownerId}/pets/new")
// 将pet对象存储到Session范围内
@SessionAttributes("pet")
public class AddPetForm {
// 引用持久层业务逻辑服务对象,注解控制器推荐使用控制器对持久层业务逻辑的直接调用,在不复杂的情况下,不再需要服务层和DAO层次
private final Clinic clinic;
// 自动注入持久层业务逻辑服务对象
@Autowired
public AddPetForm(Clinic clinic) {
this.clinic = clinic;
}
// 声明模型属性,这些模型属性会在视图显示中使用
@ModelAttribute("types")
public Collection<PetType> populatePetTypes() {
return this.clinic.getPetTypes();
}
// 用来初始化绑定Pet对象
@InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id");
}
// HTTP GET请求用来显示Form
@RequestMapping(method = RequestMethod.GET)
// 从路径变量中提取OWNER ID
public String setupForm(@PathVariable("ownerId") int ownerId, Model model) {
// 取得Owner信息
Owner owner = this.clinic.loadOwner(ownerId);
// 创建一个Pet对象加入到Owner中
Pet pet = new Pet();
owner.addPet(pet);
// 加Pet对象到模型中,并且Pet对象是Session属性,所以,它也会保存在Session中
model.addAttribute("pet", pet);
return "pets/form";
}
// HTTP POST请求用来创建Pet对象
@RequestMapping(method = RequestMethod.POST)
// Pet对象在显示Form的请求中存储在Session中,所以,它在模型中也是可得
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {
// 对Pet对象绑定和校验
new PetValidator().validate(pet, result);
// 如果出错继续显示Form视图
if (result.hasErrors()) {
return "pets/form";
}
// 如果成功则创建Pet对象
else {
this.clinic.storePet(pet);
// 结束一个Session周期,清楚Session中保存的属性
status.setComplete();
// 成功后显示Owner视图
return "redirect:/owners/" + pet.getOwner().getId();
}
}
}