1

在Spring框架中,所有的请求都可通过Spring转发器(Dispatcher)拦截,然后转到Controller层处理,但是有些资源文件的访问(比如图片、JS、CSS等文件)不需要经过Controller处理,这种情况如果处理?

使用Spring框架时,一般在web.xml中配置Spring的Servlet转发器,拦截前端请求以转交给Spring的Controller层处理。比如:
配置URL规则:

<servlet-mapping>   
    <servlet-name>springmvc</servlet-name>   
    <url-pattern>/</url-pattern>
</servlet-mapping>

配置转发器对应的class:

<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-mvc.xml</param-value>   
        </init-param>   
    <load-on-startup>1</load-on-startup>   
    <async-supported>true</async-supported>
</servlet>

上述配置好后,前端的所有请求,包含资源文件,都会转至Controller层处理,然后通过@RequestMapping来映射具体的处理方法。

但资源文件的请求也会被转至Controller中处理,可通过如下配置查看效果:

@RequestMapping(value = "/**", method = RequestMethod.GET)
public String index() {

注意:value中的/后面有两个*号,表示所有目录及子目录的路径。
这样,在URL中单独访问某个资源文件,可以看到该请求被转到index方法中处理了。

那如何解决这个问题呢?比如有下面的HTML,请求了js资源:

<!DOCTYPE html>
<html lang="en">
<head>    
    <meta charset="UTF-8">    
    <title>Title</title>    
    <script src="assets/jquery-1.11.0.js" type="text/javascript" ></script>
</head>
<body>
    <h1>Hello</h1>
</body>
</html>

注意:使用</script>结尾,而不是直接<script src.. />,否则html解析会有问题。

按照上面的配置,直接访问:http://localhost:8080/Test/assets/jquery-1.11.0.js,会转到index方法中处理,然后返回index方法指定的页面。而不是返回JS内容。
如果直接访问:http://localhost:8080/Test,会请求两次index,一次是/Test请求,一次是JS资源请求。但JS资源请求返回的不是JS内容,而是html。

有三种方式,通过:
1)<mvc:default-servlet-handler />
2)<mvc:resources mapping
3)web.xml中配置默认serlvet的映射


第一种方式:

在springmvc的xml配置文件中,加上<mvc:default-servlet-handler />即可。
这样会在Spring MVC上下文中定义一个org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,则该请求由Web应用服务器默认的Servlet和DispatcherServlet处理(如果没有匹配的@RequestMapping,则不处理)。如果不是静态资源的请求,只由DispatcherServlet处理。

一般Web应用服务器默认的Servlet名称是"default",因此DefaultServletHttpRequestHandler可以找到它。如果Web应用服务器的默认Servlet名称不是"default",则需要通过default-servlet-name属性显示指定:

<mvc:default-servlet-handler default-servlet-name="所使用的Web服务器默认使用的Servlet名称" />

第二种方式:

可以通过配置文件,配置指定资源的请求映射路径,使其不只是依赖于controller。比如:

<mvc:resources mapping="/assets/**" location="/assets/" />
<mvc:resources mapping="/app/**" location="/app/" />
<mvc:resources mapping="/manager/**" location="/manager/" />

其中第一行表示,资源请求中所有满足/assets/**规则的,都转到/assets/目录下。

注意:如果配置了@RequestMapping(value = "/", method = RequestMethod.GET),还是会处理资源请求的。说明任何请求,都会由DispatcherServlet处理,只是如果没有匹配的@RequestMapping,则交给其他的Servlet处理。因此,要避免"/"这种配置来防止请求被拦截,否则会出现错误之一:

Uncaught SyntaxError: Unexpected token <

第三种方式:

配置web.xml,将资源文件处理的servlet配置成default或其他自定义的。

<servlet-mapping>  
    <servlet-name>default</servlet-name>  
    <url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>  
    <servlet-name>default</servlet-name>  
    <url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>  
    <servlet-name>default</servlet-name>  
    <url-pattern>*.css</url-pattern>
</servlet-mapping>

这种方式比较繁琐,一般采用第二种方式。


anh6
87 声望1 粉丝