1. servlet-mapping
的三种配置方式
*① / **
拦截所有 jsp js png .css 真的全拦截,因为全拦截了所以对于jsp的某些转发也会被解析 不建议使用
**② .action .do **
拦截以do action 结尾的请求
**③ / **
拦截所有,不包括jsp,包含.js .png.css,所以我们还要配置静态文件不由它解析 建议使用
<!-- 配置SpringMVC前端控制器 -->
<servlet>
<servlet-name>mySpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定SpringMVC配置文件 -->
<!-- SpringMVC的配置文件的默认路径是/WEB-INF/${servlet-name}-servlet.xml -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>mySpringMVC</servlet-name>
<!-- 拦截所有,不包括jsp,包含.js .png.css -->
<url-pattern>/</url-pattern>
</servlet-mapping>
2. SpringMVC静态资源拦截问题
浏览器访问服务器的一个页面,实际上是包含了很多次请求的。除了请求页面本身,页面上的图片,js等静态资源也是通过请求资源在服务器上的相对地址实现的;
来自浏览器的所有访问都会被前端控制器(DispatcherServlet
)捕获,当我们使用/的时候,对静态资源的请求也会被前端控制器捕获,并转交给处理器映射。由于我们的代码中不会有对应的控制器处理请求,因此请求无法被相应,导致网页无法加载静态资源
解决方法1
<mvc:default-servlet-handler/>
在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名称" />
解决方法2:<mvc:default-servlet-handler />
对静态资源放行
<mvc:default-servlet-handler />
将静态资源的处理经由Spring MVC框架交回Web应用服务器处理。而<mvc:resources />
更进一步,由Spring MVC框架自己处理静态资源,并添加一些有用的附加值功能。
首先,<mvc:resources />
允许静态资源放在任何地方,如WEB-INF
目录下、类路径下等,你甚至可以将JavaScript
等静态文件打到JAR
包中。通过location
属性指定静态资源的位置,由于location
属性是Resources
类型,因此可以使用诸如"classpath:"
等的资源前缀指定资源位置。传统Web容器的静态资源只能放在Web容器的根路径下,<mvc:resources />
完全打破了这个限制。
其次,<mvc:resources />
依据当前著名的Page Speed、YSlow等浏览器优化原则对静态资源提供优化。你可以通过cacheSeconds属性指定静态资源在浏览器端的缓存时间,一般可将该时间设置为一年,以充分利用浏览器端的缓存。在输出静态资源时,会根据配置设置好响应报文头的Expires 和 Cache-Control值。
在接收到静态资源的获取请求时,会检查请求头的Last-Modified值,如果静态资源没有发生变化,则直接返回303相应状态码,提示客户端使用浏览器缓存的数据,而非将静态资源的内容输出到客户端,以充分节省带宽,提高程序性能。
在springMVC-servlet中添加如下配置:
<mvc:resources location="/,classpath:/META-INF/publicResources/" mapping="/resources/**"/>
以上配置将Web根路径"/"及类路径下 /META-INF/publicResources/
的目录映射为/resources
路径。
假设Web根路径下拥有images、js这两个资源目录,在images下面有bg.gif图片,在js下面有test.js文件,则可以通过 /resources/images/bg.gif
和 /resources/js/test.js
访问这二个静态资源。
假设WebRoot还拥有images/bg1.gif 及 js/test1.js,则也可以在网页中通过 /resources/images/bg1.gif
及 /resources/js/test1.js
进行引用
如果出现下面的错误,可能是没有配置 <mvc:annotation-driven />
的原因
WARNING: No mapping found for HTTP request with URI ??? in DispatcherServlet with name 'SpringMVC'
原理
使用 <mvc:resources />
元素,把 mapping
的 URI 注册到 SimpleUrlHandlerMapping
的 urlMap
中,key
为 mapping
的 URI pattern
值,而 value
为 ResourceHttpRequestHandler
,这样就巧妙的把对静态资源的访问由 HandlerMapping
转到 ResourceHttpRequestHandler
处理并返回,所以就支持 classpath
目录, jar 包内静态资源的访问。另外需要注意的一点是,不要对 SimpleUrlHandlerMapping
设置 defaultHandler
. 因为对 static uri
的 defaultHandler
就是 ResourceHttpRequestHandler
,否则无法处理 static resources request.
3. 调用静态资源时涉及到的路径问题
前台路径
出现在 css,js,html,jsp 中的路径
因为浏览器访问服务器资源时会把css,js,html,jsp文件缓存到浏览器中,然后进行渲染,所以请求是从浏览器端发出的,由浏览器解析;它的参照路径是服务器的根路径;
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>页面A</title>
</head>
<body>
<!--
超链接有三种书写路径的方式
1,绝对地址
2,以"/"开头的相对地址
3,不以"/"开头的相对地址
-->
<!-- 1.绝对地址 -->
<!-- 完整的URL -->
<a href="http://localhost:8080/javaee/jsp/b.jsp">这是绝对地址超链接</a><br/>
<!-- 2.以"/"开头的相对地址 -->
<!-- /代表了整个web项目,即:http://localhost:8080/ -->
<a href="/javaee/jsp/b.jsp">这是以"/"开头的相对地址超链接</a><br/>
<!-- 3.不以"/"开头的相对地址 -->
<!--
不以/开头,则相对于当前资源的路径
当前资源的路径为:http://localhost:8080/javaee/jsp/
而b.jsp也在此路径下
所以直接书写b.jsp
-->
<a href="b.jsp">这是不以"/"开头的相对地址超链接</a><br/>
</body>
</html>
后台路径
出现在java 代码 ,jsp 文件中的动态部分,xml
像web项目中的WEB-INF里面的资源,就不能通过前台路径访问,只能通过后台代码访问;
后台路径的参照路径是项目的根路径
当页面跳转路径加/时,表示是绝对路径(推荐)
当页面跳转路径不加/时,表示是相对路径(不推荐)
4. 获取资源路径
Java类中需要读取properties
中的配置文件,可以采用文件(File)方式进行读取:
File file = new File("src/main/resources/properties/test.properties");
InputStream in = new FileInputStream(file);
当在IDEA中运行(不部署在服务器上),可以读取到该文件,但是部署到服务器上就不行了,因为JavaWeb项目部署服务器中,会将项目打包成Jar包或者war包,此时就不会存在 src/main/resources
目录,JVM会在编译项目时,主动将 java文件编译成 class文件 和 resources 下的静态文件放在 target/classes
目录下
所以我们需要获取到这个时候的资源路径,获取资源的路径的方法主要有3种,分别是ServletContext
、Class
和ClassLoader
其中ServletContext
是WEB阶段的,Tomcat提供的一种获取资源的方式;
Class
和ClassLoader
获取资源主要是JavaAPI提供的一种获取流的方式,由于这是JDK提供的,所以不仅局限于Web,在普通Java类中也可以使用,主要用于获取src目录及其子目录下的文件流
① ServletContext
获取资源
ServletContext
获取资源的路径是相对系统的绝对路径(在Windows中是带盘符的,可以用来获取上传或下载文件的具体路径)
获取ServletContext
的方法如下:
//使用request获取:
request.getSession().getServletContext();
//在Servlet中获取:
this.getServletContext();
//使用FilterConfig对象获取(在Filter中使用):
config.getServletContext();
基本语法:
servletContext.getRealPath("路径");
//参数中的路径必须是相对路径,可以“/”开头,也可以不使用“/”开头,但无论是否使用“/”开头都是相对当前应用路径,建议以"/"开头(这样可以尽量统一)
② ClassLoader
获取资源
public class ClassLoaderServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
InputStream in = this.getClass().getClassLoader().getResourceAsStream("cn/ccnu/classloaderpath/c.properties");
Properties prop = new Properties();
prop.load(in);
System.out.println(prop.getProperty("url"));
}
}
③ Class获取资源
Class获取资源主要是用作自己写的配置文件,用来读取内容。
用法:clazz.getResourceAsStream("路径")
参数中的路径可以以“/”开头,也可以不以“/”开头。其中带“/”的表示相对于当前类的路径,不以“/”开头表示相对于当前class所在目录的路径。
public class ClassServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/*
* 1.以/开头的相对路径
* 此时的/代表类路径,即:/javaee/WEB-INF/classes
*/
// InputStream in = ClassServlet.class.getResourceAsStream("/cn/ccnu/classpath/b.properties");
// Properties porp = new Properties();
// porp.load(in);
// System.out.println(porp.getProperty("url"));
/*
* 2.不以/开头的相对路径
* 此时相对的是:类ClassServlet.class的路径,即:\javaee\WEB-INF\classes\cn\ccnu\classpath
* 即:/javaee/WEB-INF/classes/cn/ccnu/classpath
*/
InputStream in = ClassServlet.class.getResourceAsStream("b.properties");
Properties porp = new Properties();
porp.load(in);
System.out.println(porp.getProperty("url"));
}
}
class.getResourceAStream()
与 class.getClassLoader().getResorceAsStream()
的区别
1) InputStream inStream = PropertiesTest.class.getResourceAsStream("test.properties");
2) inStream = PropertiesTest.class.getResourceAsStream("/com/test/demo/test.properties")
3) inStream = PropertiesTest.class.getClassLoader().getResourceAsStream("com/test/demo/test.properties");
第一种和第二种方式采用 Class
对象去加载,第三种方式采用 ClassLoader
对象去加载资源文件
之所以 Class
可以加载资源文件,是因为 Class
类封装的 ClassLoader
的 getResourceAsStream()
方法,从 Class 类中的源码可以看出:
public InputStream getResourceAsStream(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResourceAsStream(name);
}
return cl.getResourceAsStream(name);
}