Spring Framework--SpringMVC(2)--Controller(1)
Controller (控制器)通过一个服务接口提供了对Web应用功能的调用;控制器解释用户的输入并把它转换成一个模型(model),通过视图(View)展现给用户。Spring实现的控制器采用的是一种抽象的方式,这样使得创建更多不同的控制器成为可能。Spring从2.5版本开始为Controller引入了基于注解的编程模型(比如:@Controller,@RequestMapping,@RequestParam,@ModelAttribute等等),这些注解支持在ServletMVC,PortletMVC框架下也是可用的。这种基于注解方式实现的控制器不需要继承特定的基类,也不需要实现特定的接口,甚至不需要依赖于Servlet和Portlet API,但是我们可以容易地配置它来访问Servlet和Portlet的功能。很多web应用都在使用这种基于注解的方式,比如:MvcShowcase, MvcAjax, MvcBasic, PetClinic, PetCare, and others.
1、使用@Controller注解定义一个控制器
使用了@Controller注解的类,表示这个类充当的是一个控制器,DispatcherServlet会扫描含有这个注解的类,并且检测映射方法。你可以在DispatcherServlet的上下文中像配置普通的bean一样显示地配置这些Controller,也可以使用Spring通用的自动检测bean功能。要使用这种自动检测bean的功能,需要在配置文件中添加自动组件扫描功能,方式是使用spring-context Schema,如:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.springframework.samples.petclinic.web"/> <!-- ... --> </beans>
2、使用@RequestMapping映射请求到一个处理器方法。
我们一般使用@RequestMapping注解来把基于URLs的请求(如:/home)映射到整个类或者类中的一个处理方法上。特别地,类级别的注解是把一个请求路径(或者路径模式)映射到一个表单控制器,然后方法级别的注解把这个主映射限制到某一个具体的http请求方法(“GET”,“POST”,etc)或者http请求参数条件。如:
@Controller @RequestMapping("/appointments") public class AppointmentsController { private final AppointmentBook appointmentBook; @Autowired public AppointmentsController(AppointmentBook appointmentBook) { this.appointmentBook = appointmentBook; } @RequestMapping(method = RequestMethod.GET) public Map<String, Appointment> get() { return appointmentBook.getAppointmentsForToday(); } @RequestMapping(value="/{day}", method = RequestMethod.GET) public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) { return appointmentBook.getAppointmentsForDay(day); } @RequestMapping(value="/new", method = RequestMethod.GET) public AppointmentForm getNewForm() { return new AppointmentForm(); } @RequestMapping(method = RequestMethod.POST) public String add(@Valid AppointmentForm appointment, BindingResult result) { if (result.hasErrors()) { return "appointments/new"; } appointmentBook.addAppointment(appointment); return "redirect:/appointments"; } }
使用类级别注解,表示在这个控制器里的所有方法注解的映射URL路径都是相对于类上面的路径,如果类上没有url路径,则方法上的url路径都是绝对路径。
在有些情况下,@RequestMapping注解需要放到接口方法上,比如在使用基于接口的JDK代理时。但是方法参数的注解(如:RequestParam)是必须要放在控制器类的方法里的。
(1)URL模版模式,如:
@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable("ownerId") String theOwner, Model model) {...}
如果方法的参数名称和路径中变量名一致,那么@PathVariable里的参数可以省略,上面方法也可以写成:public String findOwner(@PathVariable String ownerId, Model model) {...}
(2)URL模版中使用正则表达式,语法是:{varName:regex},如:
@RequestMapping("/spring-web/{symbolicName:[a-z-]}-{version:\\d\\.\\d\\.\\d}{extension:\\.[a-z]}")
public void handle(@PathVariable String version, @PathVariable String extension) {...}
(3)URL路径可以采用ant风格,?表示任意一个字符,*表示任意字符串,**表示任意路径,如:/owners/*/pets/{petId}
(4)URL中可以包含占位符,语法是${...},...表示一个本地属性,系统属性或者环境变量的值,参考:PropertyPlaceholderConfigurer
(5)URL可以包含用分号(;)分隔的键值对参数,我们称之为矩阵变量,为了映射这种路径,使用注解@MatrixVariable,如:
//一个请求: GET /owners/42;q=11/pets/21;q=22
@RequestMapping(value = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)
public void findPet(@MatrixVariable(value="q", pathVar="ownerId") int q1,@MatrixVariable(value="q", pathVar="petId") int q2) {
// q1 == 11
// q2 == 22
}
(6)通过一个请求的请求头Content-Type的值来限制请求映射到特定的方法,如下,只有当请求头的Content-Type为application/json时,才会使用这个方法处理请求。
@RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json")
public void addPet(@RequestBody Pet pet, Model model) {...}
consumes的值还可以使用取反表达式!expression,如!text/plain表示所有Content-Type不是text/plain,如果在类级别和方法级别都定义了consumes,那么以方法为准。
(7)通过一个请求的请求头Accept的值来限制请求映射到特定的方法,如下,只有当请求头的Accept为application/json时,才会使用这个方法处理请求。
@RequestMapping(value = "/pets/{petId}", method =RequestMethod.GET, produces="application/json")
@ResponseBody
public Pet getPet(@PathVariable String petId, Model model) {...}
produces的值还可以使用取反表达式!expression,如!text/plain表示所有Accept不是text/plain,如果在类级别和方法级别都定义了produces,那么以方法为准。
(8)通过URL中的参数或者请求头中的参数来限制请求映射到一个处理方法,语法为:
a. 使用URL参数:params={param condition},其中param condition为:myParam, !myParam, myParam=myValue,分别表示参数存在,不存在,或者等于某个具体的值,如:
@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {
@RequestMapping(value = "/pets/{petId}", method =RequestMethod.GET, params="myParam=myValue")
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {...}
}
b. 使用请求头中的参数:headers={header condition},其中header condition为:myHeader, !myHeader, myHeader=myValue,分别表示参数存在,不存在,或者等于某个具体的值,如:
@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {
@RequestMapping(value = "/pets", method =RequestMethod.GET, headers="myHeader=myValue")
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {...}
}