Servlet(一)

一、什么是Servlet?

顾名思义,server applet ,运行在服务器端的Java小程序,定义了一个类被浏览器访问的规则,是一个接口。

功能:接受请求、处理请求、作出响应

二、Servlet初涉

(1)原始的开发流程

1--创建web项目
2--定义一个Java类,实现Servlet接口
3--重写所有未实现方法(5个)

4--在web.xml配置Servlet

(2)实现的五个方法的说明

package org.wzj.servlet;

import javax.servlet.*;
import java.io.IOException;

public class ServletDemo1 implements Servlet {

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
            //方法1
    }

    @Override
    public ServletConfig getServletConfig() {
           //方法2
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException,IOException{
           //方法3  
    }

    @Override
    public String getServletInfo() {
          //方法4
        return null;
    }

    @Override
    public void destroy() {
         //方法5
    }
}

方法1的说明:默认情况下,当Servlet第一次被创建时,调用此init()方法;那么Servlet什么时候被创建呢?你第一次客户端请求的时候,服务器(容器--引擎)就会读取web.xml配置文件,通过servlet和servlet-mapping的标签获取类的全路径名,然后通过反射创建Servelt对象,调用init()方法,进行初始化,此方法只调用一次。

特点:只执行一次,Servlet是单例的,但是可能会存在线程安全问题,尽量不要定义成员变量。

初始化的功能:一般做一些准备工作

问题:准备工作(写了大量的代码),比较耗时用户体验不好

需求:在服务器一开启,我就把初始化的工作准备好

我们可以在web.xml中配置init方法的初始化时机(那用户在再来请求的时候,就不用再等待初始化了)

说明1:-1是默认值,表示用户第一次请求的时候,才去执行init方法

说明2:非负整数服务器一开启就执行init方法,数值越小执行的时机越早(可以在一个web.xml中配置多个servlet)

简单的配置:在web.xml的<servlet>标签中配置<load-on-startup>

用法:建立数据库的连接,获取配置信息。

方法2的说明:获取代当前Servlet在web.xml中的配置信息

说明:当servlet配置了初始化参数之后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象(服务器创建)中,并在调用servlet的init方法时,将ServletConfig对象传递给Servlet,进而可以通过servlet对象得到当前servlet的初始化参数信息。

具体方式:在Servlet 的配置文件中,用一个或多个<init-param>标签(键值对的形式)为当前Servlet配置一些初始化参数。

注意:一个servlet被实例化后,任何客户端在任何时候访问有效(但仅对本servlet有效),一个servlet的ServletConfig对象不能被另一个servlet访问。

用法:将数据库信息编码方式等配置信息放在web.xml中,如果以后数据库的用户名、密码改变了,则直接很方便地修改web.xml就行了,避免了直接修改源代码的麻烦。

配置对象:ServletConfig

特点:是一个接口,在Servlet初始化的时候,由服务器创建其子类对象,将配置信息封装到对象中传递给init()方法

常用的方法

(1) String getInitParameter(String name)    --键找值

(2) Enumeration getInitParameterNames()  --获取当前Servlet所有初始化参数的名字组成的枚举

(3)String getServletName()  -- 获取当前Servlet在web.xml中配置的名字(别名)

(4)ServletContext getServletContext()  -- 获取代表当前Web应用的ServletContext(上下文--全局域)对象(重点!!!)

前提:全局域对象有内容--键值对的形式

具体使用: 要想使用该方法获取ServletConfig对象,则需要提升config对象的作用域。

(1)声明 私有的成员变量ServletConfig 
(2)在init方法中赋值
(3)在getServletConfig方法中 获取

关于初始化时机配置信息在web.xml中如下:

<?xml version="1.0" encoding="UTF-8"?>
<!--.rsd作为xml的约束文档-->
<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">
    <!--一个web.xml可以配置多个servlet-->
    <servlet>
        <!--servlet的别名(随便起)-->
        <servlet-name>haha</servlet-name>
        <!--servlet的全路径名称(包含包名)-->
        <servlet-class>org.wzj.servlet.MyServlet</servlet-class>
        <!--初始化参数的配置信息(在加载时机之前)(可以配置多个参数)-->
        <init-param>
            <param-name>username</param-name>
            <param-value>Jane</param-value>
        </init-param>
        <!--初始化的加载时机(服务器开启之后,客户端请求之前完成)-->
        <load-on-startup>-1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <!--当前servlet的映射信息-->
        <servlet-name>haha</servlet-name>
        <url-pattern>/MyServlet</url-pattern>
    </servlet-mapping>
</web-app>

