一、原理

Spring MVC基于模型-视图-控制器(Model-View-Controller,MVC)模式实现,它能够帮你构建像Spring框架那样灵活和松耦合的Web应用程序,将请求处理的逻辑和视图中的渲染实现解耦。

1、DispatcherServlet是Spring MVC的核心 。Spring MVC 中的请求页面都会委托给DispatcherServlet来执行处理。

2、DispatcherServlet需要知道将请求发送给哪个控制器,所以DispatcherServlet会查询一个或多个处理器映射(handler mapping) 来确定请求的下一站在哪里。

3、到了控制器(controller),请求会卸下其负载(用户提交的信息)并耐心等待控制器处理这些信息。

4、控制器在处理完成后,通常会产生一些信息,这些信息称为模型(model)。但是这个模型到底是渲染哪个页面的呢?所以控制器还会返回视图相关的东西。Spring 有个思想就是前后端分离,为了和视图解耦,所以控制器只返回了视图名。即,这里控制器返回了模型和视图名(modelAndViews)。

tips:Model 实际上就是一个Map(也就是key-value对的集合),它会传递给视图,这样数据就能渲染到客户端了,当调用addAttribute()方法并且不指定key的时候,那么key会根据值的对象类型推断确定,比如 List<Spittle>,那么推断他的 key 就是 spittleList。如果你希望使用非Spring类型的话,那么可以用java.util.Map来代替Model。

5、MVC 要怎么依靠一个视图名找到对应的视图呢?答案就是 视图解析器(view resolver)。

6、视图解析器(ViewResolver )接口会根据试图名和Locale对象返回一个View实例。View 接口的任务就是接受Model 以及Servlet的request和response对象,并将输出结果渲染到response中。

7、视图 (比如 JSP)。最终会被相应的容器(比如Tomcat)解析成 HTML 页面,并响应用户的请求。

tips:实际上,设计良好的控制器本身只处理很少甚至不处理工作,而是将业务逻辑委托给一个或多个服务对象进行处理。

二、使用 Java 配置

按照传统的方式,像 DispatcherServlet 这样的Servlet会配置在web.xml文件中 ,但是,借助于Servlet 3规范和Spring 3.1的功能增强,这种方式已经不是唯一的方案了 。我们会使用Java将DispatcherServlet配置在Servlet容器中。开始前,我们先来理解下 DispatcherServlet 和 Servlet 监听器(也就是ContextLoaderListener) 这两个应用上下文 。

DispatcherServlet 上下文:当DispatcherServlet启动的时候,它会创建Spring应用上下文,并加载配置文件或配置类(即带有@configuration注解的配置类)中所声明的bean,主要是Web 组件中的 bean, 包括 控制器(controller)、映射器(handler mapping)、视图解析器(view resolver)等。

ContextLoaderListener 上下文:这个上下文 由 ContextLoaderListener  创建,主要负责加载应用中的其他 bean 。这些bean通常是驱动应用后端的中间层和数据层组件。

1、实现:
    我们通过继承 AbstractAnnotationConfigDispatcherServletInitializer 类来配置SpringMVC,以作为传统 XML 配置的替代方案。实际上,AbstractAnnotationConfigDispatcherServletInitializer  会 同时创建 DispatcherServlet 和 ContextLoaderListener 。当然,我们需要手动配置我们的映射路径、视图解析器 并启用组件扫描 以及一系列我们可以自定义的配置。当然,如果我们没有配置视图解析器,SpringMVC 会启用默认的视图解析器(通过查找 ID 与视图名称相匹配的Bean,并且这个Bena 要实现View 接口)。如果没有配置路径映射,DispatcherServlet会映射为应用的默认Servlet,所以它会处理所有的请求,包括对静态资源的请求,如图片和样式表等。

  1. public class SplittrWebAppInitailzer extends AbstractAnnotationConfigDispatcherServletInitializer {
  2.  
  3. /*返回会创建ContextLoaderListener 上下文*/
  4. @Override
  5. protected Class<?>[] getRootConfigClasses() {
  6. return new Class<?>[]{RootConfig.class};
  7. }
  8.  
  9. /*返回会创建 DispatcherServlet 上下文*/
  10. @Override
  11. protected Class<?>[] getServletConfigClasses() {
  12. return new Class<?>[]{WebConfig.class};
  13. }
  14.  
  15. /*配置路径映射*/
  16. @Override
  17. protected String[] getServletMappings() {
  18. return new String[]{"/"};
  19. }
  20. }

