Spring笔记(Spring MVC)

每当用户在 WEB 浏览器中点击链接或提交表单的时候,请求就开始工作了。请求从俩开浏览器开始到获取响应返回,它会经历好多站,并在每站都会留下一些信息同时带上其它信息,下图展示了请求使用 Spring MVC 所经历的所有站点。
在这里插入图片描述
图释:

  • 在请求离开浏览器时,会带有用户所请求内容的信息,至少会包含请求的 URL,但是还可能带有其它的信息,例如用户提交的表单信息。
  • 请求的旅程第一站是 Spring 的 DispatcherServlet 前端控制器,DispatcherServlet 的任务是将请求发送给 Spring MVC 控制器,控制器是一个用于处理请求的 Spring 组件。在普通的引用程序中可能有多个控制器,DispatcherServlet 需要知道应该讲请求发送到哪个控制器,所以 DispatcherServlet 会查询一个或多个 处理器映射 来确定请求的下一站是在哪里。
  • 一旦选择了合适的控制器,DispatcherServlet 会将请求发送给选中的控制器,到了控制器,请求会卸下其负载(用户提交的信息)并耐心等待控制器处理这些信息(实际上,设计良好的控制器本身只处理很少甚至不处理工作,而是将业务逻辑委托给一个或多个 服务对象 进行处理
  • 控制器砸IWC逻辑处理后,通常会产生一些信息,这些信息需要返回给用户并在浏览器上显示,这些消息被称为 模型(model),有时候给用户返回信息是不够的,这些信息需要以用户友好的方式进行格式化,所以,信息需要发送给一个 视图(veiw),通常会是 JSP,以上就是 MVC 的命名由来了。
  • 如果需要使用视图包装,控制器所做的最后一件事就是将模型数据打包,并且表示出用于渲染输出的视图名,然后会将 请求连同模型和视图名 发送回 DispatcherServlet。
  • DispatcherServlet 将会使用 视图解析器 来讲逻辑视图名匹配为一个特性的视图实现,最后视图将使用模型数据渲染输出,这个输出会通过响应对象传递给客户端。

1 搭建 Spring MVC 配置

1.1 使用 XML 文件配置

1.1.1 两个应用上下文

在配置之前,需要先理解 DispatcherServlet 和一个 Servlet 监听器(也就是 ContextLoaderListener)的关系:
当 DispatcherServlet 启动的时候,它会创建 Spring 应用上下文,并加载配置文件或配置类中所声明的 bean。但是在 Spring Web 应用中,通常还会有另外一个应用上下文,这个应用上下文就是有 ContextLoaderListener 创建的。
我们希望的是 DispatcherServlet 加载包含 Web 组件的 bean,如 控制器、视图解析器以及处理器映射,而 ContextLoaderListener 要加载应用中的其他 bean,这些 bean 通常是驱动应用后端的 中间层和数据层组件

1.1.2 web.xml 文件

在典型的 Spring MVC 应用中,会需要到 DispatcherServlet 和 ContextLoaderListener,如下是一个基本的 web.xml 文件,它按照传统的方式搭建了 DispatcherServlet 和 ContextLoaderListener

<web-app version="3.0" 
	xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

	<!-- 设置 ContextLoaderListener 根上下文设置文件位置 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring/applicationContext.xml</param-value>
	</context-param>

	<!-- 注册 ContextLoaderListener -->
	<listener>
		<listener-class>
			org.spirngframework.web.context.ContextLoaderListener
		</listener-class>
	</liestender>

	<!-- 注册 DispatcherServlet -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServelt
		</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>			
			<param-value>
				classpath:spring/dispatcher-servlet.xml
			</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	
	<!-- 将 DispatcherServlet 映射到 “/” -->
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-parrten>
	</servlet-mapping>
</web-app>

DispatcherServlet 从 dispatcher-servlet.xml 文件中加载应用上下文,这里主要包括控制器、视图解析器以及处理器映射等,如:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
	http://www.springframework.org/schema/mvc
	http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 自动扫描该包,使SpringMVC认为包下用了@controller注解的类是控制器 -->
    <context:component-scan base-package="cn.seiei.controller" />

    <!-- <mvc:annotation-driven>会自动注册RequestMappingHandlerMapping与RequestMappingHandlerAdapter两个Bean,
            这是Spring MVC为@Controller分发请求所必需的, 并且提供了数据绑定支持, @NumberFormatannotation支持,
            @DateTimeFormat支持, @Valid支持读写XML的支持(JAXB)和读写JSON的支持(默认Jackson)等功能。 要使用spring
            mvc中的@Controller注解,就必须要配置<mvc:annotation-driven />, 否则org.springframework.web.servlet.DispatcherServlet无法找到控制器并把请求分发到控制器。 -->
    <mvc:annotation-driven />
    
    <!-- 以下两个 Bean 用于收,发 json 数据,支持 @RequestBody 注释将json对象转换为 java 对象 -->
    <bean id="jsonHttpMessageConverter"
          class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <property name="supportedMediaTypes">
            <list>
                <value>application/json;charset=UTF-8</value>
            </list>
        </property>
    </bean>
    <!-- org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter 已经废弃了 -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="jsonHttpMessageConverter" />
            </list>
        </property>
    </bean>

    <!-- 文件上传 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760"/> <!-- 指定所上传文件的总大小不能超过10M。注意maxUploadSize属性的限制不是针对单个文件,而是所有文件的容量之和 -->
        <property name="maxInMemorySize" value="4096" />
        <property name="defaultEncoding" value="UTF-8"></property>
    </bean>

    <!-- 定义跳转的文件的前后缀 ,配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->
        <!-- 这里的路径根目录是 webapp -->
        <property name="prefix" value="/" />
        <property name="suffix" value=".html" />
    </bean>

</beans>

ContextLoaderListener 从 applicationContext.xml 文件中加载应用上下文,这里包括配置文件的导入,以及其他如服务层,数据层等组件的配置文件,如:

<?xml version="1.0" encoding="UTF-8"?>
<beans
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context.xsd">
	
	<!-- spring 根应用上下文文件 -->
	<context:component-scan base-package="cn.seiei" annotation-config="true"/>
	
	<!-- 扫描配置文件 -->
	<context:property-placeholder location="classpath:properties/*.properties"/>
	
	<!-- 导入其余应用上下文文件 -->
	<import resource="classpath:spring/applicationContext-*.xml"/>
</beans>

1.2 使用 JavaConfig 配置

按照传统的方式,像 DispatcherServlet 这样的 Servlet 会配置在 web.xml 文件中,但是借助于 Servlet3 规范和 Spring 3.1 的功能增强我们还可以使用 Java 将 DispatcherServlet 配置在 Servlet 容器中,而不会再使用 web.xml 文件。
具体方法就是编写一个扩展了 AbstractAnnotationConfigDispatcherServletInitializer 的任意类都会 自动地配置 到 DispatcherServlet 和 Spring 应用上下文,扩展这个类很简单,只需要重写三个方法,如:

public class WebAppInititalizer extends AbstractAnnotationConfigDispatcherServletInitializer {
    /**
     * 指定 ContextLoaderListener 加载应用上下文的配置类
     * @return
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { RootConfig.class };
    }

    /**
     * 指定 DispatcherServlet 加载应用上下文的配置类
     * @return
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebConfig.class };
    }

   	/**
     * 用于将 DispatcherServlet 映射到“/”上
     * @return
     */
    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};
    }
}

