Servlet(JavaWeb片段三)

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服务器将结果返回给客户端。

官方文档[JSR]

第一个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,值越小,越先被优先加载。

参考:

关于web.xml配置的那些事儿

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内的初始化信息

ServletConfig接口的常用方法

实例:配置字符编码参数信息并在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()获取。

ServletContext接口的常用方法

官网文档

应用:

获取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有以下几种:

  1. InputStream Class.getResourceAsStream(String path) : path 不以’/‘开头时默认是从此类所在的包下取资源,以’/‘开头则是从ClassPath根下获取。其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源。

  2. InputStream Class.getClassLoader.getResourceAsStream(String path):默认则是从ClassPath根下获取,path不能以’/‘开头,最终是由ClassLoader获取资源。

  3. InputStream ServletContext.getResourceAsStream(String path):默认从WebAPP根目录下取资源,Tomcat下path是否以’/‘开头无所谓。

  4. 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\
    
  5. String reqest.getContextPath():返回请求的URL中属于web应用程序的路径,这个路径以斜杠开头,不以斜杠结尾如果请求URL属于站点的根目录,那么返回结果为空字符串(“”)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值