持续学习&持续更新中…

守破离


【Java从零到架构师第③季】【28】SpringMVC-Servlet的URL匹配_path-matching suffix-pattern

  • Servlet的URL匹配
    • *.do
    • /
    • /*
    • 总结
  • Tomcat是如何匹配请求的
    • /—DefaultServlet
    • *.jsp—JspServlet
  • 新的问题
  • 静态资源被匹配的解决方案1
  • 静态资源被匹配的解决方案2
  • 静态资源被匹配的解决方案3
  • path-matching
  • 注意和一些细节
  • 参考

Servlet的URL匹配

*.do

  • 只会匹配以.do为结尾的请求

    *.controller
    *.action
    *.access

    可以自定义后缀
    这里使用.do

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><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:applicationContext.xml</param-value></init-param><load-on-startup>0</load-on-startup></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><!-- 匹配所有以.do为结尾的请求 --><!-- 匹配到请求后,就会交给对应的Servlet(这里就是DispatcherServlet)去处理 --><url-pattern>*.do</url-pattern></servlet-mapping>
    </web-app>
    
    @Controller
    public class DoController {//    @RequestMapping(value = "/test.do")@RequestMapping(value = "/test/test.do")@ResponseBodypublic String test(String username, String password) {System.out.println("username : " + username + ", password : " + password);return "<h1 style='color:red;'>热爱Coding,热爱Programming。</h1>";}
    }
    

/

  • 除了动态资源(例如.jsp文件)以外

  • 会匹配所有请求(静态资源(.css、.js、.png…)、自定义的URL请求、…)

/*

  • 真正意义上的匹配所有请求(动态资源、静态资源、自定义的URL请求、…)
  • 一般用于Filter

总结

  • 可以理解为:/ + *.jsp = /*

Tomcat是如何匹配请求的

在Tomcat的conf\web.xml中可以找到,例如:D:\apache-tomcat-8.5.70\conf\web.xml

/—DefaultServlet

org.apache.catalina.servlets.DefaultServlet用于处理除过动态资源(例如JSP文件)以外的所有请求,当然会包括静态资源(.css、.png、…)。

也就是说,DefaultServlet就是Tomcat用来处理静态资源的。

DefaultServlet会将静态资源解析处理后,返回(写出)给客户端。

  <!-- The default servlet for all web applications, that serves static resources. --><servlet><servlet-name>default</servlet-name><servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class><!-- ... --></servlet>
    <!-- The mapping for the default servlet --><servlet-mapping><servlet-name>default</servlet-name><url-pattern>/</url-pattern></servlet-mapping>

*.jsp—JspServlet

org.apache.jasper.servlet.JspServlet用于处理以.jsp为结尾的请求。

也就是说,JspServlet就是Tomcat用来处理JSP文件的。

JspServlet可以将JSP文件解析处理后,返回(写出)给客户端。

    <servlet><servlet-name>jsp</servlet-name><servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class><!-- ... --></servlet>
    <!-- The mappings for the JSP servlet --><servlet-mapping><servlet-name>jsp</servlet-name><url-pattern>*.jsp</url-pattern><url-pattern>*.jspx</url-pattern></servlet-mapping>

新的问题

  • 现在我们已经知道了*.do//*的区别。

  • 也已经知道了Tomcat是如何处理静态资源和JSP文件的。

  • 那么,使用SpringMVC,在平时开发中,我们应该如何去匹配请求呢?

    1. 首先,肯定不能使用/*,因为/*会匹配到所有的请求,当然也会将JSP文件也给匹配到,但是我们的DispatcherServlet却不能够解析处理JSP文件。
    2. 其次,在开发中,我们肯定也不想为每个请求都在后面加上一个.do.action之类的后缀。
    3. 那么,只能使用/来匹配请求了。
  • 问题来了,如果使用/来匹配请求的话,我们知道,/是会匹配到除了JSP文件以外的所有请求的,但是静态资源(.css、.png、*.js、…)的请求怎么办呢?我们的DispatcherServlet也不能够解析这些静态资源呀。

静态资源被匹配的解决方案1

交给Tomcat去处理

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"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"><context:component-scan base-package="programmer.lp"/><!-- annotation-driven 用于保证注解可以被正常使用 --><mvc:annotation-driven><mvc:message-converters><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="defaultCharset" value="utf-8"/></bean></mvc:message-converters></mvc:annotation-driven><!-- 如果上面没有处理字符串响应的话,就需要加上这一句 --><!-- <mvc:annotation-driven/> --><!-- DispatcherServlet没有处理的请求都交回给默认Servlet去处理 --><mvc:default-servlet-handler/>
</beans>

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><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:applicationContext.xml</param-value></init-param><load-on-startup>0</load-on-startup></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-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></filter><filter-mapping><filter-name>CharacterEncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
</web-app>

静态资源被匹配的解决方案2

交给SpringMVC去处理

 <mvc:annotation-driven/>    <!-- **代表所有子路径 --><!-- mapping是请求路径 --><!-- location是静态资源的位置 --><mvc:resources mapping="/assets/**" location="/assets/"/>

静态资源被匹配的解决方案3

观察Tomcat的web.xml(D:\apache-tomcat-8.5.70\conf\web.xml),我们可以看到有如下配置:

 <!-- ... --><!-- The default servlet for all web applications, that serves static resources. --><servlet><servlet-name>default</servlet-name><servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class><init-param><param-name>debug</param-name><param-value>0</param-value></init-param><init-param><param-name>listings</param-name><param-value>false</param-value></init-param><load-on-startup>1</load-on-startup></servlet><!-- The JSP page compiler and execution servlet, which is the mechanism  used by Tomcat to support JSP pages. --><servlet><servlet-name>jsp</servlet-name><servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class><init-param><param-name>fork</param-name><param-value>false</param-value></init-param><init-param><param-name>xpoweredBy</param-name><param-value>false</param-value></init-param><load-on-startup>3</load-on-startup></servlet><!-- The mapping for the default servlet --><servlet-mapping><servlet-name>default</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!-- The mappings for the JSP servlet --><servlet-mapping><servlet-name>jsp</servlet-name><url-pattern>*.jsp</url-pattern><url-pattern>*.jspx</url-pattern></servlet-mapping><!-- ... -->

我们发现:org.apache.jasper.servlet.JspServlet之所以可以处理JSP文件(以.jsp、.jspx为结尾的请求),就是因为JspServlet被配置了<url-pattern>

    <!-- The JSP page compiler and execution servlet, which is the mechanism  used by Tomcat to support JSP pages. --><servlet><servlet-name>jsp</servlet-name><servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class><init-param><param-name>fork</param-name><param-value>false</param-value></init-param><init-param><param-name>xpoweredBy</param-name><param-value>false</param-value></init-param><load-on-startup>3</load-on-startup></servlet><!-- The mappings for the JSP servlet --><servlet-mapping><servlet-name>jsp</servlet-name><url-pattern>*.jsp</url-pattern><url-pattern>*.jspx</url-pattern></servlet-mapping>

还记得上文的一个结论吗:/ + *.jsp = /*

  • /*代表匹配所有的请求
  • /代表匹配除过JSP的所有请求
  • *.jsp代表匹配JSP请求(以.jsp为结尾的请求)

那么此时我们就知道为什么/是代表匹配除过JSP的所有请求了:原因在于Tomcat的web.xml中有对JSP请求做单独配置。

PS:Tomcat在运行时会使用它的web.xml和项目的web.xml,也就是说,自己项目的web.xml可以覆盖Tomcat的web.xml中的一些配置信息,如果不覆盖的话,那么就会使用Tomcat默认的配置。

那么可以得出一个结论:/会匹配所有的请求,但前提是该请求没有被其它的<url-pattern>所匹配,也可以这样说:/代表匹配未被其它<url-pattern>匹配的所有请求;也就是说,/ == /* - 其它<url-pattern>

换个说法,也就是:如果某个请求在web.xml中有<url-pattern>匹配的话(就像jsp那样),那么,/对应的Servlet就不会去匹配该请求;如果你没有在web.xml中使用<url-pattern>匹配某个请求的话,那么/对应的Servlet就会去匹配该请求。

PS:通过注解配置Servlet,类似于:@WebServlet("/user/*"),本质上也是<url-pattern>

那么,静态资源就有第3种方法来解决了:

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><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:applicationContext.xml</param-value></init-param><load-on-startup>0</load-on-startup></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><!-- / 代表匹配未被其它url-pattern匹配的所有请求 --><url-pattern>/</url-pattern></servlet-mapping><!-- 处理静态资源对应的请求 --><servlet-mapping><servlet-name>default</servlet-name><url-pattern>*.html</url-pattern><url-pattern>*.css</url-pattern><url-pattern>*.js</url-pattern><url-pattern>*.png</url-pattern><url-pattern>*.mp4</url-pattern><url-pattern>*.mp3</url-pattern><!-- ... --></servlet-mapping><!-- POST请求乱码 --><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></filter><filter-mapping><filter-name>CharacterEncodingFilter</filter-name><!-- /* 代表匹配所有请求 --><url-pattern>/*</url-pattern></filter-mapping>
</web-app>

path-matching

在SpringMVC中默认:访问URL,加任意后缀名都能访问。
比如:你想访问/login,但是通过/login.do、/login.action、/login.json、…都能访问

webapp目录下,有一个hello.html:

这个html文件的访问路径应该是:

http://host:port/context_path/hello.html

有一个Controller:

@Controller
public class MyController {@GetMapping("/hello")@ResponseBodypublic String hello() {return "<h1 style=\"color: green;\">Controller-hello</h1>";}
}

这个Controller的访问路径应该是:

http://host:port/context_path/hello

但是当我们使用浏览器访问的时候,发现访问hello.html时却访问的是Controller:

为了解决这个问题,我们需要在applicationContext.html中配置如下:

<mvc:annotation-driven><mvc:path-matching suffix-pattern="false"/>
</mvc:annotation-driven>

配置好后,重新部署项目,我们就可以看到hello.html可以正常访问了:

注意和一些细节

  • (DispatcherServlet)Servlet是匹配请求,而不是拦截请求。

参考

小码哥-李明杰: Java从0到架构师③进阶互联网架构师.

脚本之家: SpringMVC URL匹配—禁用后缀访问操作.


本文完,感谢您的关注支持!


【Java从零到架构师第③季】【28】SpringMVC-Servlet的URL匹配_path-matching suffix-pattern相关推荐

  1. 【Java从零到架构师第③季】【49】会话管理—Token_ehcache

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][49]会话管理-Token_ehcache 基于Cookie.Session 基于Token ehcache 简单使用 项目使用 ...

  2. 【Java从零到架构师第③季】【48】SpringBoot-Swagger

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][48]SpringBoot-Swagger 接口文档-Swagger 基本使用 不使用starter 使用starter(Swa ...

  3. 【Java从零到架构师第③季】【26】SpringMVC-反射获取方法参数名_SpringMVC是如何获取方法的参数名的

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][26]SpringMVC-反射获取方法参数名_SpringMVC是如何获取方法的参数名的 利用反射获取方法的参数名 直接编译 修 ...

  4. 【Java从零到架构师第③季】【24】SpringMVC-概述_入门

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][24]SpringMVC-概述_入门 Spring.SpringMVC.MyBatis之间的关系 SpringMVC简介 Spr ...

  5. 【Java从零到架构师第二季】【07】JDBC FOR MySQL

    持续学习&持续更新中- 学习态度:守破离 JDBC FOR MySQL 什么是JDBC 如何通过Java操作数据库 JDBC是属于JavaSE的一部分 下载MySQL的JDBC实现 JDBC细 ...

  6. 【Java从零到架构师第二季】【14】AJAX

    持续学习&持续更新中- 学习态度:守破离 AJAX 同步请求和异步请求 未学AJAX之前向服务器提交请求的方式 同步和异步 AJAX 什么是AJAX AJAX的常见使用方式 原生 jQuery ...

  7. 【Java从零到架构师第1季】【并发 Concurrent 03】线程间通信_ReentrantLock_线程池

    持续学习&持续更新中- 守破离 [Java从零到架构师第1季][并发 Concurrent 03]线程间通信_ReentrantLock_线程池 线程间通信 线程间通信-示例 可重入锁Reen ...

  8. 个人总结的一个中高级Java开发工程师或架构师需要掌握的一些技能...

    近三年,其实都是在做一个项目,项目是一个大型的多节点部署的项目,做了好几个版本,中间用到了很多技术和框架, 也用了一些管理工具和敏捷实践.我这里不是来说项目的,因为最近看了一些招聘信息,结合项目中用到 ...

  9. 【Java从0到架构师(2),Java面试问题

    新建一个核心配置文件:applicationContext.xml <?xml version="1.0" encoding="UTF-8"?>&l ...

最新文章

  1. python【数据结构与算法】最长公共子串详解(附代码)
  2. 【bzoj1029】【JSOI2007】建筑抢修
  3. 使用shiro安全管理
  4. C/C++程序设计IDE推荐
  5. python循环10次1001python循环10次_Python循环题怎么做?
  6. 感谢Adobe,用上了Silverlight RC0版本
  7. 使用Canal实现redis和mysql的同步
  8. 【剑指offer - C++/Java】14、链表中倒数第k的节点
  9. LeetCode 351. 安卓系统手势解锁(回溯)
  10. java打印前线程的id_logback打印日志输出线程ID:切面模式
  11. 凯斯西储计算机科学,凯斯西储大学电气工程与计算机科学系基本信息详解
  12. OS函数:sleep-exit-wait
  13. React中的state和props有什么区别?
  14. python编辑快速上手_Python编程如何快速上手,答案在这里
  15. DB2错误SQL1585N
  16. Unity iOS使用ASTC格式纹理实践
  17. EasyExcel的导入excel文件
  18. LEFT()与RIGHT()函数
  19. 【软件测试】测试驱动开发与行为驱动开发
  20. luoguP4466 [国际集训队]和与积 莫比乌斯反演

热门文章

  1. android fatal signal 分析,android 内存异常报错,/libc: Fatal signal 11 (SIGSEGV) at 0x00
  2. 32个最热CPLD-FPGA论坛 1
  3. 几种主流网页开发语言的思考(下)
  4. oneui2正式版_使用OneUI 2.1欺骗三星手机-界面的最新版本
  5. 《操作系统实验》C++实现生产者-消费者问题
  6. Photoshop: Customization Photoshop:自定义功能 Lynda课程中文字幕
  7. Android 接入微信扫码库,实现堪比微信的扫码效果
  8. 注入中转生成器php,泛微协同商务系统e-cology某处SQL注入(附验证中转脚本)
  9. 万能码的码上付来袭(安全扫码专业委员会)
  10. Hello Kafka(五)——Kafka管理