1.2.1 DispatcherServlet 配置类

正如上述注释所说的 getServletConfigClasses 方法用于指定 DispatcherServlet 加载应用上下文的配置类,即导入的 WebConfig 配置类就是指定 DispatcherServlet 加载应用上下文的配置类,在使用 XML 进行配置的时候,使用的是 <mvc:annotation-driven> 启动注解驱动的 Spring MVC。在这里就可以使用 @EnableWebMvc 注释来启动注解驱动了。具体例子如:

/**
 * 该类是用于加载 DispatcherServlet 应用上下文的配置类
 * 在使用 XML 配置的时候,可以使用声明 <mvc:annotation-driven> 来启动注解驱动的 Spring MVC
 * 在 JavaConfig 配置中,可以使用 @EnaleWebMvc 来启动 Spring MVC
 *
 * 本类包含:
 * - 配置视图解析器
 * - 扫描加载应用中的控制器组件
 * - 配置静态资源的处理:扩展 WebMvcConfigurerAdapter 并重写了 configureDefaultServeltHandling 方法
 */
@Configuration
@EnableWebMvc // 启动 Spring Mvc
@ComponentScan("top.seiei.controller") // 启动组件扫描,导入控制器
public class WebConfig extends WebMvcConfigurerAdapter {

    /**
     *  配置 JSP 视图解析器
     */
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/");
        resolver.setSuffix(".html");
        resolver.setExposeContextBeansAsAttributes(true);
        return resolver;
    }

    /**
     *  以下两个 Bean 用于收,发 json 数据,支持 @RequestBody 注释将json对象转换为 java 对象
     */
    @Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        List<MediaType> supportedMediaTypes = new ArrayList<>();
        supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
        mappingJackson2HttpMessageConverter.setSupportedMediaTypes(supportedMediaTypes);
        return mappingJackson2HttpMessageConverter;
    }
    @Bean
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter(MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter) {
        RequestMappingHandlerAdapter requestMappingHandlerAdapter = new RequestMappingHandlerAdapter();
        List<HttpMessageConverter<?>> httpMessageConverters = new ArrayList<>();
        httpMessageConverters.add(mappingJackson2HttpMessageConverter);
        requestMappingHandlerAdapter.setMessageConverters(httpMessageConverters);
        return requestMappingHandlerAdapter;
    }

    /**
     * 文件上传
     */
    @Bean("multipartResolver")
    public CommonsMultipartResolver commonsMultipartResolver() {
        CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
        commonsMultipartResolver.setMaxUploadSize(10485760);
        commonsMultipartResolver.setMaxInMemorySize(4096);
        commonsMultipartResolver.setDefaultEncoding("UTF-8");
        return commonsMultipartResolver;
    }

    /**
     * 配置静态资源的处理
     * 通过调用 DefaultServletHandlerConfigurer 的 enable 方法
     * 会使 DispathcerServlet 将对静态资源的请求转发到 Servlet 容器中默认的 Servlet 上
     * 而不是使用 DispatcherServlet 本身来处理此类请求
     */
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