最小但可用的SpringMVC配置

  1. @Configuration
  2. @ComponentScan(basePackages = {"com"},
  3. excludeFilters = {
  4. @ComponentScan.Filter(type = FilterType.ANNOTATION,value = EnableWebMvc.class)
  5. })
  6. public class RootConfig {
  7. }

RootConfig.java

  1. @Configuration
  2. @EnableWebMvc //启用SpringMVC,当然也可以使用 <mvc:annotation-driven /> 注解驱动
  3. @ComponentScan(basePackages = "com.controller")
  4. public class WebConfig extends WebMvcConfigurerAdapter {
  5.  
  6. /**
  7. * 在查找的时候,它会在视图名称上加一个特定的前缀和后缀
  8. * (例如,名为home的视图将会解析为/WEB-INF/pages/home.jsp)。
  9. *
  10. * @return
  11. */
  12. @Bean
  13. public ViewResolver viewResolver() {
  14. InternalResourceViewResolver resolver = new InternalResourceViewResolver();
  15. resolver.setPrefix("/WEB-INF/pages/");
  16. resolver.setSuffix(".jsp");
  17. /*设置是否把所有在上下文中定义的bean作为request属性可公开访问。
  18. 这样在JSP 2.0中可使用${}来存取,JSTL中使用c:out。
  19. 默认为false。*/
  20. resolver.setExposeContextBeansAsAttributes(true);
  21. resolver.setViewClass(org.springframework.web.servlet.view.JstlView.class); //设置解析JSTL
  22. return resolver;
  23. }
  24.  
  25. /**
  26. * 通过调用DefaultServlet-HandlerConfigurer的enable()方法,
  27. * 我们要求DispatcherServlet将对静态资源的请求转发到Servlet容器
  28. * 中默认的Servlet上,而不是使用DispatcherServlet本身来处理此类请求
  29. *
  30. * @param configurer
  31. */
  32. @Override
  33. public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
  34. configurer.enable();
  35. }
  36. }

WebConfig.java

InternalResourceViewResolver所采取的方式并不那么直接。它遵循一种约定,会在视图名上添加前缀和后缀,进而确定一个Web应用中视图资源的物理路径。当逻辑视图中包含斜线时,这个斜线也会带到资源的路径名中。
    通过  resolver.setViewClass(org.springframework.web.servlet.view.JstlView.class)  配置了视图解析器的ViewClass后,可以保证 JSTL的格式化和信息标签能够获得Locale对象以及Spring中配置的信息资源。

2、测试:

  1. @RequestMapping(value = {"/","/home"},method = RequestMethod.GET)
  2. public String getHome(Model model){
  3. return "home";
  4. }

controller

3、请求参数说明

A、处理requet URL 部分(不含queryString)的注解: @PathVariable;
B、处理request header部分的注解: @RequestHeader, @CookieValue;
C、处理request body部分的注解:@RequestParam, @RequestBody;
D、处理attribute类型是注解: @SessionAttributes, @ModelAttribute;

@RequestParam:可以处理get方式中的queryString的值,也可以处理post方式的body data 的值。用来处理Content-Type 为 application/x-www-form-urlencoded 编码的内容,提交方式GET、POST。

@RequestBody:

该注解常用来处理Content-Type: 不是application/x-www-form-urlencoded编码的内容,例如application/json, application/xml等;
特殊情况下,也可以用来处理 application/x-www-form-urlencoded的内容,处理完的结果放在一个MultiValueMap<String, String>里。
返回结果不会被解析为跳转路径,而是直接写入HTTP response body中。比如异步获取json数据,加上@responsebody后,会直接返回json数据

@ModelAttribute
该注解有两个用法,一个是用于方法上,一个是用于参数上;
用于方法上时: 通常用来在处理@RequestMapping之前,为请求绑定需要从后台查询的model;
用于参数上时: 用来通过名称对应,把相应名称的值绑定到注解的参数bean上;要绑定的值来源于:
    A) @SessionAttributes 启用的attribute 对象上;
    B) @ModelAttribute 用于方法上时指定的model对象;(会绑定需要的对象,比如model.addAttribute("pet", pet);)
    C) 上述两种情况都没有时,new一个需要绑定的bean对象,然后把request中按名称对应的方式把值绑定到bean 对象的各个属性中。

