这个例子是来自于Gary Mak等人写的Spring攻略(第二版)第八章Spring @MVC中的一个例子,在此以学习为目的进行记录。
问题:想用Spring MVC开发一个简单的Web应用, 学习这个框架的基本概念和配置。
解决方案:
Spring MVC的核心组件是一个控制器(大多数框架都是控制器比较重要吧)。
在最简单的Spring MVC应用中,控制器是需要在web.xml文件中配置的唯一Servlet。
Spring MVC的控制器通常称作请求分发Servlet(Dispatcher Servlet),实现了Java EE设计模式中的前端控制器(Front controller)。
每个web请求都要经过这个前端控制器,以便它能够管理整个请求处理过程。
当一个web请求发送给Spring MVC应用,控制器首先接受这个请求,然后控制器组织处理该请求的组件。
在Spring 3.0中定义一个控制器类,必须以@Control注解标记。(不理解注解是个啥)在以前则是要通过实现框架专有的接口或者扩展框架专用的基类,3.0以后就只用添加注解了。
加上了@Controller注解的类(也就是控制器类),就回去找人(合适的处理程序方法)来处理请求。
用@RequestMapping注解修饰的控制器方法就成为处理程序的方法。
这些处理程序方法的签名就像任何标准类里的方法一样,可以任意修改。同时处理程序方法也可以根据应用逻辑返回一系列值。
在处理程序结束请求处理之后,便将控制委托给视图,这个视图来处理程序方法的返回值,视图可以是多种形式。
为了从控制器传递信息给视图,处理程序的方法返回一个逻辑视图名称,String或者void是无关紧要的,因为处理程序的输入参数可以为视图所用。
当控制器类接受一个视图时,它依靠视图解析器将逻辑视图名称解析为具体的视图实现(例如user.jsp)。
视图解析器是web应用上下文中配置的一个实现ViewResolver接口的Bean,其任务是返回逻辑名称视图的具体实现。
视图的作用是将处理程序方法的逻辑中添加的对象显示给用户。
工作原理:
一个简单的web应用实例——开发一个球场预定系统。
首先在domain子包中建立如下三个类:
第一个是预定类,Reservation.java
第二个是预定者,Player.java
第三个是运动类型,SportType.java
在service子包中定义如下的服务接口:ReservationService.java,为表现层提供预定服务。
用包含硬编码添加几个预定订单的类来实现这个接口,即ReservationServiceImpl.java。生产中应该用数据库持续性来实现这个接口。
设置Spring MVC应用
创建一个Spring MVC应用布局和标准的Java Web应用相同,但是例外的是必须添加一些Spring MVC专用的配置文件和必须的库程序。
用户可以通过URL直接访问到WEB-INF目录之外的文件,所以CSS文件和图像必须放在那里,使用Spring MVC时,JSP文件起着模板的作用。
框架读取JSP文件用于生成动态内容,所以JSP必须在WEB-INF目录内,避免直接访问。
创建配置文件
web.xml是Java Web必不可少的配置文件,在这里为应用程序定义Servlet以及Web请求到这些Servlet的映射方式。
对于Spring MVC应用,只需要定义一个DispatcherServlet实例,作为前端控制器,如果需要的话也可以定义多个。
在大型应用中,使用多个DispatcherServlet实例可能更加方便,可将DispatcherServlet实例指派给特定的URL。
DispatcherServlet名称的另一个目的就是让DispatcherServlet决定加载哪个Spring MVC配置文件。
默认情况查找的文件名是servlet名加上-servlet.xml文件。
当然也可以在Servlet参数contextConfigLocation中明确指定一个配置文件。
如上court-servlet.xml是一个标准的Spring bean配置文件。
每一层声明一个Bean配置文件(例如持续层court-persistence.xml和服务层的court-service.xml)。
为了让Spring加载court-servlet.xml之外的配置文件,就必须要在web.xml中定义servlet监听器ContextLoaderListener。
(这配置文件把头的搞晕了,不适合我这双商低的弱势群体啊!)
ContextLoaderListener加载指定的Bean配置文件到根应用的上下文中,而每个DispatcherServlet将其配置文件加载到自己的应用上下文,并且引用根应用上下文为期上下级。
所以每个DispatcherServlet实例加载的上下文可以访问甚至覆盖根应用的上下文声明中的Bean(反之则不行)。
(这里讲的是啥啊,啥啥啥。根应用上下文和自己的应用上下文?局部变量覆盖了全局变量?)
激活Spring MVC注解扫描
(开雷达了?)
在创建控制器类之前,要在配置web应用,使其扫描各个类来确定@Controller和@RequestMapping注解的存在。
只有带有这些注解的类能够像控制器一样操作。
首先,要让Spring自动监测注解,必须通过<context:component-scan>元素启用Spring的组件扫描功能。
除了这个之外,Spring MVC的@RequestMapping注解将URL请求映射到控制器类及其对应的处理方法,这就需要在Web应用上下文有更多的声明。
在Web应用上下文注册一个DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例。
上面两个实例分别在类级别和方法级别处理@RequestMapping注解。
创建Spring MVC控制器
基于注解的控制器类可以是任意的类,不用实现特殊的接口或扩展特殊的基类。
可以用@Controller注解这种类。控制器中可以定义一个或者多个处理程序方法来处理一个或者多个动作。
@RequestMapping注解可以应用到类级别或者方法级别。
@RequestMapping注解还可以包含属性。
这个类中使用的第一个值("/welcome")用于指定体现控制器操作的URL,意味着/welcome URL接受的请求由WelcomeController类处理。
一旦控制器开始处理请求,它将调用委派给控制器中声明的默认HTTP GET处理程序方法。
这是因为对URL的每个初始请求都是HTTP GET类型。
所以当控制器处理对/welcome URL请求时,请求随后被委派到默认的HTTP GET处理程序方法处理。
@RequestMapping(method=RequestMethod.GET)注解用于将welcome方法装饰成控制器默认的HTTP GET处理程序方法。
新增加了赋予类的构造程序@Autowired注解,这个注解允许类的构造程序从应用配置文件court-service.xml中声明实例化其字段。
@Autowired注解不需要使用XML注入属性。
@RequestMapping("/reservationQuery")语句指出,URL/reservationQuery上的任何请求都又该控制器处理。
一个类级别的注解对应了两个处理程序方法,一个方法在/reservationQuery URL上的HTTP GET请求时发生,而另一个方法是在HTTP POST请求发生时调用。
Web应用中大部分请求是HTTP GET,HTTP POST请求一般在用户提交HTML表单时发出。
@RequestParam("courtName") String courtName声明,用于提取名为courtName的请求参数。
另外一个是Model声明,用于定义向返回视图传递数据的对象。
创建JSP视图
在Spring MVC中,视图常常是JSTL编写的JSP模板。当应用的web.xml文件中定义的DispatcherServlet接收到处理程序返回的视图名称,它将逻辑视图名称解析为视图实现以供显示。
部署web应用