欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

servlet详解(第一篇)

程序员文章站 2022-06-10 16:38:37
servlet基本概述 生命周期方法: void init(servletconfig):出生之后(1次); void service(servletrequest request, servlet...

servlet基本概述

生命周期方法:

void init(servletconfig):出生之后(1次);
void service(servletrequest request, servletresponse response):每次处理请求时都会被调用;
void destroy():临死之前(1次);

特性:

单例,一个类只有一个对象;当然可能存在多个servlet类!
线程不案例的,所以它的效率是高的!
servlet类由我们来写,但对象由服务器来创建,并且由服务器来调用相应的方法。

1 什么是servlet

    ?接收请求数据;
    ?处理请求;
    ?完成响应。

例如:客户端发出登录请求,或者输出注册请求,这些请求都应该由servlet来完成处理!servlet需要我们自己来编写,每个servlet必须实现javax.servlet.servlet接口。

2 实现servlet的方式(由我们自己来写!)

实现servlet有三种方式:
实现javax.servlet.servlet接口;
继承javax.servlet.genericservlet类;
继承javax.servlet.http.httpservlet类;

  通常我们会去继承httpservlet类来完成我们的servlet,但学习servlet还要从javax.servlet.servlet接口开始学习

public interface servlet [servlet中的方法大多数不由我们来调用,而是由tomcat来调用。并且servlet的对象也不由我们来创建,由tomcat来创建!]{
    public void init(servletconfig 
    public servletconfig getservletcconfig) throws servletexception;onfig();
    public void service(servletrequest req, servletresponse res)
            throws servletexception, ioexception;
    public string getservletinfo();
    public void destroy();
}

3 创建helloservlet应用

我们开始第一个servlet应用吧!首先在webapps目录下创建helloservlet目录,它就是我们的应用目录了,然后在helloservlet目录中创建准备javaweb应用所需内容:
?创建/helloservlet/web-inf目录;
?创建/helloservlet/web-inf/classes目录;
?创建/helloservlet/web-inf/lib目录;
  创建/helloservlet/web-inf/web.xml文件;
  接下来我们开始准备完成servlet,完成servlet需要分为两步:
?编写servlet类;
?在web.xml文件中配置servlet;
helloservlet.java
public class helloservlet implements servlet {
    public void init(servletconfig config) throws servletexception {}
    public servletconfig getservletconfig() {return null;}
    public void destroy() {}
    public string getservletinfo() {return null;}

    public void service(servletrequest req, servletresponse res)
            throws servletexception, ioexception {
        system.out.println("hello servlet!");
    }
}
web.xml
    
        hello
        cn.itcast.servlet.helloservlet
    
    
        hello
        /helloworld
      

web.xml中配置servlet详解

在web.xml中配置servlet的目的其实只有一个,就是把访问路径与一个servlet绑定到一起,上面配置是把访问路径:“/helloworld”与“cn.itcast.servlet.helloservlet”绑定到一起。
?:指定helloservlet这个servlet的名称为hello;
?:指定/helloworld访问路径所以访问的servlet名为hello。
和通过这个元素关联在一起了!
接下来,我们编译helloservlet,注意,编译helloservlet时需要导入servlet-api.jar,因为servlet.class等类都在servlet-api.jar中。
javac -classpath f:/tomcat6/lib/servlet-api.jar -d . helloservlet.java
然后把helloservlet.class放到/helloworld/web-inf/classes/目录下,然后启动tomcat,在浏览器中访问:http://localhost:8080/helloservlet/helloworld即可在控制台上看到输出!
?/helloservlet/web-inf/classes/cn/itcast/servlet/helloservlet.class;

servlet接口详解

1servlet的生命周期

所谓xxx的生命周期,就是说xxx的出生、服务,以及死亡。servlet生命周期也是如此!与servlet的生命周期相关的方法有:

?void init(servletconfig);
?void service(servletrequest,servletresponse);
?void destroy();

1.1 servlet的出生

服务器会在servlet第一次被访问时创建servlet,或者是在服务器启动时创建servlet。如果服务器启动时就创建servlet,那么还需要在web.xml文件中配置。也就是说默认情况下,servlet是在第一次被访问时由服务器创建的。
而且一个servlet类型,服务器只创建一个实例对象,例如在我们首次访问时,服务器通过“/helloworld”找到了绑定的servlet名称为cn.itcast.servlet.helloservlet,然后服务器查看这个类型的servlet是否已经创建过,如果没有创建过,那么服务器才会通过反射来创建helloservlet的实例。当我们再次访问时,服务器就不会再次创建helloservlet实例了,而是直接使用上次创建的实例。
在servlet被创建后,服务器会马上调用servlet的void init(servletconfig)方法。请记住, servlet出生后马上就会调用init()方法,而且一个servlet的一生。这个方法只会被调用一次。这好比小孩子出生后马上就要去剪脐带一样,而且剪脐带一生只有一次。
我们可以把一些对servlet的初始化工作放到init方法中!

1.2 servlet服务

  当服务器每次接收到请求时,都会去调用servlet的service()方法来处理请求。服务器接收到一次请求,就会调用service() 方法一次,所以service()方法是会被调用多次的。正因为如此,所以我们才需要把处理请求的代码写到service()方法中!

1.3 servlet的离去

  servlet是不会轻易离去的,通常都是在服务器关闭时servlet才会离去!在服务器被关闭时,服务器会去销毁servlet,在销毁servlet之前服务器会先去调用servlet的destroy()方法,我们可以把servlet的临终遗言放到destroy()方法中,例如对某些资源的释放等代码放到destroy()方法中。

2 servlet接口相关类型

在servlet接口中还存在三个我们不熟悉的类型:

servletrequest:service() 方法的参数,它表示请求对象,它封装了所有与请求相关的数据,它是由服务器创建的;
servletresponse:service()方法的参数,它表示响应对象,在service()方法中完成对客户端的响应需要使用这个对象;
servletconfig:init()方法的参数,它表示servlet配置对象,它对应servlet的配置信息,那对应web.xml文件中的元素。

2.1 servletrequest和servletresponse详解

servletrequest和servletresponse是servlet#service() 方法的两个参数,一个是请求对象,一个是响应对象,可以从servletrequest对象中获取请求数据,可以使用servletresponse对象完成响应。你以后会发现,这两个对象就像是一对恩爱的夫妻,永远不分离,总是成对出现。
servletrequest和servletresponse的实例由服务器创建,然后传递给service()方法。如果在service() 方法中希望使用http相关的功能,那么可以把servletrequest和servletresponse强转成httpservletrequest和httpservletresponse。这也说明我们经常需要在service()方法中对servletrequest和servletresponse进行强转,这是很心烦的事情。不过后面会有一个类来帮我们解决这一问题的。

httpservletrequest方法:

string getparameter(string paramname):获取指定请求参数的值;

string getmethod():获取请求方法,例如get或post;

string getheader(string name):获取指定请求头的值;

void setcharacterencoding(string encoding):设置请求体的编
码!因为get请求没有请求体,所以这个方法只只对post请求有效。当调用request.setcharacterencoding(“utf-8”)之后,再通过getparameter()方法获取参数值时,那么参数值都已经通过了转码,即转换成了utf-8编码。所以,这个方法必须在调用getparameter()方法之前调用!

httpservletresponse方法:
printwriter getwriter():获取字符响应流,使用该流可以向客户端输出响应信息。例如response.getwriter().print(“hello javaweb!”);

servletoutputstream getoutputstream():获取字节响应流,当需要向客户端响应字节数据时,需要使用这个流,例如要向客户端响应图片;

void setcharacterencoding(string encoding):用来设置字符响应流的编码,例如在调用setcharacterencoding(“utf-8”);之后,再response.getwriter()获取字符响应流对象,这时的响应流的编码为utf-8,使用response.getwriter()输出的中文都会转换成utf-8编码后发送给客户端;

void setheader(string name, string value):向客户端添加响应头信息,例如setheader(“refresh”, “3;url=”),表示3秒后自动刷新到;

void setcontenttype(string contenttype):该方法是setheader(“content-type”, “xxx”)的简便方法,即用来添加名为content-type响应头的方法。content-type响应头用来设置响应数据的mime类型,例如要向客户端响应jpg的图片,那么可以setcontenttype(“image/jepg”),如果响应数据为文本类型,那么还要台同时设置编码,例如setcontenttype(“text/html;chartset=utf-8”)表示响应数据类型为文本类型中的html类型,并且该方法会调用setcharacterencoding(“utf-8”)方法;

void senderror(int code, string errormsg):向客户端发送状态码,以及错误消息。例如给客户端发送404:response(404, “您要查找的资源不存在!”)。

2.2 servletconfig

servletconfig对象对应web.xml文件中的元素。例如你想获取当前servlet在web.xml文件中的配置名,那么可以使用servletconfig.getservletname()方法获取!
servlet详解(第一篇)

servletconfig对象是由服务器创建的,然后传递给servlet的init()方法,你可以在init()方法中使用它!

string getservletname():获取servlet在web.xml文件中的配置名称,即指定的名称;
servletcontext getservletcontext():用来获取servletcontext对象,servletcontext会在后面讲解;
string getinitparameter(string name):用来获取在web.xml中配置的初始化参数,通过参数名来获取参数值;
enumeration getinitparameternames():用来获取在web.xml中配置的所有初始化参数名称;

genericservlet

genericservlet是servlet接口的实现类,我们可以通过继承genericservlet来编写自己的servlet。下面是genericservlet类的源代码:

genericservlet.java
public abstract class genericservlet implements servlet, servletconfig,
        java.io.serializable {
    private static final long serialversionuid = 1l;
    private transient servletconfig config;
    public genericservlet() {}
    @override
    public void destroy() {}
    @override
    public string getinitparameter(string name) {
        return getservletconfig().getinitparameter(name);
    }
    @override
    public enumeration getinitparameternames() {
        return getservletconfig().getinitparameternames();
    }
    @override
    public servletconfig getservletconfig() {
        return config;
    }
    @override
    public servletcontext getservletcontext() {
        return getservletconfig().getservletcontext();
    }
    @override
    public string getservletinfo() {
        return "";
    }
    @override
    public void init[实现了servlet的init(servletconfig)方法,把参数config赋给了本类的成员config,然后再调用本类自己的无参的init()方法。](servletconfig config) throws servletexception {
        this.config = config;
        this.init();
    }
    public void init[这个方法是genericservlet自己的方法,而不是从servlet继承下来的。当我们自定义servlet时,如果想完成初始化作用就不要再重复init(servletconfig)方法了,而是应该去重写init()方法。因为在genericservlet中的init(servletconfig)方法中保存了servletconfig对象,如果覆盖了保存servletconfig的代码,那么就不能再使用servletconfig了。]() throws servletexception {}
    public void log(string msg) {
        getservletcontext().log(getservletname() + ": " + msg);
    }
    public void log(string message, throwable t) {
        getservletcontext().log(getservletname() + ": " + message, t);
    }
    @override
    public abstract void service(servletrequest req, servletresponse res)
            throws servletexception, ioexception;
    @override
    public string getservletname() {
        return config.getservletname();
    }
}

2 genericservlet的init()方法

在genericservlet中,定义了一个servletconfig config实例变量,并在init(servletconfig)方法中把参数servletconfig赋给了实例变量。然后在该类的很多方法中使用了实例变量config。
如果子类覆盖了genericservlet的init(stringconfig)方法,那么this.config=config这一条语句就会被覆盖了,也就是说genericservlet的实例变量config的值为null,那么所有依赖config的方法都不能使用了。如果真的希望完成一些初始化操作,那么去覆盖genericservlet提供的init()方法,它是没有参数的init()方法,它会在init(servletconfig)方法中被调用。

3 实现了servletconfig接口

  genericservlet还实现了servletconfig接口,所以可以直接调用getinitparameter()、getservletcontext()等servletconfig的方法。

httpservlet(从事javaweb开发的重点)

上面说了servlet接口和genericservlet都只是httpservlet的父类和父接口,从事web网站开发的人大部分用到的是httpservlrt这个类,下面是这个类的详解

1 httpservlet概述

httpservlet类是genericservlet的子类,它提供了对http请求的特殊支持,所以通常我们都会通过继承httpservlet来完成自定义的servlet。

2 httpservlet覆盖了service()方法

httpservlet类中提供service(httpservletrequest,httpservletresponse)方法,这个方法是httpservlet自己的方法,不是从servlet继承来的。在httpservlet的service(servletrequest,servletresponse)方法中会把servletrequest和servletresponse强转成httpservletrequest和httpservletresponse,然后调用service(httpservletrequest,httpservletresponse)方法,这说明子类可以去覆盖service(httpservletrequest,httpservletresponse)方法即可,这就不用自己去强转请求和响应对象了。

3 doget()和dopost()

在httpservlet的service(httpservletrequest,httpservletresponse)方法会去判断当前请求是get还是post,如果是get请求,那么会去调用本类的doget()方法,如果是post请求会去调用dopost()方法,这说明我们在子类中去覆盖doget()或dopost()方法即可。

public class aservlet extends httpservlet {
    public void doget(httpservletrequest request, httpservletresponse response)
            throws servletexception, ioexception {
        system.out.println("hello doget()...");
    }
}
public class bservlet extends httpservlet {
    public void dopost(httpservletrequest request, httpservletresponse response)
            throws servletexception, ioexception {
        system.out.println("hello dopost()...");
    }
}

servlet其他细节

不要在servlet中创建成员!创建局部变量即可!

可以创建无状态成员!

可以创建有状态的成员,但状态必须为只读的!

1 servlet与线程安全

因为一个类型的servlet只有一个实例对象,那么就有可能会现时出一个servlet同时处理多个请求,那么servlet是否为线程安全的呢?答案是:“不是线程安全的”。这说明servlet的工作效率很高,但也存在线程安全问题!
所以我们不应该在servlet中便宜创建成员变量,因为可能会存在一个线程对这个成员变量进行写操作,另一个线程对这个成员变量进行读操作。

2 让服务器在启动时就创建servlet

默认情况下,服务器会在某个servlet第一次收到请求时创建它。也可以在web.xml中对servlet进行配置,使服务器启动时就创建servlet。

        hello1
        cn.itcast.servlet.hello1servlet
        0[在中配置,其中给出一个非负整数!]
    
    
        hello1
        /hello1
    
    
        hello2
        cn.itcast.servlet.hello2servlet
        1
    
    
        hello2
        /hello2
    
    
        hello3
        cn.itcast.servlet.hello3servlet
        2
    
    
        hello3
        /hello3
    
在元素中配置元素可以让服务器在启动时就创建该servlet,其中元素的值必须是大于等于的整数,它的使用是服务器启动时创建servlet的顺序。上例中,根据的值可以得知服务器创建servlet的顺序为hello1servlet、hello2servlet、hello3servlet。

3url-pattern>

是的子元素,用来指定servlet的访问路径,即url。它必须是以“/”开头!

1)可以在中给出多个,例如:
  
    aservlet
    /aservlet
    /bservlet
    