Java代码(原始的创建Servlet的方式--继承Servlet接口的形式)

package org.wzj.servlet;

import javax.servlet.*;
import java.io.IOException;

public class MyServlet implements Servlet {
    //提升作用域(成员变量)并提供一个公共的接口供外界访问--屏蔽具体的细节
    private ServletConfig servletConfig;
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        this.servletConfig=servletConfig;
        System.out.println("servlet对象创建成功,并成功进行init()初始化!");
    }
    /**
     * 说明:提供公共的方法供外界访问
     * @return
     */
    @Override
    public ServletConfig getServletConfig() {
        return servletConfig;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException,IOException{
        System.out.println("servlet开始建功立业!");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {
        System.out.println("Servlet即将谢幕!");
    }
}

方法3的说明:获取请求,然后处理客户端的请求并给予反馈

特点:客户端每请求一次,服务器就会单独开辟一个线程,执行一次

方法4的说明:返回一个String类型的字符串(纯文本),包含Servlet的一些基本信息(作者、版本、版权等)--了解即可

方法5的说明:将servlet对象从服务中移除(服务器正常关闭也会调用)

时机:容器检测到一个servlet对象从服务器从服务中移除时,会调用该方法,该对象一段时间内会被Java的垃圾回收器所回收。

作用:释放该servlet占用的资源,保存数据到持球存储设备中(硬盘、U盘等)

常见:内存中的数据保存到数据库中,关闭数据库的连接等,主要是一些善后工作。

三、Servlet的生命周期

Servlet的生命周期方法:创建(init)---提供服务(service)---销毁(destroy)

回顾:多线程的生命周期

四、Servlet的原理


五、Servlet创建方式

(1) 实现Servlet

不好:有些方法没有用,方法赘余!

(2)继承GenericServlet(了解即可)

1、采用适配器模式(GenericServlet除了service没有实现之外,其余的四个方法都实现了!是一个抽象类)

2、对ServletConfig进行优化,提升config对象的作用域(私有的成员变量)

3、实现了ServletConfig接口,简化对config对象的使用方式(因此也是ServletConfig的对象,不需要层层调用了!)

缺点:由于service有7种提交方式,目前浏览器仅实现两种(Get和Post的提交方式),其他方法(预留)也无用

(3)继承HttpServlet(最终版--对http协议的封装)

特点1:继承体系--继承自GenericServlet

特点2:重写doGet()和doPost()的方法     

注意:去掉super.doGet()super.doPost()--完全重写,不需要父类的功能。

说明:常在Get或Post中调用另外一个的该方法(后续报道!!!)

-------------------------------

六、ServletContext接口

说明:表示一个Web应用程序的上下文(全局域对象),在它所代表的范围内可以共享数据

特点:是单例的,Web容器在启动时会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。

说明:一个Web应用中的所有Servlet共享同一个ServletContext对象(不管这些Servlet是否为同一个客户进行服务),因此Servlet对象之间可以通过ServletContext对象来实现通信。ServletContext对象通常也被称之为context域对象,该对象中维护了ServletContext对象的引用

(1)获取ServletContext对象方式

方式1:this.getServletConfig().getServletContext()

原因:Servlet容器在Servlet初始化期间,向其传递ServletConfig对象,而ServletConfig对象中维护了ServletContext对象的引

用,可以通过getServletContext()的方式获取该对象

方式2:this.getServletContext()

原因:GenericServlet抽象类继承了ServletConfig,this也相当于ServletConfig的对象,所以可以直接调用。

说明:方式1和方式2获取的对象是一致的,都是通过ServletConfig对象中的getServletContext()方法获取的。

ServletContext常用的方法

ServletContext的作用1:在域的范围内共享数据

1)setAttribute("键--字符串",值);

功能:设置共享数据(一定要有意义!)

结果:共享数据存储在全局域中,当前Web的其它servlet也可以访问。

2)getAttribute("键"):

功能:获取共享属性

3)getAttributeNames();

注意:返回的是枚举(Enumeration)类型

4) removeAttribute("键")

说明:删除对应的共享属性(配置文件中的无法删除)

5)getInitParameter("键");

6)getInitParameterNames()

说明:获取配置信息中所有的键(枚举的形式)

说明:为Servlet上下文定义初始化参数.可以被整个Web应用程序所使用。在web.xml中的<context-param>定义上下文初始化

参数,上面的两个方法用于访问这些参数。

测试:在web中写一个login,html的表单提交,提交到Servlet01,在Servlet01中设置上下文共享数据,在Servlet02中看是否获取

配置信息(在web-app第一个子节点)