1.2.2 ContextLoaderListener 配置类

正如上述注释所说的 getRootConfigClasses 方法用于指定 ContextLoaderListener 加载应用上下文的配置类,具体例子如:

/**
 * 该类是用于加载 ContextLoaderListener 应用上下文的配置类
 *
 * 本类包括:
 * - 导入其它应用上下文的配置文件
 * - 导入 .properties 的文件
 * - 扫描加载应用中的其他 bean,如中间层和数据层组件
 */
@Configuration
@PropertySource("classpath:properties/jdbc.properties") // 导入 .properties 文件
/*@ComponentScan("top.seiei") // 启动组件扫描*/
public class RootConfig {
    
}

1.2.3 使用 web.xml 加载 JavaConfig

不扩展 AbstractAnnotationConfigDispatcherServletInitializer 也是可以使用 web.xml 文件导入 JavaConfig 配置,如:

<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <display-name>ssmDemo</display-name>

    <!-- 声明使用 JavaConfig 配置 -->
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </context-param>
    <!-- 指定 ContextLoaderListener 应用上下文配置类 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>top.seiei.springMvcConfig.RootConfig</param-value>
    </context-param>
    
    <!-- 防止Spring内存溢出监听器,应该配置在web.xml中与Spring相关监听器中的第一个位置 -->
    <listener>
        <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
    </listener>

    <!-- Spring监听器,在启动Web容器时,自动装配Spring applicationContext.xml的配置信息 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- 编码过滤器 -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <async-supported>true</async-supported>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 主要让浏览器不支持put,delete等方法的form表单可以支持这些方法 -->
    <filter>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 对客户端请求的静态资源如图片、JS文件等的请求交由默认的servlet进行处理 -->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.jpg</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.js</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.css</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.png</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.gif</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.ttf</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.woff</url-pattern>
    </servlet-mapping>

    <!-- 配置springmvc的前端调度器,配置位置比资源过滤器的位置要后 -->
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 声明使用 JavaConfig 配置 -->
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
        </init-param>
        <!-- 指定 DispatcherServlet 配置类 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>top.seiei.springMvcConfig.WebConfig</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <!-- 拦截所有 -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值