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-name>spring</servlet-name>
        <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"

        use-default-filters="false">
        <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

    @RequestMapping("/welcome")
    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="prefix" value="/WEB-INF/jsp/" />
     <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="order" value="2" />
          <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">

        <property name="location">
                    <value>/WEB-INF/xxx-view.xml</value>
        </property>

    </bean> 

spring还提供了从资源集中加载视图,这样利用资源集功能从不同的资源集加载用于不同区域的视图Bean。配置如下:

 <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver">

            <property name="basename" value="views"/>
    </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:用于标识是处理器类;

@RequestMapping:请求到处理器功能方法的映射规则;
@RequestParam:请求参数到处理器功能处理方法的方法参数上的绑定;
@ModelAttribute:请求参数到命令对象的绑定;
@SessionAttributes:用于声明session级别存储的属性,放置在处理器类上,通常列出模型属性(如@ModelAttribute)对应的名称,则这些属性会透明的保存到session中;
@InitBinder:自定义数据绑定注册支持,用于将请求参数转换到命令对象属性的对应类型;
@CookieValue:cookie数据到处理器功能处理方法的方法参数上的绑定;
@RequestHeader:请求头(header)数据到处理器功能处理方法的方法参数上的绑定;
@RequestBody:请求的body体的绑定(通过HttpMessageConverter进行类型转换);
@ResponseBody:处理器功能处理方法的返回值作为响应体(通过HttpMessageConverter进行类型转换);
@ResponseStatus:定义处理器功能处理方法/异常处理器返回的状态码和原因;
@ExceptionHandler:注解式声明异常处理器;
@PathVariable:请求URI中的模板变量部分到处理器功能处理方法的方法参数上的绑定,从而支持RESTful架构风格的URI;

JSR-303验证框架的无缝支持(通过@Valid注解定义验证元数据);

ConversionService进行类型转换(PropertyEditor依然有效),支持使用@NumberFormat 和 @DateTimeFormat来进行数字和日期的格式化;
HttpMessageConverter(Http输入/输出转换器,比如JSON、XML等的数据输出转换器);
ContentNegotiatingViewResolver,内容协商视图解析器,它还是视图解析器,只是它支持根据请求信息将同一模型数据以不同的视图方式展示(如json、xml、html等),RESTful架构风格中很重要的概念(同一资源,多种表现形式);
<mvc:annotation-driven>:自动注册基于注解风格的处理器需要的DefaultAnnotationHandlerMapping、AnnotationMethodHandlerAdapter
<mvc:interceptors>:注册自定义的处理器拦截器;
<mvc:view-controller>:和ParameterizableViewController类似,收到相应请求后直接选择相应的视图;
<mvc:resources>:逻辑静态资源路径到物理静态资源路径的支持;
<mvc:default-servlet-handler>:当在web.xml 中DispatcherServlet使用<url-pattern>/</url-pattern> 映射时,能映射静态资源(当Spring Web MVC框架没有处理请求对应的控制器时(如一些静态资源),转交给默认的Servlet来响应静态文件,否则报404找不到资源错误,)。

  最好的指南是spring本身的文档,建议多看看文档! 

posted on 2013-06-29 20:45  糊涂先生  阅读(685)  评论(0编辑  收藏  举报