SpringMVC - 静态资源访问

Java项目读取resources资源文件路径那点事

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,它会像一个检查员,对进入DispatcherServletURL进行筛查,如果发现是静态资源的请求,就将该请求转由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 注册到 SimpleUrlHandlerMappingurlMap 中,keymappingURI pattern 值,而 valueResourceHttpRequestHandler,这样就巧妙的把对静态资源的访问由 HandlerMapping 转到 ResourceHttpRequestHandler 处理并返回,所以就支持 classpath 目录, jar 包内静态资源的访问。另外需要注意的一点是,不要对 SimpleUrlHandlerMapping 设置 defaultHandler. 因为对 static uridefaultHandler 就是 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种,分别是ServletContextClassClassLoader

其中ServletContext是WEB阶段的,Tomcat提供的一种获取资源的方式;

ClassClassLoader获取资源主要是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 类封装的 ClassLoadergetResourceAsStream() 方法,从 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);
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值