• Spring MVC使用小结


    Spring提供了一个相当灵活和可扩展的MVC实现——Spring MVC。Spring MVC框架主要由DispatcherServlet、处理器映射(handler)、处理器(controller)、视图解析器(ViewResolver)、视图(view)组成。

    Spring MVC的处理过程从一个HTTP请求开始:

      1)DispatcherServlet接收到请求后,根据对应配置文件中配置的处理器映射,找到对应的处理器映射(HandlerMapping),根据配置的映射规则,找到对应的处理器(Handler)。

      2)调用相应处理器中的处理方法,处理该请求,处理器处理结束后会将一个ModelAndView类型的数据传给DispatcherServlet,这其中包含了处理结果的视图和视图中要使用的数据。

      3)DispatcherServlet根据得到的ModelAndView中的视图对象,找到一个合适的ViewResolver(视图解析器),根据视图解析器的配置,DispatcherServlet将视图要显示的数据传给对应的视图,最后给浏览器构造一个HTTP响应。

    DispatcherServlet是整个Spring MVC的核心。它负责接收HTTP请求组织协调Spring MVC的各个组成部分。其主要工作有以下三项:

       1)截获符合特定格式的URL请求。

       2)初始化DispatcherServlet上下文对应的WebApplicationContext,并将其与业务层、持久化层的WebApplicationContext建立关联。

       3)初始化Spring MVC的各个组成组件,并装配到DispatcherServlet中。

    我们从一个多视图、多控制器的配置入手来理解Spring MVC.

    使用多视图、多控制器时,我们常采用的处理器映射是SimpleUrlHandlerMapping,并采用路径匹配算法将web请求映射到正确的处理器(handler)上。视图解析器根据使用的模板、JSP选择合适的解析器,当多个视图解析器一起使用,Spring可以组成一个视图解析链顺序查找,直到找到对应的 “视图解析器”。

    1)首先在web.xml中配置多个Dispatcher,不同的视图转发不同,如下:

    <servlet-name>sample</servlet-name>

        <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class>

    </servlet>
    <servlet-mapping>

        <servlet-name>sample</servlet-name>

        <url-pattern>/**/*.jstl</url-pattern>
    </servlet-mapping>
    <servlet-mapping>

        <servlet-name>sample</servlet-name>

        <url-pattern>/**/*.form</url-pattern>
    </servlet-mapping>

    上面的web.xml设置允许所有以.jstl和.form结尾的请求都由这个sample DispatcherServlet处理。

    2)配置处理器映射

    <beans>

        <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

            <property name="mappings">

                <value>

                    /jstl/*.form=myFormController

                    /ex/*.jstl=myJstlController

                </value>

            </property>

        </bean>

        <bean id="myJstlController" class="org.springframework.web.servlet.mvc.UrlFilenameViewController">

            <property name="validator"> <!-- 增加校验器 -->
              <bean class="sample.myJstlValidator" />
            </property>

        </bean>

        <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 

            <!-- property name="prefix"><value>/WEB-INF/sample/jsp/</value></property -->  

            <property name="suffix"><value>.jstl</value></property>  

            <property name="viewClass"><value>org.springframework.web.servlet.view.JstlView</value></property>  

       <bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">  

          <property name="suffix"><value>.form</value></property>  

          <property name="viewClass">  

                <value>org.springframework.web.servlet.view.freemarker.FreeMarkerView</value>  

          </property>  

          <property name="contentType"><value>text/html; charset=utf-8</value></property>  

    </bean>     
    </beans> 

     如果使用视图链,那么freemarker和jsp/jstl多视图配置文件如下:

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

        <property name="basename" value="views" />

        <property name="order" value="0" />

    </bean>

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

        <property name="prefix" value="/WEB-INF/sample/jsp/" />

        <property name="suffix" value=".jstl" />

    </bean>

    <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">

        <property name="templateLoaderPath">

            <value>/WEB-INF/sample/freemarker/</value>

        </property>

    </bean>

    上面配置中,ResourceBundleViewResolver设置了order属性,用于定义顺序,注意,一般将jsp处理放在视图处理链的未尾。

    ResourceBundleViewResolver还需要有它的配置文件(这里配置的是views.properties文件),并把它放置在classpath的下。views.properties文件内容如下:

        sample.(class)=org.springframework.web.servlet.view.freemarker.FreeMarkerView

        sample.url=sample.ftl

    文件内容中的sample是spring mvc返回字符串的名称,url对应freemarkerConfig中设置的templateLoaderPath下的文件路径。

     对多视图、多控制器一个更好的选择是采用注解方式配置。注解方式配置中有两个主要的类:

      DefaultAnnotationHandlerMapping,支持通过直接扫描Controller类中的Annotation来确定请求映射关系。

      AnnotationMethodHandlerAdapter,支持对某个 Controller 注册属性编辑器,包括基本数据类型及其包裹类的属性编辑器、String 属性编辑器、JavaBean 的属性编辑器等,以及注册一些自定义的属性编辑器,如时间格式编辑器等,该类在实际调用handlermethod前使用属性编辑器对其参数进行处理。 

      注解方式还有一种简写方式:<mvc:annotation-driven />。使用<mvc:annotation-driven />,Spring会自动注册DefaultAnnotationHandlerMapping 与AnnotationMethodHandlerAdapter 这两个bean。

    注:在spring mvc 3.1中,这两个Bean对应变如下: 
        DefaultAnnotationHandlerMapping -> RequestMappingHandlerMapping 
        AnnotationMethodHandlerAdapter -> RequestMappingHandlerAdapter 
        AnnotationMethodHandlerExceptionResolver -> ExceptionHandlerExceptionResolver 

    具体配置如下:

        <!-- 对web包中的所有类进行扫描,以完成Bean创建和自动依赖注入的功能 -->

        <context:component-scan base-package="sample.contoller"/>

        <!--Spring3.1开始的注解 HandlerMapping -->
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
          <property name="interceptors">       
            <list>       
              <bean class="sample.MyInteceptor"></bean>  <!-- 进行安全校验 -->
            </list>       
          </property>
        </bean>
        <!--Spring3.1开始的注解 HandlerAdapter -->
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
          <property name="webBindingInitializer">
            <bean class="sample.MyBindingInitializer"/><!-- 对参数进行格式化处理 -->
          </property>
        </bean>

    或者使用简写方式:

    <!-- 拦截器 -->  
    <mvc:interceptors> 
    <bean class="sample.MyInteceptor" />  <!-- 进行安全校验 -->
    </mvc:interceptors>
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <list> <bean class="sample.MyDataConverter" /><!-- 对参数进行格式化处理 --> </list> </property> </bean>
    <mvc:annotation-driven conversion-service="conversionService" />

    配置完成以上的文件后,我们来看看Controller的书写,Spring提供了一些关于合法的请求处理方法(见参考手册):

    1)  标准格式(跟Controller接口定义的一样)

             public ModelAndView displayCatalog(HttpServletRequest, HttpServletResponse)

    2)  下面这个方法接收Login参数,该参数中包含从请求中抽取出来的信息。

             public ModelAndView login(HttpServletRequest, HttpServletResponse, Login)

    3)   下面这个方法要求请求中已经存在合法的session对象。

    public ModelAndView viewCart(HttpServletRequest, HttpServletResponse, HttpSession)

    4)   下面这个方法接受一个Product参数,这个参数包含从请求中抽取出来的信息,并且要求请求中已经存在一个 合法的session对象。注意参数的顺序很重要:session必须是第三个参数,而绑定参数必须是final的,并位于session之后。

             public ModelAndView updateCart(HttpServletRequest, HttpServletResponse, HttpSession, Product)

    5)  下面这个方法声明返回void类型,这说明它会直接写response。

                public void home(HttpServletRequest, HttpServletResponse)

    6)  下面这个方法返回Map,表明视图解析器应该从请求中抽取视图名,而返回数据将被放入model。

              public Map list(HttpServletRequest, HttpServletResponse)

    7)可以声明自己的方法来处理请求处理过程中产生的Exceptions。该方法的签名与请求处理方法的签名类似:第一个参数必须是 HttpServletRequest,第二个参数必须是HttpServletResponse。不过与请求处理 方法不同的是,该方法的名字可以任意,具体匹配策略由该方法的第三个参数(参数类型必须是一种Exception)决定。Spring根据最接近的 异常类型进行匹配。下面是一个这种异常处理方法签名的例子:

             public ModelAndView processException(HttpServletRequest, HttpServletResponse, IllegalArgumentException)

    Spring引入Annotation来完成请求-响应的映射关系,可以让一个Controller来处理多个请求。并且SpringMVC在响应方法上,可以支持多种多样不同的参数类型和返回值类型。例如,当参数类型为Model时,SpringMVC将会自动将请求参数封装于Model内部而传入请求方法;当返回值类型是String时,直接表示SpringMVC需要返回的视图类型和视图内容。

    请求处理方法为标注了 @RequestMapping 注解的 Controller 方法,Spring MVC 允许极其灵活的请求处理方法签名方式。对于方法入参来说,它允许多种类型的入参,通过下表进行说明(参考:使用 Spring 2.5 基于注解驱动的 Spring MVC http://www.ibm.com/developerworks/cn/java/j-lo-spring25-mvc/):

    请求处理方法入参的可选类型

    说明

    Java 基本数据类型和 String

    默认情况下将按名称匹配的方式绑定到 URL 参数上,可以通过 @RequestParam 注解改变默认的绑定规则

    request/response/session

    既可以是 Servlet API 的也可以是 Portlet API 对应的对象,Spring 会将它们绑定到 Servlet 和 Portlet 容器的相应对象上

    org.springframework.web.context.request.WebRequest

    内部包含了 request 对象

    java.util.Locale

    绑定到 request 对应的 Locale 对象上

    java.io.InputStream/java.io.Reader

    可以借此访问 request 的内容

    java.io.OutputStream / java.io.Writer

    可以借此操作 response 的内容

    任何标注了 @RequestParam 注解的入参

    被标注 @RequestParam 注解的入参将绑定到特定的 request 参数上

    java.util.Map / org.springframework.ui.ModelMap

    它绑定 Spring MVC 框架中每个请求所创建的潜在的模型对象,它们可以被 Web 视图对象访问(如 JSP)

    命令/表单对象(注:一般称绑定使用 HTTP GET 发送的 URL 参数的对象为命令对象,而称绑定使用 HTTP POST 发送的 URL 参数的对象为表单对象)

    它们的属性将以名称匹配的规则绑定到 URL 参数上,同时完成类型的转换。而类型转换的规则可以通过 @InitBinder 注解或通过 HandlerAdapter 的配置进行调整

    org.springframework.validation.Errors / org.springframework.validation.BindingResult

    为属性列表中的命令/表单对象的校验结果,注意检验结果参数必须紧跟在命令/表单对象的后面

    org.springframework.web.bind.support.SessionStatus

    可以通过该类型 status 对象显式结束表单的处理,这相当于触发 session 清除其中的通过 @SessionAttributes 定义的属性

     方法返回参数,通过下表进行说明:(参考:使用 Spring 2.5 基于注解驱动的 Spring MVC http://www.ibm.com/developerworks/cn/java/j-lo-spring25-mvc/)

    请求处理方法入参的可选类型

    说明

    void

    此时逻辑视图名由请求处理方法对应的 URL 确定,如以下的方法:

    @RequestMapping("/welcome.do")
    public void welcomeHandler() {

    }

    对应的逻辑视图名为“welcome”

    String

    此时逻辑视图名为返回的字符,如以下的方法:

    @RequestMapping(method = RequestMethod.GET)
    public String setupForm(@RequestParam("ownerId") int ownerId, ModelMap model) {
      Owner owner = this.clinic.loadOwner(ownerId);
      model.addAttribute(owner);
      return "ownerForm";

    }

    对应的逻辑视图名为“ownerForm”

    org.springframework.ui.ModelMap

    和返回类型为 void 一样,逻辑视图名取决于对应请求的 URL,如下面的例子:

    @RequestMapping("/vets.do")
    public ModelMap vetsHandler() {
      return new ModelMap(this.clinic.getVets());

    }

    对应的逻辑视图名为“vets”,返回的 ModelMap 将被作为请求对应的模型对象,可以在 JSP 视图页面中访问到。

    ModelAndView

    当然还可以是传统的 ModelAndView

     我们常用的书写方式:

    @RequestMapping({"/sample/enableshop/{id}"})

    public String enableShop(HttpServletRequest request, HttpServletResponse response, @PathVariable("id")String shopId) ; //返回url地址 

    @RequestMapping({"/sample/addproduct"})

    public String addProduct(HttpServletRequest request, HttpServletResponse response, Product product) ;  //返回url地址  

     @RequestMapping(value = {"/sample/savestorestatus"}, method = {org.springframework.web.bind.annotation.RequestMethod.GET})

    public @ResponseBody String saveShopStatus(ModelMap modelMap, HttpServletRequest request, HttpServletResponse response);   

    @RequestMapping(value = {"/sample/getcurrentorders"}, method = {
                org.springframework.web.bind.annotation.RequestMethod.GET})
    public void getCurrentOrders(HttpServletRequest request, HttpServletResponse response);//可以使用Ajax方式来调用,数据采用JSON返回; 

    @RequestMapping(value = {"/sample/saveshopparams"}, method = {
                org.springframework.web.bind.annotation.RequestMethod.POST})
     public void saveShopParams(HttpServletRequest request, HttpServletResponse response) ; //可用使用Ajax方式来调用

    访问静态资源

    我们可以用Web服务器的defaultServlet来处理静态文件,也可用Spring框架来处理静态文件。使用Spring来处理,可以在配置中加入以下代码:

               <mvc:default-servlet-handler/>  

    这样spring会用默认的Servlet来响应静态文件,(DefaultServletHttpRequestHandler在容器启动是会使用主流web容器默认servlet的名称列表自动查找容器的默认servlet,包括Tomcat, Jetty, Glassfish, JBoss, Resin, WebLogic, and WebSphere。),如果为默认servlet配置了新的名称,或者这个容器servlet名字不在spring列表中是,必须显式配置默认servlet的名字,如下:
               <mvc:default-servlet-handler default-servlet-name="customServlet"/>

    或者使用mvc:resources方式来处理,如下:

             <mvc:resources mapping="/images/**" location="/images/" />  

    使用<mvc:resources/>元素把images/**映射到ResourceHttpRequestHandler进行处理,location指定静态资源的位置.可以是web application根目录下、jar包里面,这样可以把静态资源压缩到jar包中。cache-period 可以使得静态资源进行web cache 

    文件上传

    Spring是通过MultipartResolver来处理文件上传,它支持 Commons FileUpload 和 COS FileUpload。 想要使用Spring的multipart支持文件上传,首先需要在web应用的上下文中添加multipart解析器。这样,对每个请求就会检查是否包含multipart,当请求中包含multipart,上下文中定义的MultipartResolver就会解析它。

    <!-- 添加上传拦截 -->

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <property name="maxUploadSize" value="1048576"/>
            <property name="defaultEncoding" value="utf-8"/>
        </bean>

    在controller中增加处理逻辑,如下

    @RequestMapping(value = "/uploadfile", method = RequestMethod.POST)   

    public String handleFormUpload(@RequestParam("file") MultipartFile file) {   

       if (!file.isEmpty()) {   

       byte[] bytes = file.getBytes();   

       // ….

    }  

    方法验证

     如前面在controller中增加校验类sample.MyJstlValidator,该类实现了Validate接口。如果使用注解方式,则首先实现一个Validator接口的类,如下:

    @Component("myJstlValidator")

    public class MyJstlValidator implements Validator {

        @SuppressWarnings("unchecked")

        @Override

        public boolean supports(Class clazz) {

            return …;

        }

        @Override

        public void validate(Object object, Errors errors) {

            ValidationUtils.rejectIfEmpty(errors, "name","field.required");

        }

    }

    在Controller中通过注解获取:

         @Resource(name = " myJstlValidator ")

         private Validator validator;

            ...

        @RequestMapping("/jstl/save.form")

        public ModelAndView save(Product product, BindingResult result) {

            this.validator.validate(product, result);

            if (result.hasErrors()) {

                return new ModelAndView("input");

            }

             ….

         }

    国际化

    首先配置资源文件绑定

    <!-- 资源文件绑定器 -->

    <bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource">

     <property name="basename" value="i18n/Messages" />

     <property name="useCodeAsDefaultMessage" value="true" />

    </bean>

    配置好这个bean后,在JSP中设置JSTL支持的渲染器,那么在JSP文件中使用fmt标记就可以实现客户浏览器语言国际化了。如:

     <fmt:message key="sample.title" />

    其中的sample.title和你的资源文件对应.

    另外一种方式是使用spring自带的标签显示国际化信息,如:

     <spring:message code="sample.title" />

    实际操作中,针对不同语言要求进行切换的方式大多有以下几种:
    1. 根据语言种类,部署时手动替换*.properties文件
    2. 根据当前系统Locale设置,自动匹配(如上例)
    3. 根据客户浏览器语言设定,自动切换界面语种。
    前两种部署方式依赖于部署时的设定和系统环境。第三种最为灵活,系统一旦部署后,仍可自动根据客户浏览器的语言设定来自动切换语言种类。Spring中提供了以下三种语言自动切换机制的实现(均实现了LocaleResolver接口):

    1) AcceptHeaderLocaleResolver:根据浏览器Http Header中的accept-language域判定。

    2)SessionLocaleResolver:根据用户本次会话过程中的语言设定决定语言种类(一般用户在登录时选择语言种类,此后本次登录周期内统一使用该语言设定)。

    3) CookieLocaleResolver:根据Cookie判定用户的语言设定(Cookie中保存着用户前一次的语言设定参数)。

    如果改变locale设置时,需要增加LocaleChangeInterceptor拦截器,这个时候,但凡有了符合UrlMapping的请求,就会被拦截,并且开始配置国际化参数。

  • 相关阅读:
    Android监听系统短信数据库变化-提取短信内容
    Android 短信拦截及用途分析
    ListView:The content of the adapter has changed but ListView did not receive a notification终极解决方法
    Activity onDestroy() 回调缓慢问题分析及完美解决方案
    获取View的截图-将View转换为Bitmap对象
    Android正则表达式使用及性能隐患分析
    Android Activity返回键控制的两种方式
    Android TextView 添加下划线的几种方式
    android gridview几个重要属性(android:listSelector自带内部padding分析)
    ADB server didn't ACK
  • 原文地址:https://www.cnblogs.com/jevo/p/2975301.html
Copyright © 2020-2023  润新知