<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
这里以html为例,如果需要多种静态资源类型,就需要配置多个以上。
为什么配置这个就能访问了呢?default是哪个servlet?为什么要使用这个servlet处理静态资源?我的脑海中产生这样一系列的问题。
总的来说,是因为配置了spring MVC的DispatcherServlet拦截“/”,为了实现REST风格,拦截了所有的请求,同时,静态文件也被拦截。 所以激活Tomcat的defaultServlet来处理静态文件。
我们接着刚刚的疑问继续探究。
先在项目里面找了default,没有找到。很好,百度吧!百度说这是他tomcat默认的serlvet,那这个servlet是干什么用的呢?我们已经知道它的一个用处了,就是处理静态资源。从这个网址可以看到官方文档里面对DefaultServlet的解释。http://tomcat.apache.org/tomcat-7.0-doc/default-servlet.html#what
1. What is the DefaultServlet?
DefaultServlet是用来处理静态资源,就像处理目录列表一样。
2. Where is it declared?
DefaultServlet是在$CATALINA_BASE/conf/web.xml里面做全局声明的,默认情况下是这样子的
<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>
...
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
所以通常情况下,DefaultServlet是在web项目启动时加载的,同时debug调试和文件目录都是禁用的。
这里的listings是指文件目录,可是文件目录又是什么呢?别着急,我们继续往下看。
3. What can I change?
DefaultServlet允许下面这些初始化参数
- debug 这个参数对tomcat的开发者用处比较大,对我们而言用处不大。可选的值有0,1,11,1000.[0]
- listings 如果没有设置欢迎页,那么当我们访问项目名时,会显示文件目录吗?这个参数的值是true或者false.[false].(这里我把值设置成了true,并且删除了欢迎文件,访问项目时,显示了文件目录可以对比我的项目目录) 欢迎文件也是servlet api的一部分。警告:包含很多实体的文件目录是非常珍贵的。大量的对大文件列表的请求,十分消耗服务器资源。
- readmeFile 如果设置了显示文件列表,readme文件可能也会显示在列表里面。这个文件是插入的,它可能包含html.
- globalXsltFile 如果你想定制你的文件目录,你可以使用XSL来转换。这个的值也是一个相对文件的名称($CATALINA_BASE/conf/ or $CATALINA_HOME/conf/),这个将会给所有的文件目录使用。但是这个可以被每一个context或者directory覆盖。具体的请看下面的contextXsltFile和localXsltFile.
- contextXsltFile 你可以通过配置contextXsltFile来定制你的文件目录。但是一定要使用上下文的相对路径,并且是一.xsl或者.xslt为扩展名的文件(例如:/path/to/context.xslt)。这个会覆盖globalXsltFile的值. 如果配置的文件路径不存在,仍然会使用globalXsltFile的配置。如果默认的globalXsltFile文件也不存在,那会直接显示文件目录。
- localXsltFile 你同样可以通过配置localXsltFile来定制你的文件目录。它一定是以.xsl或.xslt为扩展名的在目录列表里面的文件。并且这个配置能覆盖globalXsltFile和contextXsltFile的配置。如果配置的这个值找不到对应文件,就会使用contextXsltFile的配置,如果contextXsltFile也找不到,就会使用globalXsltFile的配置,如果都找不到,那么就会展示默认的文件目录。
- input 当读取资源文件时,服务器写入缓冲区的大小,单位为bytes.[2048]
- output 当写入资源文件时,服务器输出缓冲区大小,单位为bytes.[2048]
- readonly 上下文是否是只读的,HTTP的命令,像PUT,DELETE这些是不是被拒绝的。[true]
- fileEncoding 读取静态资源时的文件编码。[platform default]
- sendfileSize 如果使用的连接器支持sendfile,这意味着以KB大小的小文件将会被使用。通常使用负数来禁止sendfile.[48]
- useAcceptRanges 如果设置为true,当响应时请求头的Accept-Ranges将会被设置。[true]
- showServerInfo 当展示文件列表是,服务器信息是否在响应时一起发送给客户端。[true]
<listing>
<entries>
<entry type='file|dir' urlPath='aPath' size='###' date='gmt date'>
fileName1
</entry>
<entry type='file|dir' urlPath='aPath' size='###' date='gmt date'>
fileName2
</entry>
...
</entries>
<readme></readme>
</listing>
- 如果设置type='dir',就不用设置size
- Readme是一个CDATA,不由xml解析器解析
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:output method="html" html-version="5.0"
encoding="UTF-8" indent="no"
doctype-system="about:legacy-compat"/>
<xsl:template match="listing">
<html>
<head>
<title>
Sample Directory Listing For
<xsl:value-of select="@directory"/>
</title>
<style>
h1 {color : white;background-color : #0086b2;}
h3 {color : white;background-color : #0086b2;}
body {font-family : sans-serif,Arial,Tahoma;
color : black;background-color : white;}
b {color : white;background-color : #0086b2;}
a {color : black;} HR{color : #0086b2;}
table td { padding: 5px; }
</style>
</head>
<body>
<h1>Sample Directory Listing For
<xsl:value-of select="@directory"/>
</h1>
<hr style="height: 1px;" />
<table style="width: 100%;">
<tr>
<th style="text-align: left;">Filename</th>
<th style="text-align: center;">Size</th>
<th style="text-align: right;">Last Modified</th>
</tr>
<xsl:apply-templates select="entries"/>
</table>
<xsl:apply-templates select="readme"/>
<hr style="height: 1px;" />
<h3>Apache Tomcat/8.0</h3>
</body>
</html>
</xsl:template>
<xsl:template match="entries">
<xsl:apply-templates select="entry"/>
</xsl:template>
<xsl:template match="readme">
<hr style="height: 1px;" />
<pre><xsl:apply-templates/></pre>
</xsl:template>
<xsl:template match="entry">
<tr>
<td style="text-align: left;">
<xsl:variable name="urlPath" select="@urlPath"/>
<a href="{$urlPath}">
<pre><xsl:apply-templates/></pre>
</a>
</td>
<td style="text-align: right;">
<pre><xsl:value-of select="@size"/></pre>
</td>
<td style="text-align: right;">
<pre><xsl:value-of select="@date"/></pre>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
我们可以看到DefaultServlet继承了HttpServlet,刚刚那些参数都是DefaultServlet里面的属性,并且在构造器里面设置了默认值。
/* */ private static final long serialVersionUID = 1L;
/* */ private static final DocumentBuilderFactory factory;
/* */ private static final SecureEntityResolver secureEntityResolver;
/* */ protected int debug;
/* */ protected int input;
/* */ protected boolean listings;
/* */ protected boolean readOnly;
/* */ protected int output;
/* */ protected static final URLEncoder urlEncoder;
/* */ protected String localXsltFile;
/* */ protected String contextXsltFile;
/* */ protected String globalXsltFile;
/* */ protected String readmeFile;
/* */ protected transient ProxyDirContext resources;
/* */ protected String fileEncoding;
/* */ protected int sendfileSize;
/* */ protected boolean useAcceptRanges;
/* 227 */ protected static final ArrayList<Range> FULL = new ArrayList();
/* */ protected boolean showServerInfo;
/* */ protected static final String mimeSeparation = "CATALINA_MIME_BOUNDARY";
/* */ protected static final String RESOURCES_JNDI_NAME = "java:/comp/Resources";
/* */ protected static final StringManager sm;
/* */ protected static final int BUFFER_SIZE = 4096;
/* */
/* */ public DefaultServlet()
/* */ {
/* 144 */ this.debug = 0;
/* */
/* 150 */ this.input = 2048;
/* */
/* 156 */ this.listings = false;
/* */
/* 162 */ this.readOnly = true;
/* */
/* 168 */ this.output = 2048;
/* */
/* 180 */ this.localXsltFile = null;
/* */
/* 186 */ this.contextXsltFile = null;
/* */
/* 192 */ this.globalXsltFile = null;
/* */
/* 198 */ this.readmeFile = null;
/* */
/* 204 */ this.resources = null;
/* */
/* 211 */ this.fileEncoding = null;
/* */
/* 217 */ this.sendfileSize = 49152;
/* */
/* 222 */ this.useAcceptRanges = true;
/* */
/* 232 */ this.showServerInfo = true;
/* */ }
接着就是destroy()和init()方法。init()在服务器启动时执行,destroy()方法在服务器停止时执行。在init()方法里面,我们可以看到它是去读取配置文件的这些属性值,并赋值。
/* */ public void init()/* */ throws ServletException
/* */ {
/* 305 */ if (getServletConfig().getInitParameter("debug") != null) {
/* 306 */ this.debug = Integer.parseInt(getServletConfig().getInitParameter("debug"));
/* */ }
/* 308 */ if (getServletConfig().getInitParameter("input") != null) {
/* 309 */ this.input = Integer.parseInt(getServletConfig().getInitParameter("input"));
/* */ }
/* 311 */ if (getServletConfig().getInitParameter("output") != null) {
/* 312 */ this.output = Integer.parseInt(getServletConfig().getInitParameter("output"));
/* */ }
/* 314 */ this.listings = Boolean.parseBoolean(getServletConfig().getInitParameter("listings"));
/* */
/* 316 */ if (getServletConfig().getInitParameter("readonly") != null) {
/* 317 */ this.readOnly = Boolean.parseBoolean(getServletConfig().getInitParameter("readonly"));
/* */ }
/* 319 */ if (getServletConfig().getInitParameter("sendfileSize") != null) {
/* 320 */ this.sendfileSize = (Integer.parseInt(getServletConfig().getInitParameter("sendfileSize"))
* 1024);
/* */ }
/* */
/* 323 */ this.fileEncoding = getServletConfig().getInitParameter("fileEncoding");
/* */
/* 325 */ this.globalXsltFile = getServletConfig().getInitParameter("globalXsltFile");
/* 326 */ this.contextXsltFile = getServletConfig().getInitParameter("contextXsltFile");
/* 327 */ this.localXsltFile = getServletConfig().getInitParameter("localXsltFile");
/* 328 */ this.readmeFile = getServletConfig().getInitParameter("readmeFile");
/* */
/* 330 */ if (getServletConfig().getInitParameter("useAcceptRanges") != null) {
/* 331 */ this.useAcceptRanges = Boolean
.parseBoolean(getServletConfig().getInitParameter("useAcceptRanges"));
/* */ }
/* */
/* 334 */ if (this.input < 256)
/* 335 */ this.input = 256;
/* 336 */ if (this.output < 256) {
/* 337 */ this.output = 256;
/* */ }
/* 339 */ if (this.debug > 0) {
/* 340 */ log(new StringBuilder().append("DefaultServlet.init: input buffer size=").append(this.input)
.append(", output buffer size=").append(this.output).toString());
/* */ }
/* */
/* 345 */ this.resources = ((ProxyDirContext) getServletContext()
.getAttribute("org.apache.catalina.resources"));
/* */
/* 347 */ if (this.resources == null) {
/* */ try {
/* 349 */ this.resources = ((ProxyDirContext) new InitialContext().lookup("java:/comp/Resources"));
/* */ }
/* */ catch (NamingException e)
/* */ {
/* 354 */ throw new ServletException("No resources", e);
/* */ }
/* */ }
/* */
/* 358 */ if (this.resources == null) {
/* 359 */ throw new UnavailableException("No resources");
/* */ }
/* */
/* 362 */ if (getServletConfig().getInitParameter("showServerInfo") != null)
/* 363 */ this.showServerInfo = Boolean
.parseBoolean(getServletConfig().getInitParameter("showServerInfo"));
/* */ }
我猜测getServletConfig().getInitParameter("debug")这两个方法就是读取在web.xml里面配置的default的参数的值的。
那么文件拦截后,交到doGet(),doPost方法处理。我们来看下。。在doGet()里面调用了serveResource(request, response, true)方法。我看了一下这个方法,不是所有的代码都能看懂,但是大致就是获取请求地址,然后处理跳转响应页面。和我们普通的servlet差不多。
最后就是要把这个default的servlet配置到springMVC跳转器的前面,这样请求就会走DefaultServlet了。
以上便是我的理解,欢迎指教!!