Spring Web MVC 文档简略翻译1:简介、DispatcherServlet

Spring MVC 文档:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc


1. Spring Web MVC

1.1. 简介

Spring MVC是基于Servlet API和Spring框架构建的项目,同时,Spirng WebFlux是支持反应式web构建的框架。

1.2. DispatcherServlet

DispatcherServlet用于分发请求,实际的请求处理工作由其他组件处理。

DispatcherServlet可以使用Java代码或者在web.xml中配置。其需要处理的工作有:请求映射、视图处理、异常处理等。

如下代码是DispatcherServlet的注册和初始化,该类会自动被Servlet容器检测到。

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletCxt) {

        // Load Spring web application configuration
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        ac.register(AppConfig.class);
        ac.refresh();

        // Create and register the DispatcherServlet
        DispatcherServlet servlet = new DispatcherServlet(ac);
        ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/app/*");
    }
}

如下是web.xml中DispatcherServlet的注册和初始化配置。

<web-app>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/app-context.xml</param-value>
    </context-param>

    <servlet>
        <servlet-name>app</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>app</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>

</web-app>
1.2.1. Context层次结构

DispatcherServlet依赖WebApplicationContext进行配置。多个DispatcherServlet可以共用一个WebAplicationContext实例。Root WebApplicationContext包括数据服务bean,业务服务bean等,而Servlet WebpplicationContext仅包含特定servlet处理bean。

如下是WebApplicationContext的配置示例:

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?[] { RootConfig.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?[] { App1Config.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/app1/*" };
    }
}

如果不需要应用上下文,只需要使用getRootConfigClasses()返回配置并且getServletConfigClasses()返回null即可。

对应的web.xml如下:

<web-app>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/root-context.xml</param-value>
    </context-param>

    <servlet>
        <servlet-name>app1</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/app1-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>app1</servlet-name>
        <url-pattern>/app1/*</url-pattern>
    </servlet-mapping>

</web-app>

如果应用不需要上下文,仅需要配置root上下文并设置contextConfigLocation参数为空。

1.2.2. 特殊Bean类型

DispatcherServlet委派特殊Bean处理请求并返回相应。如下是DispatcherHandler能够检测的特殊Bean:
1.HandlerMapping:映射请求到Handler,有两个实现:RequestMappingHandlerMapping和SimpleUrlHandlerMapping。
2.HandlerAdapter:用于帮助DispatcherServlet调动handler。
3.HandlerExceptionResolver:解决映射异常,html错误视图等。
4.VieResolver:主要作用是把一个逻辑上的视图名称解析为一个真正的视图,SpringMVC中用于把View对象呈现给客户端的是View对象本身,而ViewResolver只是把逻辑视图名称解析为对象的View对象。
4.LocaleResolver、LocaleContextResolver:国际化资源处理。
5.ThemeResolver:主题处理,可以个性化主题处理。
6.MultipartResolver:处理multi-part request,如上传等。
7.FlashMapManager:存储FlashMap,用于处理重定向问题。

1.2.3. Web MVC配置

应用可以声明上述特殊bean来处理对应的请求。DispatcherServlet会检查WebApplicationContext,如果没有发现特殊bean,将返回DispatcherServlet.properties中定义的默认类型bean。

1.2.4. Servlet配置

在Servlet 3.0+环境中,支持在代码中和web.xml中配置servlet。如下是注册DispacherServlet的例子:

import org.springframework.web.WebApplicationInitializer;

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {
        XmlWebApplicationContext appContext = new XmlWebApplicationContext();
        appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");

        ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet(appContext));
        registration.setLoadOnStartup(1);
        registration.addMapping("/");
    }
}

继承WebApplicationInitializer保证你的servlet被Servlet3容器加载。AbstractDispatcherServletInitializer是WebApplicationInitializer的抽象类,它通过重写方法来简化Servlet的配置。

下面是推荐的基于Java的应用配置方法:

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { MyWebConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

如果使用基于XML的配置,就应该直接扩展AbstractDispatcherServletInitializer。

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }

    @Override
    protected WebApplicationContext createServletApplicationContext() {
        XmlWebApplicationContext cxt = new XmlWebApplicationContext();
        cxt.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
        return cxt;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

AbstractDispatcherServletInitializer也提供简单的方法添加Filer实例。

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {

    // ...

    @Override
    protected Filter[] getServletFilters() {
        return new Filter[] {
            new HiddenHttpMethodFilter(), new CharacterEncodingFilter() };
    }
}

AbstractDispatcherServletInitializer的isAsyncSupported保护方法提供 异步支持,默认设置为true。

如果想自定义DispatcherServlet,重写createDispatcherServlet方法。

1.2.5. Processing

DispatcherServlet处理请求流程如下:
1.查找WebApplicationContext并将其作为属性和请求绑定以便使用。
2.绑定local resolver到请求处理资源国际化,可以不使用。
3.绑定theme resolver到请求处理主题,可以不使用。
4.如果设定了multipart resolver并发送了multipart请求,请求的内容采用MultipartHttpServletRequest包装以便后续处理
5.查找匹配的handler,找到后顺序执行:preprocessors/postprocessors/controllers。
6.查找模型,找到则渲染视图,找不到则不渲染视图。

WebApplicationContext中的HandlerExceptionResolver用于处理异常请求。支持自定义异常处理。

DispatcherServlet也支持返回上次修改日期,其流程为:DispatcherServlet查找对应的映射处理器并检查该处理器是否实现LastModified接口,如果继承该接口,通过方法long getLastModified(request)返回上次修改时间值给客户端。

你可以通过添加Servlet初始化参数(init-param)在web.xml中自定义DispatcherServlet。下面是支持的初始化参数:
1.contexClass:继承自WebApplicationContext,实力化Servlet使用的上下文,默认使用XmlWebApplicationContext。
2.contextConfigLocation:上下文配置文件路径,支持多个路径配置多个上下文,对于在不同路径配置文件中重复定义的bean,以最后的定义为准。
3.namespace:WebApplicationContext的命名空间,默认[servlet-name]-servlet。

1.2.6. 拦截器

所有映射处理器都支持拦截器,用于对请求添加特殊处理。拦截器需要实现org.springframework.web.servlet包下的HandlerInterceptor接口的三个方法:
1.preHandler(..)-handler执行前处理
2.postHandler(..)-handler执行后处理
3.afterCompletion(..)-handler处理完成之后执行
preHandler(..)方法返回布尔值,你可以通过该函数打断或者继续handler的处理流程。true继续执行,false不继续执行接下来的拦截器或者handler。

1.2.7. 异常

如果在请求映射或者处理时发生异常,DispatcherServlet委托HandlerExceptionResolver解决异常,例如准备错误页面等。

下面是HandlerExceptionResolver的实现类:
1.SimpleMappingExceptionResolver:异常类与错误视图名称的映射,用于在浏览器中渲染错误页面。
2.DefaultHandlerExceptionResolver:处理异常并将其映射成HTTP错误码。
3.ResponseStatusExceptionResolver:使用@ResponseStatus注解处理异常并映射为HTTP错误码。
4.ExceptionHandlerExceptionResolver:在使用@Controller和@ControllerAdvice注解的类种,通过@ExceptionHandler注解处理异常。

异常处理过程:设置多个异常处理resolver,如果需要,设置resolver的优先级,优先级越高,执行的越晚。

HandlerExceptionResolver约定返回内容如下:
1.指向错误页面的ModeAndView。
2.如果异常在resolver中被处理,返回空的ModeAndView。
3.如果异常无法处理,返回null后继续下一个resolvers;如果均无法处理,异常抛给Servlet容器。

异常处理的配置就是在spring配置中添加HandlerExceptionesolver。对于Spring MVC的异常,使用@ResponseStatus注解的异常和@ExceptionHandler方法注解的异常,MVC配置自动声明内置的异常处理器。

容器中的错误页面
如果HandlerExceptionResolver依然无法处理异常或者响应错误码是4xx,5xx,Servlet容器会呈现一个错误页面。自定义容器的错误页面,需要在web.xml 中进行如下定义。

<error-page>
    <location>/error</location>
</error-page>

当由servlet容器处理异常或者错去码是4xx或者5xx时,servlet容器根据配置的 url(/error)分发错误。然后DispatcherServlet可以通过@Controller映射处理返回异常视图名称,如下:

@RestController
public class ErrorController {

    @RequestMapping(path = "/error")
    public Map<String, Object> handle(HttpServletRequest request) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("status", request.getAttribute("javax.servlet.error.status_code"));
        map.put("reason", request.getAttribute("javax.servlet.error.message"));
        return map;
    }
}
1.2.8. 视图

Spring MVC定义ViewResolver和View放假鹅口来处理视图。ViewResolver定义名和实际视图的映射,View用于展示视图之前的数据准备。下面是ViewResolver的类层次结构:
1.AbstractCachingViewResolvre:用于缓存处理的视图实例。缓存可以提升性能,可以将cache属性设置为false来关闭缓存。如果必须刷新缓存,可以调用removeFromCache(String viewName, Locale loc)方法。
2.XmlViewResolver:实现ViewResolver接口,采用xml的配置方式,默认配置文件是/WEB-INF/view.xml。
3.ResourceBundleViewResolver:实现ViewResolver接口,使用ResourceBundle读取配置文件中视图类和视图的映射关系。配置文件中配置方式为:[viewname].(class)指定视图类,[viewname].url指定视图。
4.UrlBasedViewResolver:简单实现ViewResolver接口,关联逻辑视图名与url,不使用明确的视图定义。
5.InternalResourceViewResolver:UrlBaseViewResolver的子类,支持InternalResourceView/JstlView和TilesView。
6.FreeMarkerViewResolver:UrlBasedViewResolver的子类,支持FreeMarkerView视图处理。
7.ContentNegotiatingViewResolver:实现ViewResolver接口,用于根据请求名或者Accep请求消息头类型处理视图。

处理流程:可以设置多个resolver组成视图处理链,甚至可以设置处理的优先级。记住,优先级越高,越晚执行。

ViewResolver返回null表示视图未找到。在处理jsp时,InternalResourceViewResolver一定要设置为最后处理的resolver。下文会介绍ViewResolver的配置。

重定向:
特殊的重定向:通过视图名的前缀进行重定向。UrlBaseViewResolver识别前缀然后将前缀后的内容作为重定向的地址。

控制器Controller返回RedirectView也是重定向。例如,逻辑视图名:redirect:/myapp/some/resource基于当前上下文重定向相对路径,而redirect:http://myhost.com/some/arbitrary/path基于绝对路径进行重定向。

如果控制器的方法使用@ResponseStatus注解,那么注解值优先于RedirectView设置的响应值。

转发:UrlBasedViewResolver可以根据视图名处理转发。通过创建InternalResourceView执行RequestDispatcher.forward()。这样对于InternalResourceViewResolver和InternalResourceView而言前缀失效,不进行重定向而进行转发。

内容协商:协商返回的数据格式。
ContentNegotiatingViewResolver不直接处理view,而是委托给其他符合客户端请求格式的resolver。检测Accept消息头中的数据格式或者从参数(如/path?form=pdf)中提取格式。ContentNegotiatingViewResolver通过比较media type(就是Content-Type)来选取合适的视图处理。如果没有找到对应的,使用DefaultView。Accept消息头可以设置统配,例如text/*可以匹配到text/xml的视图处理。

1.2.9. 国际化资源

DispatcherServlet支持根据客户端地区自动消息转换,这是通过LocaleResolver实现的。

请求来到时,DispatcherServlet查找对应的LocaleResolver处理国际化。使用RequestContext.getLocale()方法获取当前处理国际化resolver的地区。

LocaleContextResolver提供LocaleContext,用以获取当前client的时区。请求的时区信息开通过RequestContext.getTmeZone获取。

地区信息还可以使用Header Resolver从accept-language消息头中获取并处理
地区信息还可以使用Cookie Resolver从cookie中获取并处理。CookieLocaleResolver例子如下:

<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">

    <property name="cookieName" value="clientlanguage"/>

    <!-- in seconds. If set to -1, the cookie is not persisted (deleted when browser shuts down) -->
    <property name="cookieMaxAge" value="100000"/>

</bean>

CookieLocaleResolver属性如下:
1.cookieName:cookie名称
2.cookieMaxAge:客户端存储coodie的最大值,-1表示不存储cookie,客户端关闭browser时cookie清空。
3.cookiePath:存储cookie的地址。

SessionLocaleResolver也允许从session中获取Locale和TimeZone。该信息存储于Servlet容器的HttpSession中。

地区拦截器:通过添加LocaleChangeInterceptor处理特定映射的地区。

1.2.10. 主题

主题是一系列静态资源,如样式表、图片等。Spring MVC支持主题的更改。

定义主题:要想使用主题,必须实现org.springframework.ui.context.ThemeSource接口。WebApplicaionContext继承ThemeSource但将处理任务委派给另一个实现:org.springframework.ui.context.support.ResourceBundleThemeSource。它读取配置文件中主题的定义构建主题,配置如下:

styleSheet=/themes/cool/style.css
background=/themes/cool/img/coolBg.jpg

对于JSP,使用spring:theme自定义标签,如下:

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<html>
    <head>
        <link rel="stylesheet" href="<spring:theme code='styleSheet'/>" type="text/css"/>
    </head>
    <body style="background=<spring:theme code='background'/>">
        ...
    </body>
</html>

主题处理器有:FixedThemeResolver、SessionThemeResolver和CookieThemeResolver。提供ThemeChangeInterceptor拦截器根据请求改变主题。

1.2.11. Multipart resolver

Multipart resolver用于处理诸如上传等multipart请求。使用时需要在DispatcherServlet中定义MultipartResolver,然后会监听content-type为multipart/form-data的请求,然后解析内容并将当前的HttpServletRequest打包为MultipartHttpServletRequest以便处理。

Apache文件上传:通过配置CommonsMultipartResolver来使用Apache文件上传。需要依赖commons-fileupload包。

在Servlet3.0中,添加multipart支持需要进行注册。在web.xml中添加然后添加StandardServletMultipartResolver处理multipart类型请求。

猜你喜欢

转载自blog.csdn.net/conanswp/article/details/79774615