在构建springmvc+mybatis项目时,更常用的方式是采用web.xml来配置,而且一般情况下会在web.xml中使用ContextLoaderListener加载applicationContext-*.xml,在DispatcherServlet中配置${servlet-name}-servlet.xml。

但是实际上除了采用xml方式,在springmvc+mybatis项目中也可以采用纯代码+注解方式来替换web.xml、applicationContext-*.xml、${servlet-name}-servlet.xml。

下边我们先展示下采用web.xml配置方式,后边讲解如何使用代码+注解方式来替换的方案(所有代码请参考:https://github.com/478632418/springmv_without_web_xml/tree/master/test-pro-02)。

SpringMVC+Mybatis采用web.xml整合

/WEB-INF/web.xml配置

在/WEB-INF/web.xml中一般需要配置两个部分主要内容:ContextLoaderListener、DispatcherServlet。

一般web.xml配置信息如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
id="WebApp_ID" 
version="3.1">
  
  <!-- 加载spring容器 -->
  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
      <!-- 文件上传与下载过滤器:form表单中存在文件时,该过滤器可以处理http请求中的文件,被该过滤器过滤后会用post方法提交,form表单需设为enctype="multipart/form-data"-->
    <!-- 注意:必须放在HiddenHttpMethodFilter过滤器之前 -->
    <filter>
        <filter-name>multipartFilter</filter-name>
        <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
        <init-param>
            <param-name>multipartResolverBeanName</param-name>
            <!--spring中配置的id为multipartResolver的解析器-->
            <param-value>multipartResolver</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>multipartFilter</filter-name>
        <!--<servlet-name>springmvc</servlet-name>-->
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--
    注意:HiddenHttpMethodFilter必须作用于dispatcher前
    请求method支持 put 和 delete 必须添加该过滤器
    作用:可以过滤所有请求,并可以分为四种
    使用该过滤器需要在前端页面加隐藏表单域
    <input type="hidden" name="_method" value="请求方式(put/delete)">
    post会寻找_method中的请求式是不是put 或者 delete,如果不是 则默认post请求
    -->
    <filter>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <!--servlet为springMvc的servlet名 -->
        <servlet-name>springmvc</servlet-name>
        <!--可以通过配置覆盖默认'_method'值 -->
        <init-param>
            <param-name>methodParam</param-name>
            <param-value>_method</param-value>
        </init-param>
        <!--<url-pattern>/*</url-pattern>-->
    </filter-mapping>
    <!--结束后端数据输出到前端乱码问题-->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <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>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
  <!-- springmvc前端控制器 -->
  <servlet>
      <servlet-name>springmvc</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:springmvc-servlet.xml</param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
  </servlet-mapping>    
  <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.js</url-pattern>
  </servlet-mapping>
</web-app>

备注:

1)上边关于spring的ApplicationContext配置有两处:ContextLoaderListener、DispatcherServlet,一般理解为:ContextLoaderListener为spring的parent ApplicationContext,DispatcherServlet为spring的child ApplicationContext。

2)ContextLoaderListener与DispatcherServlet所创建的上下文ApplicationContext的区别:

  1. ContextLoaderListener中创建ApplicationContext主要用于整个Web应用程序需要共享的一些组件,比如DAO,数据库的ConnectionFactory、multipartResolver等。而由DispatcherServlet创建的ApplicationContext主要用于和该Servlet相关的一些组件,比如Controller、ViewResovler等。
  2. 对于作用范围而言,在DispatcherServlet中可以引用由ContextLoaderListener所创建的ApplicationContext,而反过来不行。
  3. 为什么multipartResolver需要配置在ContextLoaderListener的applicationContext.xml?具体可以查看MultipartFilter中的代码:
    public class MultipartFilter extends OncePerRequestFilter {
    
        /**
         * The default name for the multipart resolver bean.
         */
        public static final String DEFAULT_MULTIPART_RESOLVER_BEAN_NAME = "filterMultipartResolver";
    
        private final MultipartResolver defaultMultipartResolver = new StandardServletMultipartResolver();
    
        private String multipartResolverBeanName = DEFAULT_MULTIPART_RESOLVER_BEAN_NAME;
    
    
        /**
         * Set the bean name of the MultipartResolver to fetch from Spring's
         * root application context. Default is "filterMultipartResolver".
         */
        public void setMultipartResolverBeanName(String multipartResolverBeanName) {
            this.multipartResolverBeanName = multipartResolverBeanName;
        }
    
        /**
         * Return the bean name of the MultipartResolver to fetch from Spring's
         * root application context.
         */
        protected String getMultipartResolverBeanName() {
            return this.multipartResolverBeanName;
        }
    
    
        /**
         * Check for a multipart request via this filter's MultipartResolver,
         * and wrap the original request with a MultipartHttpServletRequest if appropriate.
         * <p>All later elements in the filter chain, most importantly servlets, benefit
         * from proper parameter extraction in the multipart case, and are able to cast to
         * MultipartHttpServletRequest if they need to.
         */
        @Override
        protected void doFilterInternal(
                HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
                throws ServletException, IOException {
    
            MultipartResolver multipartResolver = lookupMultipartResolver(request);
    
            HttpServletRequest processedRequest = request;
            if (multipartResolver.isMultipart(processedRequest)) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Resolving multipart request");
                }
                processedRequest = multipartResolver.resolveMultipart(processedRequest);
            }
            else {
                // A regular request...
                if (logger.isTraceEnabled()) {
                    logger.trace("Not a multipart request");
                }
            }
    
            try {
                filterChain.doFilter(processedRequest, response);
            }
            finally {
                if (processedRequest instanceof MultipartHttpServletRequest) {
                    multipartResolver.cleanupMultipart((MultipartHttpServletRequest) processedRequest);
                }
            }
        }
    
        /**
         * Look up the MultipartResolver that this filter should use,
         * taking the current HTTP request as argument.
         * <p>The default implementation delegates to the {@code lookupMultipartResolver}
         * without arguments.
         * @return the MultipartResolver to use
         * @see #lookupMultipartResolver()
         */
        protected MultipartResolver lookupMultipartResolver(HttpServletRequest request) {
            return lookupMultipartResolver();
        }
    
        /**
         * Look for a MultipartResolver bean in the root web application context.
         * Supports a "multipartResolverBeanName" filter init param; the default
         * bean name is "filterMultipartResolver".
         * <p>This can be overridden to use a custom MultipartResolver instance,
         * for example if not using a Spring web application context.
         * @return the MultipartResolver instance
         */
        protected MultipartResolver lookupMultipartResolver() {
            WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
            String beanName = getMultipartResolverBeanName();
            if (wac != null && wac.containsBean(beanName)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Using MultipartResolver '" + beanName + "' for MultipartFilter");
                }
                return wac.getBean(beanName, MultipartResolver.class);
            }
            else {
                return this.defaultMultipartResolver;
            }
        }
    
    }
    View Code

相关文章: