Spring3之MVC
模式-视图-控制器(MVC)是UI设计中常见的设计模式, 该模式区分应用程序中的模式、视图和控制器三个角色,消除了业务逻辑与UI的耦合。模式负责封装视图展示的应用数据。视图应该只显示数据,不包含任何业务逻辑。控制器负责接受用户请求并调用后端服务进行业务逻辑。处理之后,后端服务可能返回某些数据供视图显示。控制器收集这些数据并准备视图的显示模式。MVC模式的核心思想是分离业务逻辑与UI,使它们能够独立修改,互不影响。
对与Web端的开发,从最开始的CGI,model1,以及现在的由model2演化而来的Web MVC模式, 逐渐形成这三个角色的概念,servlet作为控制器,模型采用javabean的形式,而视图展示,我们常见的是jsp页面。springmvc也是服务到工作者模式的实现,DispatchServlet作为前端控制器,由处理映射器HandlerMapping管理处理器,视图解析器进行视图的管理,其还提供了强大的约定大于配置的契约式编程支持。如下图所示:
DispatcherServlet被称为调度servlet,也是所谓的前端控制器,每个web请求都会经过它,比便使它能管理整个请求处理过程。如图当一个web用户发送请求,前端控制器收到请求将其委托给其他解析器,映射处理器HandlerMapping会将请求映射成HandlerExecutionChain对象,其找到特定的页面控制器controller,而后处理适配器HandlerAdapter调用controller内的功能方法完成处理,返回一个ModelAndView对象,视图解析器ViewResolver将这种逻辑视图名转换为特定的view,view再根据model的模型数据进行渲染,最后返回给前端控制器,由其响应用户。
我们知道web程序都会有个入口点,而springmvc的核心是DispatcherServlet,其实质上也是HttpServlet的子类,该servlet默认使用WebApplicationContext作为上下文,其会引导容器加载spring的配置信息,如图一般如下:
<servlet>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
我们也可以添加该servlet的参数配置,当然spring为我们提供了默认配置,contextClass默认使用XmlApplicationContext作为WebApplicationContext的接口,contextConfigLocation指定需要加载其他配置文件的地方,默认会在classpath里寻找[servletName]-servlet.xml的文件,我们可以自己contextConfigLocation里添加配置文件指定要添加的配置信息。
简单使用:我们进行springmvc进行web开发时,一般有两种方式。
我们可以自己实现Controller接口,然后自己编写我们自己的逻辑,然后这样会很复杂。我们可以根据的自己的需求实现和修改相应的类,下图展示类的层次结构:
如上图的各个类,现在该方式不推荐使用了。spring2.5之后增加了注解功能,spring3.0以后又丰富了注解的使用,该方法已成为事实上的标准了。
我们只需要简单地添加@Controlller,@RequestMapping等就可以指定相关的设置了,当然前提是我们需要使程序认得我们的设置,通过<context:component-scan>元素开启Spring的自动检测注解的组件扫描功能,还要在上下文中注册一个DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例处理@RequestMapping注解。如下:
<context:component-scan base-package="xxx.yyy.zzz"
<context:include-filter expression="org.springframework.stereotype.Controller"
type="annotation" />
</context:component-scan>
<bean class="org.springframework.web.serlvet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
如果我们不开启组件扫描功能的话,需要在xml配置文件中,自己注入各个controller。上述配置的后两个bean,我们可以通过添加如下配置来替代他们:
<mvc:annotation-driven/>
使用注解的springmvc的controller的形式,大概如下:
@Controller
public class WelcomeController{
@RequestMapping(method=RequestMethod.GET)
public String welcome(Model model){
Date today = new Date();
model.addAttribute("today",today);
return "welcome";
}
}
我们也可以直接定义Mapping的格式为 @RequestMapping(value="/welcome",method=RequestMethod.GET)。剩下的我们再配置一个视图解析器就可以了,springmvc支持很多不同表现技术的视图,使用较多的是jsp模板。如下一个简单配置:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="suffix" value=".jsp" />
</bean>
请求映射,使用@RequestMapping注解,如下所示:
@RequestMapping("/member/add")
@RequestMapping(value={"/member/remove","/member/delete"},method=RequestMethod.GET)
@RequestMapping("/member/*") 这种一般配置Controller的。
@RequestMapping(“/member/display/{user}”) 其中user是要传入的变量,我们需要指定它如:@PathVariable("user") String user.这种方式以后传入的user变量都会代替user。
@RequestMapping(“/member/get”) 和 @RequestMapping(value="/member/get",method=RequestMethod.POST) 通过区分http不同的方法来定义不同的映射。
拦截器,拦截Web请求进行预先和事后处理, 我们可以为特定的URL映射注册处理程序拦截器,这样它只拦截映射到某些URL的请求。每个处理程序都要实现HandlerInterceptor接口,这个接口包含3个回调方法,preHandle(),postHandle(),afterCompletion()。最后一个方法是在所有请求处理完成之后(也就是显示视图之后)调用的。
如果我们实现了HandlerInterceptor接口的话,即使不需要全部方法也必须实现,因此我们可以使用继承HandlerInterceptorAdapter类来代替。这个类默认实现了所有拦截器犯法,与Java AWT的机制类似,我们需要覆盖哪个方法可以自己覆盖其内容就行了。可以将其配置和DefaultAnnotationHandlerMapping Bean放在一起就可以了。
视图解析器,我们可以在Web应用上下文声明一个或者多个视图解析器Bean,这些Bean必须实现ViewResolver接口,spring自带了很多解析器实现。
InternalResourceViewResolver 将利用前缀和后缀声明将每个视图名称映射到一个应用程序目录中。如下所示:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
这个解析器很简单,但是只能解析可内部资源视图,对于外部资源,可以它们声明为Bean,通过加载xml文件来解析的XmlViewResolver,默认加载/WEB-INF/views.xml,但是可以自己指定如:
<bean class="org.springframework.web.servlet.view.XmlViewResolver">
<value>/WEB-INF/xxx-view.xml</value>
</property>
</bean>
spring还提供了从资源集中加载视图,这样利用资源集功能从不同的资源集加载用于不同区域的视图Bean。配置如下:
<bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
</bean>
指定了资源集文件名为views.properties,在资源集中我们可以自己定义哪个页面使用哪个解析器了。文件内容大概如下:
welcome.(class)=org.springframework.web.servlet.view.JstlView
welcome.url=/WEB-INF/jsp/welcome.jsp
........
如果我们配置多个视图的话,还需要指定每个视图的优先级顺序,可通过order属性类设置,越低的顺序值代表越高的优先级。spring还提供了内容协商的视图策略,视图解析Bean为ContentNegotiatingViewResolver, 配置mediaTypes属性指定相应的视图解析器。
有时候我们需要导出Excel或者Pdf格式的文件,还需要配置特殊类型的视图解析器,SpringMVC支持Apache POI和JExcelAPI生成Excel文件,对应视图类为AbstractExcelView 和AbstractJExcelView, 支持iText程序库生成pdf文件,视图类是AbstractPdfView。
我们需要自己完成文件的创建过程,调用类库中的API编写我们自己的视图解析器类,可以使用ResourceBundleViewResolver解析器在properties文件中自定义视图解析类,还可同时使用视图内容协商方式。可在拦截器中添加文件的创建日期生成带时间的Excel或Pdf文件。
Spring还提供了标签和SpEL表达式语言,在此就不介绍了因为本人使用的少。
此外,spring还提供了区域解析器Locale resolver来识别用户区域,自带了多个该接口的实现,也可以自己创建一个区域解析器,可通过显示调用LocaleResolver.setLocale()来修改用户区域。如果我们不想为不同区域创建相同页面的不同版本,可以使用spring message来解析文本信息,jsp中使用<spring:messsage>标记来实现。spring还提供了对异常视图的解析,解析器Bean须实现HandlerExceptionResolver接口。而对于文件上传,spring提供了MultipartResolver接口,可以使用CommonsMultipartResolver,其使用Commons FileUpload类库实现。
下面介绍Springmvc常见注解及一些新特性 :
@Controller:用于标识是处理器类;
JSR-303验证框架的无缝支持(通过@Valid注解定义验证元数据);
最好的指南是spring本身的文档,建议多看看文档!