美文网首页
(一)helloworld、组件、架构

(一)helloworld、组件、架构

作者: guideEmotion | 来源:发表于2019-06-09 19:37 被阅读0次

    一 创建项目

    1. 用idea创建一个maven项目,选择maven-archetype-webapp,最后自己添加java和resouces两个目录
    2. pom引入maven依赖
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
    
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>4.2.6.RELEASE</version>
          <exclusions>
            <exclusion>
              <artifactId>commons-logging</artifactId>
              <groupId>commons-logging</groupId>
            </exclusion>
          </exclusions>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>4.2.6.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>4.2.6.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>4.2.6.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>4.2.6.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>com.github.stefanbirkner</groupId>
          <artifactId>system-rules</artifactId>
          <version>1.16.1</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjweaver</artifactId>
          <version>1.8.9</version>
        </dependency>
    
        <!--日志-->
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
          <version>1.7.13</version>
        </dependency>
        <!--logback-classic依赖logback-core,会自动级联引入-->
        <dependency>
          <groupId>ch.qos.logback</groupId>
          <artifactId>logback-classic</artifactId>
          <version>1.2.3</version>
        </dependency>
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-jcl</artifactId>
          <version>1.7.25</version>
        </dependency>
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>jcl-over-slf4j</artifactId>
          <version>1.8.0-beta2</version>
        </dependency>
    
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.9.8</version>
        </dependency>
    
      </dependencies>
    
    1. 配置spring mvc的配置文件
    <?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"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
        <context:component-scan base-package="com.zyc.controller"/>
        <mvc:annotation-driven />
    </beans>
    
    1. 配置web.xml
    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
    
    
      <!-- 配置前端控制器 -->
      <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
          <!-- 指定springmvc配置文件的路径。如果不指定,默认为:/WEB-INF/${servlet-name}-servlet.xml -->
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:springmvc.xml</param-value>
        </init-param>
      </servlet>
      <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>
    
    </web-app>
    

    二 遇到的坑

    idea中使用tomcat

    一定要把配置好的tomcat添加进来


    image.png

    使用@responseBody服务

    一定要在spring mvc配置文件中加上这个配置,否则会报406错误。原因会在第三节讲到

    <mvc:annotation-driven />
    

    tomcat控制台乱码

    参考:https://blog.csdn.net/u012611878/article/details/80723491

    三 架构和组件

    框架结构

    image.png

    流程

    1. 用户发送请求至前端控制器DispatcherServlet。
    2. DispatcherServlet收到请求调用HandlerMapping处理器映射器。
    3. 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
    4. DispatcherServlet通过HandlerAdapter处理器适配器调用处理器。
    5. 执行处理器(Controller,也叫后端控制器)。
    6. Controller执行完成返回ModelAndView。
    7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
    8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
    9. ViewReslover解析后返回具体View。
    10. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
    11. DispatcherServlet响应用户。

    注意点

    1. HandlerMapping 返回时一个处理器执行链(HandlerExecutionChain ),这个处理器执行链里面除了有Handler之外,还有拦截器(这儿我们可以开发自己的拦截器),然后返回给前端控制器。
    2. 处理器执行链中的handler,前端处理器并不能直接执行它。所以需要找到一个HandlerAdapter来执行handler

    组件

    HandlerMapping

    作用是根据当前请求的找到对应的 Handler,并将 Handler(执行程序)与一堆 HandlerInterceptor(拦截器)封装到 HandlerExecutionChain 对象中。在 HandlerMapping 接口的内部只有一个方法,

    public interface HandlerMapping {
        String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
        String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
        String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
        String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
        String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";
        String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";
    
        HandlerExecutionChain getHandler(HttpServletRequest var1) throws Exception;
    }
    

    HandlerMapping 的实现类有很多,默认加载如下(spring mvc4.2.6.RELEASE版本)


    image.png

    常见的HandlerMapping实现

    1. SimpleUrlHandlerMapping:通过配置请求路径和Controller映射建立关系,找到相应的Controller
    2. ControllerClassNameHandlerMapping:通过 Controller 的类名找到请求的Controller
    3. BeanNameUrlHandlerMapping:通过定义的 beanName 进行查找要请求的Controller
    4. DefaultAnnotationHandlerMapping:通过注解 @RequestMapping("/userlist") 来查找对应的Controller(已过时)
    5. RequestMappingHandlerMapping :取代了上面一个

    注意点:

    1. BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping的引入。<mvc:default-servlet-handler />的解析,会引入SimpleUrlHandlerMapping.需要小心重复实例化
      参考:https://blog.csdn.net/gaoshan12345678910/article/details/81778587

    HandlerAdapter

    采用了适配器模式
    springmvc的handler(Controller,HttpRequestHandler,Servlet等)有多种实现方式,例如继承Controller的,基于注解控制器方式的,HttpRequestHandler方式的。由于实现方式不一样,调用方式就不确定了。
    如果正常编写调用,就需要使用多个if else判断instance of,再添加实现方式,就需要修改源码,不符合对扩展开放,对修改关闭原则。
    HandlerAdapter接口有三个方法:

    public interface HandlerAdapter {
        boolean supports(Object var1);
    
        ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
    
        long getLastModified(HttpServletRequest var1, Object var2);
    }
    

    第一个方法是判断该适配器是否支持这个HandlerMethod,就是当得到一个handler时,该接口子类该方法做判断(就是类似handler instanceof Controller的判断方式),用来得到适配这个handler的适配器子类。
    第二个方法用来执行控制器处理函数,获取ModelAndView 。就是根据该适配器调用规则执行handler方法。

    Handlermapping和HandlerAdapter要成套配合使用

    <mvc:default-servlet-handler />

    主要会注册:

    1. DefaultServletHttpRequestHandler : 默认的Servlet请求处理器
    2. SimpleUrlHandlerMapping : url - handler映射器
    3. HttpRequestHandlerAdapter : 处理器适配器

    如果只配置了<mvc:default-servlet-handler/>除了加载上面三个组件,还会加载容器默认加载的组件:

    registerBeanNameUrlHandlerMapping(parserContext, source);
    registerHttpRequestHandlerAdapter(parserContext, source);
    registerSimpleControllerHandlerAdapter(parserContext, source);
    

    在springMVC-servlet.xml中配置<mvc:default-servlet-handler />后,会在Spring MVC上下文中定义一个org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它会像一个检查员,对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。

    一般Web应用服务器默认的Servlet名称是"default",因此DefaultServletHttpRequestHandler可以找到它。如果你所有的Web应用服务器的默认Servlet名称不是"default",则需要通过default-servlet-name属性显示指定:

    <mvc:default-servlet-handler default-servlet-name="所使用的Web服务器默认使用的Servlet名称" />
    参考:

    1. https://www.cnblogs.com/dflmg/p/6393416.html
    2. https://blog.csdn.net/abc997995674/article/details/80513203

    <mvc:annotation-driven/>

    1、会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter、ExceptionHandlerExceptionResolver三个bean支持使用了像@RquestMapping、ExceptionHandler等等的注解的controller 方法去处理请求。
    2、支持使用了ConversionService]的实例对表单参数进行类型转换。
    3、支持使用@NumberFormat、@NumberFormat注解对数据类型进行格式化。
    4、支持使用@Valid对javaBean进行JSR-303验证。
    5、支持使用@RequestBody、@ResponseBody。

    ViewReslover

    最常用的是InternalResourceViewResolver

    <bean  
       class="org.springframework.web.servlet.view.UrlBasedViewResolver">  
       <property name="prefix" value="/WEB-INF/" />  
       <property name="suffix" value=".jsp" />  
       <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/>  
    </bean>  
    

    参考:SpringMVC视图解析器

    配置BeanNameViewResolver

        <!-- 配置视图  BeanNameViewResolver 解析器: 使用视图的名字来解析视图 -->
        <!-- 通过 order 属性来定义视图解析器的优先级, order 值越小优先级越高 -->
        <bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
            <property name="order" value="100"></property>
        </bean>
    

    总结:有多个视图解析器时,会根据order值来依次尝试解析视图。例如在上面的情况下,BeanNameViewResolver会先去bean容器中找需要的view同名的View对象,没找到就让InternalResourceViewResolver来找...如果所有的视图解析器都没解析成功就抛出了异常。

    参考:

    1. SpringMVC学习(二)——SpringMVC架构及组件
    2. SpringMVC工作原理之二:HandlerMapping和HandlerAdapter
    3. 看springmvc适配器模式---HandlerAdapter
    4. <mvc:annotation-driven/>作用
    5. idea基于maven 创建SpringMVC项目

    相关文章

      网友评论

          本文标题:(一)helloworld、组件、架构

          本文链接:https://www.haomeiwen.com/subject/mzdnxctx.html