Servlet
Servlet概述
Servlet是使用Java语言编写的运行在服务器端的程序。狭义的Servlet是指Java语言的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类。通常来说,我们把实现了Servlet接口的类称为Servlet。
Servlet由Servlet容器提供,所谓的Servlet容器是指提供了Servlet功能的服务器,Servlet容器将Servlet动态地加载到服务器上。Servlet应用程序的体系结构如下图所示。
Servlet请求首先会被HTTP服务器(Apache、Ngix)接受,HTTP服务器负责静态HTML页面的解析,对于Servlet的请求转交给Servlet容器,Servlet容器会根据web.xml文件中的映射关系,调用相应的Servlet,Servlet将结果返回给Servlet容器,并通过HTTP服务器将结果返回给客户端。
第一个Servlet
1、新建类继承自HttpServlet
public class HelloWeb extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//super.doGet(req, resp); 避免调用父类方法,因为父类会将结果提前返回
resp.getWriter().write("hello,web!");
}
}
注:HttpServlet存在于tomcat类库中,idea开发需要将tomcat运行时的类库导入到项目中。
将tomcat选中之后即可在依赖中看到选项,scope域provided选项含义是在程序开发和测试过程中依赖类库,当程序部署时不依赖(不提供类库,由tomcat提供),也就不会被打入war包中。
2、创建web.xml文件,将虚拟路径进行映射。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>helloWeb</servlet-name>
<servlet-class>web.HelloWeb</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloWeb</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
3、访问http://localhost:8080/hello测试
Servlet类浅析
public interface Servlet {
//servlet第一次被创建时调用
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
//每次请求时都会被调用
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
public String getServletInfo();
//servlet销毁时调用
public void destroy();
}
Servlet是一个接口,抽象类GenericServelt实现了该接口的部分方法,HttpServlet也是实现Servlet的间接抽象类,主要是对GenericServelt类的service方法进行了重写,然后提供了doGet和doPost、doHead等常用请求方法。
HttpServlet对GenericServelt重写了service方法,完成了将ServletRequest/ServletResponse的对象强转为HttpServletRequest/HttpServletResponse类型的对象,然后再次调用形参类型不同的service方法(重载的service方法),在重载的service方法中根据请求方法的类型调用不同的HTTP方法进行处理。
HttpServlet是一个抽象类,但是它本身并没有新增抽象方法,对父类的抽象方法都已经有所实现,所以说我们只需要简单地继承HttpServlet类不需要任何写方法就基本上实现了一个web应用,但是环境是复杂的,所以说通过对父类中特定方法的重写来处理的请求,如果直接实现接口的话,将会添加许多与业务无关的代码,通过HttpServlet的封装,web应用程序的编写更加灵活,并且类也不会显得特别臃肿。
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException(lStrings.getString("http.non_http"));
}
service(request, response);
}
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
...
}
} else if (method.equals(METHOD_HEAD)) {
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
}
...
}
web.xml讲解
web.xml:tomcat对它的定义是web项目描述符,他定义了web项目所需的servelt、filter、listener、error-page等信息,如果web项目不存在上述组件,那么web.xml并不是必须的。项目中如果定义了web.xml,它就会被tomcat加载,读取并加载相应的servlet、filter等信息。
web.xml如何被tomcat加载的呢?
Tomcat加载类和资源的顺序为:
1、/Web-INF/classes
2、/Web-INF/lib/*.jar
3、Bootstrap
4、System
5、$CATALINA_HOME/common/classes
6、$CATALINA_HOME/common/endores/*.jar
7、$CATALINA_HOME/common/lib/*.jar
8、$CATALINA_HOME/shared/classes
9、$CATALINA_HOME/shared/lib/*.jar
在${catalina.base}/conf
下以及${catalina.base}/webapps/AppName/WEB_INF
下都有web.xml这个文件。
web.xml的文件格式定义在Servlet规范中,因此所有符合Servlet规范的Java Servlet Container都会用到它。当tomcat部署应用程序时(在激活过程中,或加载应用程序后),它都会读取通用的conf/web.xml,然后再读取web应用程序中的WEB-INF/web.xml。其实根据他们的位置,我们就可以知道,conf/web.xml文件中的设定会应用于所有的web应用程序,而某些web应用程序下的WEB-INF/web.xml中的设定只应用于该应用程序本身。
web.xml文件标签讲解
<!--
Web.xml依次定议了如下元素:
<web-app>
定义了WEB应用的名字
<display-name></display-name>
声明WEB应用的描述信息
<description></description>
定义过滤器
<filter></filter>
<filter-mapping></filter-mapping>
servlet定义
<servlet></servlet>
<servlet-mapping></servlet-mapping>
<session-config></session-config>
<welcome-file-list></welcome-file-list>
<taglib></taglib>
<resource-ref></resource-ref>
<security-constraint></security-constraint>
<login-config></login-config>
</web-app>
在web.xml中元素定义的先后顺序不能颠倒,否则Tomcat服务器可能会抛出SAXParseException.
-->
<web-app>
<display-name>Sample Application</display-name>
<description>
This is a Sample Application
</description>
<!--
filter 配置Servlet过滤器
filter-name 定义过滤器的名字。当有多个过滤器时,不能同名
filter-class 指定实现这一过滤的类,这个类负责具体的过滤事务
-->
<filter>
<filter-name>SampleFilter</filter-name>
<filter-class>mypack.SampleFilter</filter-class>
</filter>
<!--
filter-mapping 设定过滤器负责过滤的URL
filter-name 过滤器名。这里的名字一定要和filter中的过滤器名匹配
url-pattern 指定过滤器负责过滤的URL
-->
<filter-mapping>
<filter-name>SampleFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<!--
servlet 配置Servlet.
servlet-name 定义Servlet的名字
servlet-class 指定实现这个servlet的类
init-param 定义Servlet的初始化参数和参数值,可有多个init-param。在servlet类中通过getInitParamenter(String name)方法访问初始化参数
load-on-startup 指定当Web应用启动时,装载Servlet的次序。
当值为正数或零时:Servlet容器先加载数值小的servlet,再依次加载其他数值大的servlet.
当值为负或未定义:Servlet容器将在Web客户首次访问这个servlet时加载它
-->
<servlet>
<servlet-name>SampleServlet</servlet-name>
<servlet-class>mypack.SampleServlet</servlet-class>
<init-param>
<param-name>initParam1</param-name>
<param-value>2</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!--
配置servlet映射(下面代码为SampleServlet指定的相对URL为"/sample":
servlet-name 指定servlet的名字,这里的名字应该和<Servlet>元素中定义的名字匹配。
url-pattern 指定访问这个servlet的URL。只需给出相对路径。
-->
<servlet-mapping>
<servlet-name>SampleServlet</servlet-name>
<url-pattern>/sample</url-pattern>
</servlet-mapping>
<!--配置session session用来设定HttpSession的生命周期。单位(秒)-->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<!--配置Welcome文件清单-->
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
<welcome-file>index.htm</welcome-file>
</welcome-file-list>
<!--
配置Tag Library
taglib-uri 设定Tag Library的唯一标识符,在Web应用中将根据这一标识符来引用Tag Library
taglib-location 指定和Tag Library对应的TLD文件的位置
-->
<taglib>
<taglib-uri>/mytaglib</taglib-uri>
<taglib-location>/WEB-INF/mytaglib.tld</taglib-location>
</taglib>
<!--
配置资源引用
description 对所引用的资源的说明
res-ref-name 指定所引用资源的JNDI名字
res-type 指定所引用资源的类名字
res-auth 指定管理所引用资源的Manager,它有两个可选值:
Container:由容器来创建和管理resource
Application:同WEB应用来创建和管理Resource
-->
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/sampleDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<!--
配置安全约束(以下代码指定当用户访问该WEB应用下的所有资源时,必须具备guest角色)
web-resource-collection 声明受保护的WEB资源
auth-constraint 声明可以访问受保护资源的角色,可以包含多个<role-name>子元素
web-resource-name 标识受保护的WEB资源
url-pattern 指定受保护的URL路径
-->
<Security-constraint>
<web-resource-collection>
<web-resource-name>sample appliction</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>guest</role-name>
</auth-constraint>
</Security-constraint>
<!--
配置安全验证登录界面:指定当WEB客户访问受保护的WEB资源时,系统弹出的登录对话框的类型。
auth-method 指定验证方法,它有三个可选值:BASIC(基本验证)、DIGEST(摘要验证)、FORM(表单验证)
realm-name 设定安全域的名称
form-login-config 当验证方法为FORM时,配置验证网页和出错网页
form-login-page 当验证方法为FORM时,设定验证网页
form-error-page 当验证方法为FORM时,设定出错网页
-->
<login-config>
<auth-method>FORM</auth-method>
<realm-name>
Tomcat Server Configuration form-Based Authentication Area
</realm-name>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/error.jsp</form-error-page>
</form-login-config>
</login-config>
<!--配置对安全验证角色的引用-->
<security-role>
<description>
The role that is required to log into the sample application
</description>
<role-name>guest</role-name>
</security-role>
</web-app>
自动加载servlet程序
<load-on-startup>
是<servlet>
元素的子元素,它用于指定servlet的加载时机。该值必须是一个整数,如果该值是一个负数或者没有设置该元素,那么servelt默认在第一次请求的实时候被装载。如果该值是一个正数,Servlet容器将在Web应用启动时加载并初始化Servlet,值越小,越先被优先加载。
参考:
servlet filter URL配置细节
1、同一个Servlet可以映射到一个或多个URL上
实例:/hello
和/web
都映射到了helloweb这个servlet上面了。
<servlet>
<servlet-name>helloWeb</servlet-name>
<servlet-class>web.HelloWeb</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloWeb</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>helloWeb</servlet-name>
<url-pattern>/web</url-pattern>
</servlet-mapping>
2、URL支持通配符映射,但是只能有两种固定的格式:一种格式是"*.扩展名
",另一种格式是/*
。
对于如下的一些映射关系:
Servlet1 映射到 /abc/*
Servlet2 映射到 /*
Servlet3 映射到 /abc
Servlet4 映射到 *.do
问题:
当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应
Servlet引擎将调用Servlet3。
当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。
当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。
匹配原则:匹配最接近的虚拟映射路径
对于filter来说,以上规则也适用。
缺省servlet
如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet。
凡是在web.xml文件中找不到匹配的<servlet-mapping>
元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求。
<servlet>
<servlet-name>helloWeb</servlet-name>
<servlet-class>web.HelloWeb</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloWeb</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
当在浏览器中访问/common.js
,假设web应用根目录并没有这个js文件,那么该请求就会交给名字为helloWeb的servlet处理。
那这里就会有一个疑问,之前的web项目,web下的其他html、css静态资源怎么被处理的呢?web.xml文件中也没有相应的servlet对这些静态资源拦截处理?
其实不然,在web.xml介绍到了tomcat会加载web.xml文件,这个文件有两个,一个是catalina_home/conf/web.xml
,另一个是web应用/WEB-INF/web.xml
文件(如果存在的话),这两个文件都会被tomcat加载,并且运行时会综合这两个文件(合二为一),也可这样认为,catalina_home/conf/web.xml
是一个全局的web.xml,而web应用/WEB-INF/web.xml
是仅限于当前web应用下的一个文件,局部继承全局。
而在catalina_home/conf/web.xml
文件中定义了缺省的(或者说默认的)servlet->DefaultServlet
,当web应用下的web.xml文件没有定义缺省的servlet或者web应用下根本就没有web.xml这个文件,静态资源的请求则会交给tomcat的默认servlet去处理,这就好比子类没有重写父类的方法,当调用子类所继承的方法时会执行父类的方法。所以说没有缺省servlet的配置,静态资源的正常获取都默认被tomcat所处理了。
Tomcat默认的org.apache.catalina.servlets.DefaultServlet
做了什么?
对没有在map映射中找到的请求则会交给DefaultServlet去处理,根据请求头的资源路径找到查找web项目下是否有该文件,如果有的话则以流的形式写入给客户端,没有找到则报404错误。
SpringMVC静态资源拦截问题
解决问题的同时,不要忽略一个点,为什么这样做就能解决静态资源被拦截,其中的原理是什么样的
好文推荐:Servlet容器Tomcat中web.xml中url-pattern的配置详解附带源码分析
规则1:精确匹配,使用contextVersion的exactWrappers
规则2:前缀匹配,使用contextVersion的wildcardWrappers
规则3:扩展名匹配,使用contextVersion的extensionWrappers
规则4:使用资源文件来处理servlet,使用contextVersion的welcomeResources属性,这个属性是个字符串数组
规则7:使用默认的servlet,使用contextVersion的defaultWrapper
文章重点记录和见解:
匹配规则:
精确匹配:存在名称固定的url-pattern
映射到一个具体的servlet
,这些servlet
在初始化的时候将会放入到MappedWrapper[] exactWrappers
当中。
前缀匹配(通配符匹配):如果存在url-pattern
以/*
的映射的servlet
,这些servlet
在初始化的时候将会放入到MappedWrapper[] wildcardWrappers
中。
扩展名匹配:如果存在url-pattern
以*.xx
(*.do、*.aciton
)形式映射的servlet,这些servlet
在初始化的时候将会放入到MappedWrapper[] extensionWrappers
中,tomcat在启动的时候默认将*.jsp
和*.jspx
为代表的JspServlet放入MappedWrapper[] extensionWrappers
中,即使没有url-pattern
以*.xx
(*.do、*.aciton
)形式定义的servelt。
资源文件处理servlet:这里面对应的是全局web.xml下的welcome-file-lise
选项中的三个文件。
默认servlet:存在url-pattern
以/
形式映射的servlet,这个servlet
在初始化的时候将会放入到MappedWrapper defaultWrapper
(非数组类型)中。
web.xml中url-pattern路径匹配规则:前提是存在相应的servlet在MappedWrapper
中,精确匹配>前缀匹配>扩展名匹配>默认servlet,tomcat在扩展名匹配下默认加入了.jsp和.jspx的处理。
路径匹配是一个链式的过程(在代码中,条件分支有所体现),匹配成功,对应的处理器处理,不会再往下继续匹配,处理器处理结果无非就两种成功和失败(常见404),对于没有匹配到本项目中web.xml文件下url-pattern的请求,那么就会交给tomcat的DefaultServlet处理。
第一种配置:所有请求都会被DispatcherServlet处理,index.jsp访问不到,出现静态资源404的现象,原因就是所有的请求都被DispatcherServlet处理,因为已经匹配到并且处理了,所以就不会再去执行tomcat的DefaultServlet。
<!-- Spring MVC -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
...
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
第二种配置:只有*.do
和*.action
的请求才会被DispatcherServlet
处理,其他的静态资源请求由于没有匹配到对应的url-pattern,所以最后会被tomcat默认的servlet处理,index.jsp能够访问,静态资源能够请求成功。
注意
*.do
不要写成/*.do
,不然你会发现连tomcat都不能正常启动。前缀和扩展名匹配无法同时设置,比如下面的三个url-pattern都是非法的,如果设置,启动tomcat服务器会报错。
<url-pattern>/kata/*.jsp</url-pattern> <url-pattern>/*.jsp</url-pattern> <url-pattern>he*.jsp</url-pattern>
<servlet>
...
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
第三种配置:这种情况,index.jsp能够被访问,tomcat提供了默认处理,但是对于其它的静态资源结果就是404了,因为他重写了CATALINA_BASE/conf/web.xml
下的默认的servlet配置,也就是说这次没有匹配到的请求依然会去执行默认servlet,但是不是执行的tomcat下的,而是本项目下默认的servlet。
<servlet>
...
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
解决方案:
- 通过tomcat的defaultServlet处理
<!--通过defaultServlet来处理静态资源-->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
<url-pattern>*.png</url-pattern>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
- 通过Spring的mvc:resource来配置资源映射,将静态资源的映射进行放行。
<!-- 放行静态资源 -->
<!--放行js文件-->
<mvc:resources location="/js/" mapping="/js/**"/> <!--放行css文件-->
<mvc:resources location="/css/" mapping="/css/**"/>
<!--放行img类的资源文件-->
<mvc:resources location="/images/" mapping="/images/**"/>1234567
- 通过Spring MVC的mvc:default-handler/:通过这个标签可以启动Spring
MVC定义的一个类似于Tomcat的DefaultServlet的DefaultServletHttpRequestHandler类。
<mvc:default-servlet-handler />
静态资源也是会经过servlet处理的。
之前犯了一个错误,将匹配顺序误以为另一个语义了,认为匹配失败之后本次请求就丢弃掉了,在SpringMVC中,当初认为如果请求不是*.do
和*.action
结尾的,结果肯定404,匹配失败,实际上请求路径匹配是个条件式的,这个条件不成立,匹配下一个条件,如果本项目web.xml文件下的url选项都匹配过没有符合项,则交给tomcat默认servlet处理。另外路径为<url-pattern>/</url-pattern>
代表重写了tomcat默认servlet,要想静态资源能够访问,需要<servlet-name>default</servlet-name>
来实现。
嵌入式tomcat
搞嵌入式tomcat的原因是因为,当初看了Servlet容器Tomcat中web.xml中url-pattern的配置详解附带源码分析这篇文章,发现其中有对tomcat调试,tomcat源码debug网上教程看着有些麻烦,所以说使用嵌入式tomcat对代码debug。
- 如何实现嵌入式tomcat?
- 嵌入式tomcat不需要web.xml文件,什么类可以实现web.xml功能?
public class EmbedStartup {
public static void main(String[] args) throws Exception {
int port = 8080;
if (args.length == 1) {
port = Integer.parseInt(args[0]);
}
// 获取项目绝对路径
File webappPath = new File("G:\\studyWorkspace\\mvnProj\\embedweb");
// 创建tomat容器
Tomcat tomcat = new Tomcat();
// 设置端口
tomcat.setPort(port);
// 设置webapp目录
//StandardContext sct = (StandardContext) tomcat.addWebapp("/embedweb", webappPath.getAbsolutePath());
Context sct = tomcat.addWebapp("/embedweb", webappPath.getAbsolutePath());
sct.getServletContext().setAttribute(Globals.ALT_DD_ATTR, "G:\\studyWorkspace\\mvnProj\\embedweb\\src\\main\\webapp\\WEB-INF\\web.xml");
// web项目路径
WebResourceRoot resourceRoot = new StandardRoot(sct);
// 相当于webapps中的一个项目文件夹
DirResourceSet dirResourceSet = new DirResourceSet();
// java字节码文件路径
dirResourceSet.setBase(new File("embedweb/target/classes").getAbsolutePath());
// tomcat的默认写法 /WEB-INF/classes web项目的默认
dirResourceSet.setWebAppMount("/WEB-INF/classes");
// 这个项目文件夹的上一级目录,在tomcat中就是webapps
dirResourceSet.setRoot(resourceRoot);
dirResourceSet.setInternalPath("/");
// 相当于把项目设置到webapp中
resourceRoot.addPreResources(dirResourceSet);
sct.setReloadable(false);
// 一个web项目
sct.setResources(resourceRoot);
tomcat.start();
System.out.println("Tomcat已在本地" + port + "端口启动!");
// 方法阻塞,否则main方法运行完毕就退出,tomcat也就关闭了
tomcat.getServer().await();
}
}
Servlet运行过程
web服务器收到客户端的Servlet访问请求后:
是否创建Servlet实例
---否-->装载并创建该Servlet实例
--->调用Servlet实例对象的init()方法。
1.--->创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的 HttpServletResponse对象
2.--->调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
3.--->应用程序停止或重启之前,调用destroy方法,Servlet引擎卸载Servlet
Servlet相关对象
ServletConfig
在Servlet初始化运行时,可能需要一些配置信息,比如说编码集、配置信息等。在web.xml中,可以使用一个或多个<init-param>
元素为servlet提供初始信息,当Servlet被tomcat初始化时,这些信息都会被封装到一个ServletConfig对象里面。
ServletConfig对象的获取可以通过重写Servlet
接口的init
方法保留ServletConfig
引用,另一种是直接调用父类的getServletConfig
方法获取。
获取Servlet内的初始化信息
实例:配置字符编码参数信息并在Servlet中读取
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>web.HelloWeb</servlet-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</servlet>
之后在servlet中通过ServletConfig
读取配置信息
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletConfig servletConfig = getServletConfig();
String encoding = servletConfig.getInitParameter("encoding");
System.out.println(encoding);//utf8
}
ServletContext
容器启动时, 会为每个Web应用创建一个唯一的ServletContext
对象代表当前Web应用,该对象封装了当前Web应用的所有信息,并且实现了多个Servlet之间的数据共享。
<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
<display-name></display-name>
<!-- 配置WEB应用的初始化参数 -->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/test</param-value>
</context-param>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
在上例中,context-param
元素位于web-app
根元素下,param-name和param-value指定了参数的名字和值。要想获取这些参数,可以通过ServletContext
接口中定义的getInitParameterNames()
和getInitParameter(String name)
方法获取参数名和参数值。ServletConfig接口中为了ServletContext
对象,可以直接通过调用getServletContext或者getServletConfig().getServletContext()获取。
应用:
获取Web应用的初始化信息
实现多个Servlet对象共享数据
读取Web应用下的资源文件
ServletContext.getResourceAsStream
默认从web应用根路径下读取资源文件,"/"不是必须的。
如果我的项目目录如上,配置文件所在的位置不一样,使用ServletContext.getResourceAsStream
读取如下:
// 默认就是从webapp根目录下读取
InputStream in = servletContext.getResourceAsStream("/jdbc.properties");
// 读取路径WEB-INF/
in = servletContext.getResourceAsStream("WEB-INF/jdbc.properties");
// 类路径下读取
in = servletContext.getResourceAsStream("WEB-INF/classes/jdbc.properties");
in = servletContext.getResourceAsStream("WEB-INF/classes/front/jdbc.properties");
路径问题
首先,Java中的getResourceAsStream
有以下几种:
-
InputStream Class.getResourceAsStream(String path)
: path 不以’/‘开头时默认是从此类所在的包下取资源,以’/‘开头则是从ClassPath根下获取。其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源。 -
InputStream Class.getClassLoader.getResourceAsStream(String path)
:默认则是从ClassPath根下获取,path不能以’/‘开头,最终是由ClassLoader获取资源。 -
InputStream ServletContext.getResourceAsStream(String path)
:默认从WebAPP根目录下取资源,Tomcat下path是否以’/‘开头无所谓。 -
String ServletContext.getRealPath(String path)
:返回资源文件在服务器文件系统上的真实路径(文件的绝对路径)。参数path代表资源文件的虚拟路径,应该以“/”开头,代表web根目录,规范化。如果不以“/”开头,也是从web应用根路径读起。String realPath = this.getServletContext().getRealPath("/jdbc.properties"); String realPath1 = this.getServletContext().getRealPath("jdbc.properties"); String realPath2 = this.getServletContext().getRealPath("/WEB-INF/jdbc.properties"); String realPath3 = this.getServletContext().getRealPath(""); System.out.println(realPath); System.out.println(realPath1); System.out.println(realPath2); System.out.println(realPath3); // 输出 G:\studyWorkspace\javaWebProj\out\artifacts\web02_war_exploded\jdbc.properties G:\studyWorkspace\javaWebProj\out\artifacts\web02_war_exploded\jdbc.properties G:\studyWorkspace\javaWebProj\out\artifacts\web02_war_exploded\WEB-INF\jdbc.properties G:\studyWorkspace\javaWebProj\out\artifacts\web02_war_exploded\
-
String reqest.getContextPath()
:返回请求的URL中属于web应用程序的路径,这个路径以斜杠开头,不以斜杠结尾,如果请求URL属于站点的根目录,那么返回结果为空字符串(“”)。