那么这说明一个servlet绑定了两个url,无论访问/aservlet还是/bservlet,访问的都是aservlet。

2)还可以在中使用通配符,所谓通配符就是星号“*”,星号可以匹配任何url前缀或后缀,使用通配符可以命名一个servlet绑定一组url,例如:
?/servlet/*[路径匹配]:/servlet/a、/servlet/b,都匹配/servlet/*;
?*.do[扩展名匹配]:/abc/def/ghi.do、/a.do,都匹配*.do;
?/*[啥都匹配]:匹配所有url;

请注意,通配符要么为前缀,要么为后缀,不能出现在url中间位置,也不能只有通配符。例如:/.do就是错误的,因为星号出现在url的中间位置上了。.*也是不对的,因为一个url中最多只能出现一个通配符。

4 web.xml文件的继承(了解)

 在${catalina_home}\conf\web.xml中的内容,相当于写到了每个项目的web.xml中,它是所有web.xml的父文件。
每个完整的javaweb应用中都需要有web.xml,但我们不知道所有的web.xml文件都有一个共同的父文件,它在tomcat的conf/web.xml路径。

conf/web.xml



     
        default[它的优先级最低,如果一个请求没有人处理,那么它来处理!它显示404。]
        org.apache.catalina.servlets.defaultservlet[当访问路径不存在时,会执行该servlet!其实我们在访问index.html时也是在执行这个servlet。 ]
        
            debug0listingsfalse
        
        1


    
        jsp
        org.apache.jasper.servlet.jspservlet
        
            forkfalsexpoweredbyfalse
        
        3
    

    
        default
        /[匹配所有url,也就是说用户访问的url路径没有匹配的页面时,那么执行的就是名为default的servlet,即org.apache.catalina.servlets.defaultservlet]
    

    
        jsp
        *.jsp[任何url后缀为jsp的访问,都会执行名为jsp的servlet,即org.apache.jasper.servlet.jspservlet]
        *.jspx
    

    
        30[session的默认超时时间为30分钟,后面讲session时再深入。]
    

    
    
        bmp
        image/bmp
    
    
        htm
        text/html
    [mime类型用来标识网络上资源的媒体类型,这里举例为bmp和html两种mime类型。]

    
        index.html
        index.htm
        index.jsp
    [在应用的web.xml中如果没有对进行覆盖,那么默认主页为index.html、index.html、index.jsp]

servletcontext(重要)

一个项目只有一个servletcontext对象!
我们可以在n多个servlet中来获取这个唯一的对象,使用它可以给多个servlet传递数据!
与天地同寿!!!这个对象在tomcat启动时就创建,在tomcat关闭时才会死去!

1 servletcontext概述

服务器会为每个应用创建一个servletcontext对象:

servletcontext对象的创建是在服务器启动时完成的;
servletcontext对象的销毁是在服务器关闭时完成的。
  servletcontext对象的作用是在整个web应用的动态资源之间共享数据!例如在aservlet中向servletcontext对象中保存一个值,然后在bservlet中就可以获取这个值,这就是共享数据了。

2 获取servletcontext

?servletconfig#getservletcontext();
?genericservlet#getservletcontext();
?httpsession#getservletcontext()
?servletcontextevent#getservletcontext()
在servlet中获取servletcontext对象:
?在void init(servletconfig config)中:servletcontext context = config.getservletcontext();,servletconfig类的getservletcontext()方法可以用来获取servletcontext对象;
在genericeservlet或httpservlet中获取servletcontext对象:
?genericservlet类有getservletcontext()方法,所以可以直接使用this.getservletcontext()来获取;
public class myservlet implements servlet {
public void init(servletconfig config) {
    servletcontext context = config.getservletcontext();
}
…
}
public class myservlet extends httpservlet {
public void doget(httpservletrequest request, httpservletresponse response) {
    servletcontext context = this.getservletcontext();
}
}

3 域[域对象就是用来在多个servlet中传递数据

?域对象必须有要存数据功能
?域对象必须要有取数据功能
域对象内部其实有一个map]对象的功能
servletcontext是javaweb四大域对象之一:
?pagecontext;
?servletrequest;
?httpsession;
?servletcontext;
所有域对象都有存取数据的功能,因为域对象内部有一个map,用来存储数据,下面是servletcontext对象用来操作数据的方法:
?void setattribute(string name, object value):用来存储一个对象,也可以称之为存储一个域属性,例如:servletcontext.setattribute(“xxx”, “xxx”),在servletcontext中保存了一个域属性,域属性名称为xxx,域属性的值为xxx。请注意,如果多次调用该方法,并且使用相同的name,那么会覆盖上一次的值,这一特性与map相同;
?object getattribute(string name):用来获取servletcontext中的数据,当前在获取之前需要先去存储才行,例如:string value = (string)servletcontext.getattribute(“xxx”);,获取名为xxx的域属性;
?void removeattribute(string name):用来移除servletcontext中的域属性,如果参数name指定的域属性不存在,那么本方法什么都不做;
?enumeration getattributenames():获取所有域属性的名称;

4 获取应用初始化参数

?servlet也可以获取初始化参数,但它是局部的参数;也就是说,一个servlet只能获取自己的初始化参数,不能获取别人的,即初始化参数只为一个servlet准备!
?可以配置公共的初始化参数,为所有servlet而用!这需要使用servletcontext才能使用!
还可以使用servletcontext来获取在web.xml文件中配置的应用初始化参数!注意,应用初始化参数与servlet初始化参数不同:
servletcontext context = this.getservletcontext();[获取servletcontext对象]
        string value1 = context.getinitparameter("paramname1");
        string value2 = context.getinitparameter("paramname2");
[通过参数名,获取参数值]       system.out.println(value1 + ", " + value2);

        enumeration names = context.getinitparameternames();[获取所有应用初始化参数名称]
        while(names.hasmoreelements()) {
            system.out.println(names.nextelement());
        }