(1) SpringMVC 在 处理表单的时候,可以接受一个POJO对象(不用添加任何注解)作为参数。对象中的属性会使用请求中同名的参数进行补充,默认调用@ModelAttribute。
                                                        可以接受一个基本数据类型(不用添加任何注解)作为参数。会使用请求中同名的参数进行补充,默认调用@RequestParam。

(2) 当InternalResourceViewResolver看到视图格式中的“redirect:”前缀时,它就知道要将其解析为重定向的规则,而不是视图的名称。InternalResourceViewResolver还能识别“forward:”前缀。当它发现视图格式中以“forward:”作为前缀时,请求将会前往(forward)指定的URL路径,而不再是重定向。

分享一篇这方面讲得特别好的博客:http://blog.csdn.net/truong/article/details/28097837

4、添加自定义Servlet、Filter、Listener

  1. public class MyServlet extends HttpServlet {
  2. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  3. doGet(request,response);
  4. }
  5.  
  6. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  7. System.out.println("这是新建的Servlet");
  8. }
  9. }

自定义Servlet类

  1. public class MyServletInitializer implements WebApplicationInitializer {
  2. public void onStartup(ServletContext servletContext) throws ServletException {
  3. ServletRegistration.Dynamic myServlet = servletContext.addServlet("MyServlet", MyServlet.class);
  4. myServlet.addMapping("/myServlet");
  5. }
  6. }

注册Servlet

注册Filter、Listener 也可以用类似的方式。但是,如果你只是注册Filter,并且该Filter只会映射到DispatcherServlet上的话,那么在AbstractAnnotationConfigDispatcherServletInitializer中还有一种快捷方式。

  1. public class MyFilter implements Filter {
  2. public void destroy() {
  3. }
  4.  
  5. public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
  6. System.out.println("过滤器的工作");
  7. chain.doFilter(req, resp);
  8. }
  9.  
  10. public void init(FilterConfig config) throws ServletException {
  11.  
  12. }
  13.  
  14. }

自定义Filter类

  1. protected Filter[] getServletFilters() {
  2. return new Filter[]{new MyFilter()};
  3. }

在AbstractAnnotationConfigDispatcherServletInitializer的继承上添加...

