美文网首页
(一)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