<!--(1)给上下文对象配置参数-->
    <context-param>
        <param-name>id</param-name>
        <param-value>001</param-value>
    </context-param>

Servlet01

package org.wzj.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class Servlet01 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //(1)获取上下文对象(简易方式)
        ServletContext context = this.getServletContext();
        //(2)存储数据
        context.setAttribute("name","Servlet");
        //(3)获取web.xml中配置的上下文初始化参数
        String id = context.getInitParameter("id");
        System.out.println(id);
        //(4)移除此id对应的配置参数,在另外一个Servlet中是否能获取到
        //说明:移除共享属性(只能移除在其它servlet中设置的共享数据,不能移除web,xml中的)

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}

Servlet02

package org.wzj.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

public class Servlet02 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //需求:获取上下文共享的数据
        //(1)获取上下文的对象
        ServletContext context = this.getServletContext();
        //(2)获取全部的上下文配置信息(共享数据)--键的集合
        Enumeration<String> initParameterNames = context.getInitParameterNames();
        //(3)注意枚举的遍历方式
        if(initParameterNames!=null){
            while(initParameterNames.hasMoreElements()){
                String parm = initParameterNames.nextElement();
                String id = context.getInitParameter(parm);
                System.out.println(id);
            }
        }
        //(4)获取其它Servlet传递过来的数据(共享数据)
        String username = (String) context.getAttribute("name");
        System.out.println(username);

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

-----------------------------------

思考:在普通项目下通过src获取项目下的文件(前提是在src下)或者当前项目下,那么在Web项目呢?

作用2:获取文件运行的真实路径(服务器路径)

测试(三种情况):

 * 1.web下:项目根目录下

 * 2.WEB-INF下:项目根目录下/WEB-INF

 * 3.src下: 项目根目录下/WEB-INF/classes

%1、getRealPath()

说明:返回的是资源服务器文件系统(硬盘)的真实路径(文件的绝对路径)

服务器路径:看项目发布后资源文件在硬盘的的位置(可以明白),而不是IDEA中文件位置!!!

相关代码

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;

//说明:通过注解形式,name可以不写,但value(映射信息必须有!)
public class Servlet01 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //需求1:获取src下的b.txt
        //错误的方式(竟然成功了!!!--值得深思)
        File file = new File("src/b.txt");
        System.out.println(file);
        //标准方式
        ServletContext context = this.getServletContext();
        //获取文件的真实(服务器的)路径
        String realPath = context.getRealPath("/WEB-INF/classes/b.txt");
        //原因:项目发布后,服务器路径中的src的文件是在\ServletWeb02\WEB-INF\classes中
        //说明:"/"就表示当前的上下文路径--ServletWeb02
        System.out.println(realPath);
        //需求2:获取a.txt(/ServletWeb02)
        String realPath1 = context.getRealPath("/a.txt");
        System.out.println(realPath1);
        //需求3:获取c.txt(web/WEB-INF/)--不存在web的事情!!!
        context.getRealPath("/WEB-INF/c.txt");
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

说明:ServletContext只能用于web环境获取路径

%2、getResource()

思考:如果是非web环境,则使用什么来获取真实路径?

答:ClassLoader类加载器

需求:我Web项目里有一个普通的java工具类,我想通过Java类获取文件的真实路径 那我就用不了ServletContext

import java.net.URL;

public class JavaUtils {
    private static JavaUtils javaUtils;
    public static void main(String[] args) {
        //说明:Web项目中,普通Java类访问文件的情况
        //方式1:
        //1.获取该类对应的类加载器对象
        ClassLoader loader = javaUtils.getClass().getClassLoader();
        //2.获取文件运行的真实路径
        //说明:Resource表示src
        URL url = loader.getResource("b.txt");
        System.out.println(url);
        //-------------------------
        //方式2:返回的是输出流对象--------'/'表示src目录
        JavaUtils.class.getResourceAsStream("/b.txt");
    }
}

注意:类加载器来获取路径也有局限性,只能获取src目录下的文件。

思考3:如果在Servlet中要使用工具类获取文件的路径呢?

答:与ServletContext有关的,你懂的!!!

------------------------------

Servlet的工作原理

--------------------

打war包--项目上线,要部署项目(回顾项目的三种发布方式!!!)

方式1:手动打war包

找到文件的webapp中的路径(服务器路径),压缩成zip格式后,修改后缀名,放到服务器路径即可,此时会自动解压,切删除war包对应的解压文件也会删除!!!

方式2:IDEA自动打war包

(1)知道war包的路径--并勾选主build ...
(2)build --

----------------------


猜你喜欢

转载自blog.csdn.net/wzj_110/article/details/80579748