三、使用 XML 配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app
  3. version="3.0"
  4. xmlns="http://java.sun.com/xml/ns/javaee"
  5. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  6. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  7.  
  8. <!--Web应用图标:指出IDE和GUI工具用来表示Web应用的大图标和小图标-->
  9. <icon>
  10. <small-icon>/images/small.gif</small-icon>
  11. <large-icon>/images/large.gif</large-icon>
  12. </icon>

  13. <!--定义了WEB应用的名字-->
  14. <display-name>mvc</display-name>

  15. <!--声明WEB应用的描述信息-->
  16. <description>mvc test</description>

  17. <!--上下文参数:在servlet里面可以通过 getServletContext().getInitParameter("name")得到-->
  18. <!--设置根上下文配置文件位置-->
  19. <context-param>
  20. <param-name>contextConfigLocation</param-name>
  21. <param-value>classpath:applicationContext.xml</param-value>
  22. </context-param>

  23. <!--配置过滤器-->
  24. <filter>
  25. <filter-name>encoding-filter</filter-name>
  26. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  27. <init-param>
  28. <param-name>encoding</param-name>
  29. <param-value>UTF-8</param-value>
  30. </init-param>
  31. </filter>
  32. <filter-mapping>
  33. <filter-name>encoding-filter</filter-name>
  34. <url-pattern>/*</url-pattern>
  35. </filter-mapping>

  36. <!--配置监听器 注册ContextLoaderListener-->
  37. <listener>
  38. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  39. </listener>

  40. <!--配置Servlet 注册DispatcherServlet-->
  41. <servlet>
  42. <servlet-name>appServlet</servlet-name>
  43. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  44. <load-on-startup>1</load-on-startup>
  45. </servlet>
  46. <servlet-mapping>
  47. <servlet-name>appServlet</servlet-name>
  48. <url-pattern>/</url-pattern>
  49. </servlet-mapping>

  50. <!--会话超时配置(单位为分钟)-->
  51. <session-config>
  52. <session-timeout>120</session-timeout>
  53. </session-config>

  54. <!--mime类型配置,用来指定对应的格式的浏览器处理方式-->
  55. <!--配置静态页面的打开编码-->
  56. <mime-mapping>
  57. <extension>htm</extension>
  58. <mime-type>text/html;charset=gb2312</mime-type>
  59. </mime-mapping>
  60. <mime-mapping>
  61. <extension>html</extension>
  62. <mime-type>text/html;charset=gb2312</mime-type>
  63. </mime-mapping>
  64.  
  65. <!--欢迎文件页配置-->
  66. <welcome-file-list>
  67. <welcome-file>index.jsp</welcome-file>
  68. </welcome-file-list>

  69. <!--错误页面配置-->
  70. <!--配置了当系统发生404错误时,跳转到错误处理页面NotFound.jsp-->
  71. <error-page>
  72. <error-code>404</error-code>
  73. <location>/NotFound.jsp</location>
  74. </error-page>
  75. <!--配置了当系统发生java.lang.NullException(即空指针异常)时,跳转到错误处理页面error.jsp-->
  76. <error-page>
  77. <exception-type>java.lang.NullException</exception-type>
  78. <location>/error.jsp</location>
  79. </error-page>
  80.  
  81. <!--以上是常见的配置,以下的东西也没搞懂怎么用,特别是 security-role 的含义指的是?-->
  82.  
  83. <!--安全限制配置-->
  84. <!--与login-config元素联合使用,指定服务器应该怎样给试图访问受保护页面的用户授权-->
  85. <security-constraint>
  86. <web-resource-collection>
  87. <web-resource-name>ProtectedArea</web-resource-name>
  88. <url-pattern>/resources/*</url-pattern>
  89. <!--如果没有<http-method>方法,表示禁止所有的HTTP方法访问对应的资源-->
  90. <http-method>GET</http-method>
  91. </web-resource-collection>
  92. <!--哪些用户应该具有受保护资源的访问权
  93. 如果没有 <auth-constraint> ,配置实际上是不起作用的。
  94. 如果内容为空,表示所有的身份都被禁止访问-->
  95. <auth-constraint>
  96. <role-name>ALL Role</role-name>
  97. </auth-constraint>
  98. </security-constraint>
  99.  
  100. <!--登录验证配置四种认证类型 -->
  101. <!-- BASIC:HTTP规范,Base64 这种方式被认为是最不安全的认证,因为它没有提供强烈的加密措施 -->
  102. <login-config>
  103. <auth-method>BASIC</auth-method>
  104. </login-config>
  105. <!-- DIGEST:HTTP规范,数据完整性强一些,但不是SSL 相比于BASIC认证,它是种比较安全的认证,它在认证时将请求数据 通过MD5的加密方式进行认证 -->
  106. <login-config>
  107. <auth-method>DIGEST</auth-method>
  108. </login-config>
  109. <!-- CLIENT-CERT:J2EE规范,数据完整性很强,公共钥匙(PKC) 这是一种基于客户端证书的认证方式,比较安全。但缺陷是在没有安全证书的客户端无法使用 -->
  110. <login-config>
  111. <auth-method>CLIENT-CERT</auth-method>
  112. </login-config>
  113. <!-- FORM:J2EE规范,数据完整性非常弱,没有加密,允许有定制的登录界面 这是种基础自定义表单的认证,你可以指定登录时的验证表单 -->
  114. <login-config>
  115. <auth-method>FORM</auth-method>
  116. <form-login-config>
  117. <form-login-page>/login.html</form-login-page>
  118. <form-error-page>/error.jsp</form-error-page>
  119. </form-login-config>
  120. </login-config>
  121.  
  122. <!--安全角色-->
  123. <!--这些角色将出现在servlet元素内的security-role-ref元素的role-name子元素中。分别地声明角色可使高级IDE处理安全信息更为容易(没看懂这句话)-->
  124. <security-role>
  125. <role-name>ALL Role</role-name>
  126. </security-role>
  127. </web-app>

tips:web.xml 的加载顺序是:ServletContext -> context-param -> listener -> filter -> servlet ,而同个类型之间的实际程序调用的时候的顺序是根据对应的 mapping 的顺序进行调用的。

四、结语

2017年最后一篇博文了,坚持在2017年的最后一个晚上写完。毕竟2017的事总不好意思拖一年呀!坚持写博客真是个好习惯,好记性毕竟不如白纸黑字来的牢靠啊,如果把记性比作网上搜索的话,博客就是自己的一份离线存储。

本来想好好回顾下2017,打一大堆满满的文字,装一个文艺的青年。真到落笔的时候,什么都不想写。敬往事一杯酒,悠悠岁月不回头!

祝大家新年快乐!2018!我来了......

浅析 SpringMVC 原理和配置.的更多相关文章

  1. SpringMVC的url-pattern配置及原理剖析

    SpringMVC的url-pattern配置及原理剖析 xml里面配置标签: <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc./ ...

  2. [SpringMVC]SpringMVC学习笔记一: springmvc原理及实例解析.

    前言:今天来回顾下SpringMVC的开发原理, 使用图文并茂的方式 来解析其中的内幕, 我相信懂了其中的运行机制后, 对于面试中SpringMVC大家都可以说so easy了. 一, 图示法 第二张 ...

  3. Spring学习 6- Spring MVC (Spring MVC原理及配置详解)

    百度的面试官问:Web容器,Servlet容器,SpringMVC容器的区别: 我还写了个文章,说明web容器与servlet容器的联系,参考:servlet单实例多线程模式 这个文章有web容器与s ...

  4. 7、springmvc的自动配置

    1.springmvc的自动配置 文档:https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#boot ...

  5. SpringMVC 原理 - 设计原理、启动过程、请求处理详细解读

    SpringMVC 原理 - 设计原理.启动过程.请求处理详细解读 目录 一. 设计原理 二. 启动过程 三. 请求处理 一. 设计原理 Servlet 规范 SpringMVC 是基于 Servle ...

  6. SpringMVC的自动配置解析

    https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#boot-features-developin ...

  7. Spring MVC原理及配置

    Spring MVC原理及配置 1. Spring MVC概述 Spring MVC是Spring提供的一个强大而灵活的web框架.借助于注解,Spring MVC提供了几乎是POJO的开发模式,使得 ...

  8. 0011SpringBoot的@EnableWebMvc全面接管SpringMVC的自动配置(源码)

    所谓的@EnableWebMvc全面接管SpringMVC的自动配置,是指@EnableWebMvc注解会使SpringMVC的自动配置失效,原理如下: 1.查看@EnableWebMvc的源码,如下 ...

  9. SpringBoot中SpringMVC的自动配置以及扩展

    一.问题引入 我们在SSM中使用SpringMVC的时候,需要由我们自己写SpringMVC的配置文件,需要用到什么就要自己配什么,配置起来也特别的麻烦.我们使用SpringBoot的时候没有进行配置 ...

随机推荐

  1. TFboy养成记 tensorboard

    首先介绍几个用法: with tf.name_scope(name = "inputs"): 这个是用于区分区域的.如,train,inputs等. xs = tf.placeho ...

  2. css实现六边形图片(最简单易懂方法实现高逼格图片展示)

    不说别的,先上效果: 用简单的div配合伪元素,即可‘画出’这幅六边形图片,原理是三个相同宽高的div,通过定位旋转拼合成一个六边形,再利用背景图层叠,形成视觉上的一张整图.下面咱们一步一步来实现. ...

  3. impala基础

    impala: 查询impala表时一定要加库名使用级联删除带有表的数据库:DROP database name cascade; insert插入的两种方式: 1. insert into empl ...

  4. Tinc VPN

    服务端配置 安装 $ apt-get install tinc 配置 $ mkdir -p /etc/tinc/dock/hosts $ cd /etc/tinc/dock 配置 tinc.conf ...

  5. SQL Count(*)函数,GROUP_By,Having的联合使用

    COUNT(*)  函数返回在给定的选择中被选的行数. 语法:SELECT  COUNT(*) FROM  table 使用:现在有一个表,名叫app_category,从Navicat中可以看到表中 ...

  6. createElement的应用

    原生js表单生成列表实现原理 这里用到的一些方法有 insertBefore() createElement() appendChild() removeChild() and so on~~ < ...

  7. 单词接龙dfs洛谷

    题目传送门:https://www.luogu.org/problem/show?pid=1019#sub 典型的爆搜,每次更新最大龙长度即可 搜索每个字符串编号,与已经连接好的字符串进行比较,以此往 ...

  8. Java反射机制(创建Class对象的三种方式)

    1:SUN提供的反射机制的类: java.lang.Class<T> java.lang.reflect.Constructor<T> java.lang.reflect.Fi ...

  9. Python操作 Memcache、Redis、RabbitMQ

    Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度 ...

  10. COM组件转换为.NET元数据2

    上一篇通过命令的方式实现COM组件与.NET元素的转换.这次直接在VS中转换. 以下为步骤: