1、启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取<listener>和<context-param>两个结点。
2、紧急着,容创建一个ServletContext(servlet上下文),这个web项目的所有部分都将共享这个上下文。
3、容器将<context-param>转换为键值对,并交给servletContext。
4、容器创建<listener>中的类实例,创建监听器。
加载顺序
加载顺序会影响对spring bean 的调用。比如filter 需要用到 bean ,但是加载顺序是 先加载filter 后加载spring,则filter中初始化操作中的bean为null;
加载顺序与它们在 web.xml 文件中的先后顺序无关。最终得出的结论是:ServletContext -> listener -> filter -> servlet
同时还存在着这样一种配置节:context-param,它用于向 ServletContext 提供键值对,即应用程序上下文信息。我们的 listener, filter 等在初始化时会用到这些上下文中的信息,那么 context-param 配置节是不是应该写在 listener 配置节前呢?实际上 context-param 配置节可写在任意位置,因此真正的加载顺序为:context-param -> listener -> filter -> servlet
对于某类配置节而言,与它们出现的顺序是有关的。以 filter 为例,web.xml 中当然可以定义多个 filter,与 filter 相关的一个配置节是 filter-mapping,这里一定要注意,对于拥有相同 filter-name 的 filter 和 filter-mapping 配置节而言,filter-mapping 必须出现在 filter 之后,否则当解析到 filter-mapping 时,它所对应的 filter-name 还未定义。web 容器启动时初始化每个 filter 时,是按照 filter 配置节出现的顺序来初始化的,当请求资源匹配多个 filter-mapping 时,filter 拦截资源是按照 filter-mapping 配置节出现的顺序来依次调用 doFilter() 方法的。servlet 同 filter 类似
可以看出,web.xml 的加载顺序是:ServletContext -> context-param -> listener -> filter -> servlet ,而同个类型之间的实际程序调用的时候的顺序是根据对应的 mapping 的顺序进行调用的。
常见元素
<web-app> <!--定义了WEB应用的名字--> <display-name></display-name> <!--声明WEB应用的描述信息--> <description></description>
<!--指定该站台是否可分布式处理-->
<distributable/>
<!--context-param元素声明应用范围内的初始化参数,在servlet里面可以通过 getServletContext().getInitParameter(“context/param”)得到--> <context-param>
<param-name>参数名</param-name>
<param-value>参数值</param-value>
<description>参数描述</description>
</context-param> <!--过滤器元素将一个名字与一个实现javax.servlet.Filter接口的类相关联--> <filter>
<filter-name></filter-name> <!--过滤器名-->
<filter-class></filter-class> <!--引用的具体类文件名。一般引用官方包装好的,名字固定-->
<init-param></init-param>
</filter> <!--一旦命名了一个过滤器,就要利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联,即配置过滤器--> <filter-mapping>
<filter-name></filter-name> <!--对应于上面-->
<url-pattern></url-pattern> <!--以“/”开头并且以“/*”结尾的根据路径映射,以"*."开头的作为根据扩展名映射-->
<dispatcher></dispatcher> <!--2.4版本的servlet规范-->
</filter-mapping> <!--servlet API的版本2.3增加了对事件监听程序的支持,事件监听程序在建立、修改和删除会话或servlet环境时得到通知。Listener元素指出事件监听程序类--> <listener>
<!--指定监听类,该类继承ServletContextListener 包含初始化方法contextInitialized(ServletContextEvent event) 和 销毁方法contextDestoryed(ServletContextEvent event)-->
<listener-class></listener-class>
</listener> <!--在向servlet或JSP页面制定初始化参数或定制URL时,必须首先命名servlet或JSP页面。Servlet元素就是用来完成此项任务的--> <servlet>
<servlet-name></servlet-name> <!--servlet名称,一般跟Servlet类名有关-->
<servlet-class><servlet-class> <!--servlet类全路径-->
<jsp-file></jsp-file> <!--指定web站台中的某个JSP网页的完整路径-->
<init-param></init-param>
<!--指定当Web应用启动时,装载Servlet的次序,当值为0或者大于0时,表示容器在应用启动时就加载这个servlet;
当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载。 正数的值越小,启动该servlet的优先级越高。-->
<load-on-startup></load-on-startup>
</servlet> <!--服务器一般为servlet提供一个缺省的URL:http://host/webAppPrefix/servlet/ServletName。但是,常常会更改这个URL,以便servlet可以访问初始化参数或更容易地处理相对URL。在更改缺省URL时,使用servlet-mapping元素--> <servlet-mapping>
<servlet-name></servlet-name> <!--servlet名称,与上面一致-->
<url-pattern></url-pattern> <!--配置这个组件的访问路径,即映射路径-->
</servlet-mapping> <!--如果某个会话在一定时间内未被访问,服务器可以抛弃它以节省内存。可通过使用HttpSession的setMaxInactiveInterval方法明确设置单个会话对象的超时值,或者可利用session-config元素制定缺省超时值--> <session-config>
<session-timeout></session-timeout><!--为单个Web应用 配置超时时间,单位是分钟-->
</session-config> <!--如果Web应用具有想到特殊的文件,希望能保证给他们分配特定的MIME类型,将mime类型映射到扩展名, 用于规定下载格式--> <mime-mapping>
<extension></extension> <!--描述扩展名-->
<mime-type></mime-type> <!--MIME类型-->
</mime-mapping> <!--指示服务器在收到引用一个目录名而不是文件名的URL时,指定显示的默认页面--> <welcome-file-list>
<welcome-file></welcome-file>
</welcome-file-list> <!--在返回特定HTTP状态代码时,或者特定类型的异常被抛出时,能够制定将要显示的页面--> <!--通过错误码来配置error-page-->
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
<!--通过异常的类型配置error-page-->
<error-page>
<exception-type>java.lang.NullException</exception-type>
<location>/error.jsp</location>
</error-page>
<!-- jsp-config 包括taglib 、jsp-property-group 两个子元素 -->
<jsp-property-group>
<description></description> <!--设定的说明-->
<display-name></display-name><!--设定名称-->
<url-pattern></url-pattern><!--设定值所影响的范围,如:/CH2 或 /*.jsp-->
<el-ignored></el-ignored><!--若为true,表示不支持EL 语法-->
<page-encoding></page-encoding><!--设定JSP 网页的编码-->
<scripting-invalid></scripting-invalid><!--若为true,表示不支持<% scripting %>语法-->
<include-prelude></include-prelude><!--设置JSP 网页的抬头,扩展名为.jspf-->
<include-coda></include-coda><!--设置JSP 网页的结尾,扩展名为.jspf-->
</jsp-property-group>
<!--对标记库描述符文件(Tag Libraryu Descriptor file)指定别名。此功能使你能够更改TLD文件的位置, 而不用编辑使用这些文件的JSP页面,免去在jsp页面长引用url-->
<!--如果开发工具一直在报错,应该把<taglib> 放到 <jsp-config>中--> <taglib>
<taglib-uri></taglib-uri> <!--标签库唯一访问标识(必须与标签库tld描述文件中的uri一致)-->
<taglib-location></taglib-location> <!--标签库tld描述文件本地路径(如/WEB-INF/mytag.tld)-->
</taglib>
<!--声明与资源相关的一个管理对象,该对象与servlet环境中的资源相关联--> <resource-env-ref>
<resource-env-ref-name></resource-env-ref-name> <!--资源名-->
<resource-env-ref-type></resource-env-ref-type> <!--当web应用查找该资源的时候,返回的Java类名的全称-->
</resource-env-ref> <!--声明一个资源工厂使用的外部资源,配置数据库连接池就可在此配置--> <resource-ref>
<description></description> <!--资源说明-->
<res-ref-name></res-ref-name> <!--资源工厂引用名的名称。该名称是一个与java:comp/env上下文相对应的JNDI名称, 在整个Web应用中必须是惟一的-->
<res-type></res-type> <!--servlet代码通过编程注册到资源管理器,或者是容器将代表servlet注册到资源管理器。 该元素的值必须为Application或Container-->
<res-auth></res-auth> <!--是否可以共享通过给定资源管理器连接工厂引用获得的连接。 该元素的值必须为Shareable(默认值)或Unshareable-->
<res-sharing-scope></res-sharing-scope> <!--资源是否可以共享,有Shareable和Unshareable两个值,默认为Shareable-->
</resource-ref> <!--安全限制配置,制定应该保护的URL。它与login-config元素联合使用--> <security-constraint>
<display-name></display-name>
<web-resource-collection> <!--包含一个或多个,描述Web应用程序中的哪些web资源受到指定安全限制的保护-->
<web-resource-name></web-resource-name>
<url-pattern></url-pattern> <!-- 拒绝直接访问地址 -->
<http-method></http-method> <!--指定安全限制覆盖的HTTP方法-->
<http-method></http-method>
</web-resource-collection>
<auth-constraint> <!--描述允许访问Web组件的安全角色。此例中安全角色的例子有tomcat、manager、admin。而只有当作为admin角色的用户才可以访问HelloServlet-->
<role-name></role-name>
<role-name></role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee> <!--指定认证方法,BASIC、FORM、CLIENT-CERT、DIGEST等-->
</user-data-constraint>
</security-constraint> <!--指定服务器应该怎样给试图访问受保护页面的用户授权。它与sercurity-constraint元素联合使用--> <login-config>
<auth-method></auth-method>
<realm-name></realm-name>
<form-login-config>
<form-login-page></form-login-page>
<form-error-page></form-error-page>
</form-login-config>
</login-config> <!--给出安全角色的一个列表,这些角色将出现在servlet元素内的security-role-ref元素的role-name子元素中。分别地声明角色可使高级IDE处理安全信息更为容易--> <security-role>
<role-name></role-name>
</security-role> <!--声明Web应用的环境项--> <env-entry>
<env-entry-name></env-entry-name>
<env-entry-value></env-entry-value>
<env-entry-type></env-entry-type>
</env-entry> <!--声明一个EJB的主目录的引用--> <ejb-ref>
<description>Example EJB reference</decription>
<ejb-ref-name>ejb/Account</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<home>com.mycompany.mypackage.AccountHome</home>
<remote>com.mycompany.mypackage.Account</remote>
</ejb-ref> <!--声明一个EJB的本地主目录的应用--> <ejb-local-ref>
<description>Example Loacal EJB reference</decription>
<ejb-ref-name>ejb/ProcessOrder</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local-home>com.mycompany.mypackage.ProcessOrderHome</local-home>
<local>com.mycompany.mypackage.ProcessOrder</local>
</ejb-local-ref>
</web-app>
一个filter配置多个url-pattern
只要你在web.xml文件配置好要拦截的客户端请求,它都会帮你拦截到请求,此时你就可以对请求或响应(Request、Response)统一设置编码,简化操作
随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关请求,只有当你的web应用停止或重新部署的时候才销毁
<filter> <filter-name>authority</filter-name> <filter-class>com.util.AuthorityFilter</filter-class> </filter> <filter-mapping> <filter-name>authority</filter-name> <url-pattern>/pages/genbill/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>authority</filter-name> <url-pattern>/pages/cmm/*</url-pattern> </filter-mapping>
注:
<url-pattern>/</url-pattern>匹配到/login这样的路径型url,不会匹配到*.jsp这样的后缀型url,不会进入DispatcherServlet类
<url-pattern>/*</url-pattern>匹配到所有url,包括路径型、后缀型,会进入DispatcherServlet类,再寻找controller,找不到对应的controller而报错
dispatcher元素
2.4版本的servlet规范在部属描述符中新增加了一个<dispatcher>
元素,dispatcher的前提条件当然是要先满足url-pattern,dispatcher必须写在filter-mapping的最后,可以在一个<filter-mapping>元素中加入任意数目的<dispatcher>。如果没有指定任何< dispatcher >元素,默认值是REQUEST。四个可能的值:即REQUEST,FORWARD,INCLUDE和ERROR
1、REQUEST
只要发起的操作是一次HTTP请求,比如请求某个URL、发起了一个GET请求、表单提交方式为POST的POST请求、表单提交方式为GET的GET请求。一次重定向则前后相当于发起了两次请求,这些情况下有几次请求就会走几次指定过滤器。
2、FOWARD
只有当当前页面是通过请求转发转发过来的情形时,才会走指定的过滤器
3、INCLUDE
只要是通过<jsp:include page="xxx.jsp" />,嵌入进来的页面,每嵌入的一个页面,都会走一次指定的过滤器。
4、ERROR
假如web.xml里面配置了<error-page></error-page>
<error-page> <error-code>400</error-code> <location>/filter/error.jsp</location> </error-page> <error-page> <error-code>404</error-code> <location>/filter/error.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/filter/error.jsp</location> </error-page>
意思是HTTP请求响应的状态码只要是400、404、500三种状态码之一,容器就会将请求转发到error.jsp下,这就触发了一次error,走进了配置的DispatchFilter。需要注意的是注意一点的是,虽然把请求转发到error.jsp是一次forward的过程,但是配置成<dispatcher>FORWARD</dispatcher>并不会走DispatchFilter这个过滤器。
web.xml配置Session超时时间注意的单位问题
1、为单个Web应用 配置超时时间可以在web.xml中使用<session-config>元素
<web-app> <!--filter.listener,servlet,and servlet-mapping等元素要在session-config之前--> <session-config> <session-timeout>15 </session-timeout> <!--单位是分钟--> </session-config> ... </web-app>
2、配置Servlet是指定初始化参数决定超时时间
<servlet> <servlet-name>Example</servlet-name> <servlet-class>exa.mp.le.Example2</servlet-class> <init-param> <param-name>timeout</param-name> <param-value>600</param-value> <!--单位是秒钟--> </init-param> ... </servlet>
mime-mapping的作用及配置
用来指定对应的格式的浏览器处理方式,避免在浏览器里直接打开,常用的集中配置如下:
<mime-mapping> <extension>mht</extension> <mime-type>text/x-mht</mime-type> </mime-mapping> <mime-mapping> <extension>rar</extension> <mime-type>application/octet-stream</mime-type> </mime-mapping> <mime-mapping> <extension>iso</extension> <mime-type>application/octet-stream</mime-type> </mime-mapping> <mime-mapping> <extension>ape</extension> <mime-type>application/octet-stream</mime-type> </mime-mapping> <mime-mapping> <extension>rmvb</extension> <mime-type>application/octet-stream</mime-type> </mime-mapping> <mime-mapping> <extension>ico</extension> <mime-type>image/x-icon</mime-type> </mime-mapping> <mime-mapping> <extension>doc</extension> <mime-type>application/msword</mime-type> </mime-mapping> <mime-mapping> <extension>xls</extension> <mime-type>application/vnd.ms-excel</mime-type> </mime-mapping> <mime-mapping> <extension>ppt</extension> <mime-type>application/vnd.ms-powerpoint</mime-type> </mime-mapping>
另外也可以用来配置静态页面的打开编码:
<!-- 修改下面两行以支持静态超文本的自动编码 -->
<mime-mapping>
<extension>htm</extension>
<mime-type>text/html;charset=gb2312</mime-type>
</mime-mapping>
<mime-mapping>
<extension>html</extension>
<mime-type>text/html;charset=gb2312</mime-type>
</mime-mapping>
<welcome-file-list>设置首页注意
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.action</welcome-file>
</welcome-file-list>
访问http://localhost/时,不会去找index.html,出现404错误。 如果手工输入http://localhost/index.html又可以访问。 原因如下:
welcome-file-list的工作原理是,按照welcome-file的list一个一个去检查是否web目录下面存在这个文件,如果存在,继续下面的工作(或者跳转到index.html页面,或者配置有struts的,会直接struts的过滤工作).如上例,先去webcontent(这里是Eclipse的工程目录根目录)下是否真的存在index.html这个文件,如果不存在去找是否存在index.jsp这个文件,以此类推。
welcome-file不一定是html或者jsp等文件,也可以是直接访问一个action,注意的是,一定要在webcontent下面建立一个index.action的空文件,然后使用struts配置去跳转,不然web找不到index.action这个文件,会报404错误
解决方法:
一、在WebRoot下新建一个index.action空文件,这个方法简单实用,强烈推荐。
二、因为 welcome-file 必须是实际存在的文件,不能是action或者servlet路径你可以设置一个 比如 <welcome-file>goindex.jsp</welcome-file>,然后 goindex.jsp 写 <jsp:forward page="index.action" /> 就行了。意思就是借助一个jsp页面来转发请求进入action。
三、在index.html中使用META重定向。<META HTTP-EQUIV="Refresh" CONTENT="0;URL=max/HelloWorld.action">
content="1 是时间控制,表示1秒后自动跳转到要跳转的页面。 content="0 表示打开该页后立即跳转到你要跳转的页面。 url 是要跳转的路径
添加taglib以及在页面中使用标签
在web.xml文件中添加tablib
<taglib>
<taglib-uri>标签库唯一访问标识(必须与标签库tld描述文件中的uri一致)</taglib-uri>
<taglib-location>标签库tld描述文件本地路径(如/WEB-INF/mytag.tld)</taglib-location>
</taglib>
在JSP页面中引用标签库
<%@ taglib uri="标签库唯一访问标识(必须与标签库tld描述文件中的uri一致)" prefix="使用标签时的前缀名"%>
如:<%@ taglib uri="http://mytag.sf.net" prefix="myTag"%>
在JSP页面使用
<上面定义的prefix:标签库描述文件中tag_name 属性名1=”属性值”属性名2=”属性值”>(可选)主体内容</上面定义的prefix:标签库描述文件中tag_name>
如:<myTag:demo.Viewport northTitle="南" westTitle="西"></myTag:demo.Viewport>
使用security-constraint,tomcat四种类型的安全认证
<!-- BASIC:HTTP规范,Base64 这种方式被认为是最不安全的认证,因为它没有提供强烈的加密措施 --> <login-config> <auth-method>BASIC</auth-method> </login-config> <!-- DIGEST:HTTP规范,数据完整性强一些,但不是SSL 相比于BASIC认证,它是种比较安全的认证,它在认证时将请求数据 通过MD5的加密方式进行认证 --> <login-config> <auth-method>DIGEST</auth-method> </login-config> <!-- CLIENT-CERT:J2EE规范,数据完整性很强,公共钥匙(PKC) 这是一种基于客户端证书的认证方式,比较安全。但缺陷是在没有安全证书的客户端无法使用 --> <login-config> <auth-method>CLIENT-CERT</auth-method> </login-config> <!-- FORM:J2EE规范,数据完整性非常弱,没有加密,允许有定制的登录界面 这是种基础自定义表单的认证,你可以指定登录时的验证表单 --> <login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/login.html</form-login-page> <form-error-page>/error.jsp</form-error-page> </form-login-config> </login-config>
获取tomcat中web.xml中定义的环境变量(env-entry)
import java.io.IOException; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 获取tomcat下应用的web.xml文件中的env-entry * 本例获取的原定义为: * <env-entry> <env-entry-name>solr/home</env-entry-name> <env-entry-value>F:/developer/solr-tomcat/solr</env-entry-value> <env-entry-type>java.lang.String</env-entry-type> </env-entry> * @author larry * */ public class TestServlet extends HttpServlet { /** * */ private static final long serialVersionUID = -796123516638912971L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { Context c = new InitialContext(); String home = (String)c.lookup("java:comp/env/solr/home"); System.out.println("solr-home:" + home); } catch (NamingException e) { e.printStackTrace(); } } }