JavaWeb基础学习(二)--Servlet

 

一. Servlet简介

 

基于Java技术的Web组件,运行在服务器端,由Servlet容器管理,用于生成动态内容。

Servlet容器管理Servlet,负责Servlet和客户的通信以及调用Servlet的方法。

Servlet功能:

  1. 接收用户请求的http协议
  2. 返回http响应协议

 

Servlet优势:

  1. Servlet 在 Web 服务器的地址空间内执行。这样它就没有必要再创建一个单独的进程来处理每个客户端请求。
  2. Servlet 是独立于平台的,因为它是用 Java 编写的。
  3. 服务器上的 Java 安全管理器执行了一系列限制,以保护服务器计算机上的资源。因此,Servlet 是可信的。
  4. Java 类库的全部功能对 Servlet 来说都是可用的。它可通过 sockets 和 RMI 机制与 applets、数据库或其他软件进行交互。

 

Servlet框架:

 

Servlet实现方式:

  1. 实现javax.servlet.Servlet接口                                           (对应三)
  2. 继承javax.servlet.GenericServlet类                                  (对应六)
  3. 继承javax.servlet.http.HttpServlet类(常用方式)     (对应七)

 

Servlet核心jar包:

         tomcat/lib目录下的servlet-api.jar

 

响应客户请求的过程:

 

二. 在web.xml中配置Servlet

 

在新建项目的WebContent\WEB-INF\下,有web.xml配置文件。如果没有,新建项目时,第三步需要勾选

在根标签<web-app></webapp>中配置Servlet的相关信息,如下:

  <servlet>

         <!-- 声明名字,可以任意 -->

         <servlet-name>firstServlet</servlet-name>

         <!-- 声明类名字 -->

         <servlet-class>com.qibao.servlet.firstServlet</servlet-class>

    </servlet>

   

    <!-- 配置如何访问这个servlet -->

    <servlet-mapping>

         <!-- 必须和要和 某个声明的servlet名字一样 -->

         <servlet-name>oneServlet</servlet-name>

         <!-- 声明访问的url路径 -->

         <url-pattern>/first</url-pattern>

    </servlet-mapping>

  1. Servlet程序必须通过Servlet容器来启动运行,并且储存目录有特殊要求,需要存储在<WEB应用程序目录>\WEB-INF\classes\目录中。
  2. Servlet程序必须在WEB应用程序的web.xml文件中进行注册和映射其访问路径,才可以被Servlet引擎加载和被外界访问。
  3. 一个<servlet>元素用于注册一个Servlet,它包含有两个主要的子元素:<servlet-name>和<servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整类名。
  4. 一个<servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:<servlet-name>和<url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。

 

  • 一个Servlet可映射多个URL,即多个<servlet-mapping>元素的<servlet-name>设置的值可以是同一个Servlet的注册名。
  • Servlet映射中可使用*通配符,但是只能有两种固定的格式:一种格式是“*.扩展名”;另一种格式是以正斜杠/开头并以“/*”结尾,例如/action/*。/代表当前web应用的路径,即http://localhost:8080/webapp/
  • * 两边不能同时出现数据  /action/*do

 

<load-on-startup>1</load-on-startup>

在<servlet></servlet>标签中添加,容器加载web应用时,就创建此servlet实例,并调用init()方法.需要一个大于0的整数.值越小优先级越高.

不加这个选项只有当页面第一次发送请求时才去创建servlet,调用init().

通过注解的方式注册Servlet

@WebServlet("/firstServlet")

  1. @WebServlet 用于将一个类声明为 Servlet
  2. @WebInitParam该注解通常不单独使用,而是配合 @WebServlet 或者 @WebFilter 使用。它的作用是为 Servlet 或者过滤器指定初始化参数

属性名

类型

描述

name

String

指定 Servlet name 属性。如果没有显式指定,则该 Servlet 的取值即为类的全限定名。

value

String[]

该属性等价于 urlPatterns 属性

urlPatterns

String[]

指定一组 Servlet URL 匹配模式

loadOnStartup

int

指定 Servlet 的加载顺序

initParams

WebInitParam[]

指定一组 Servlet 初始化参数

asyncSupported

boolean

声明 Servlet 是否支持异步操作模式

description

String

Servlet 的描述信息

displayName

String

Servlet 的显示名,通常配合工具使用

 

Servlet的调用过程:

 

三. 实现Servlet接口

 

开发Servlet的第一种方式——实现Servlet接口。

        Servlet接口中有六个方法需要实现:

public class FirstServlet implements Servlet {

    //tomcat服务停止时,初始化Servlet的方法,由tomcat调用,只执行一次。

    @Override

    public void init(ServletConfig arg0) throws ServletException {}



    //用户的每一次请求,都会执行这个方法,由用户发出请求,由tomcat调用这个方法

    @Override

    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {}



    //tomcat服务停止时,服务器会去销毁Servlet,由tomcat调用,用于清空某些资源,只调用一次

    @Override

    public void destroy() {}

   

    //获取这个servlet在web.xml中的配置信息

    @Override

    public ServletConfig getServletConfig() {return null;}



    //获取这个serlvet的名称

    @Override

    public String getServletInfo() {return null;}

}

 

四. Servlet生命周期

指的就是Servlet的出生到结束。分别经历了加载、初始化、服务、销毁。

  1. 加载阶段:加载并实例化,创建servlet实例,只调用一次构造方法;
  2. 初始化阶段: 调用init()方法,只调用一次初始化方法;
  3. 响应客户请求阶段:调用service()方法,一般业务逻辑在这里处理;
  4. 终止阶段:调用destroy()方法。

当请求servlet的时候:

  • Servlet引擎检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
  • 装载并创建该Servlet的一个实例对象:调用该 Servlet 的构造器
  • 调用Servlet实例对象的init()方法。
  • 创建一个用于封装请求的ServletRequest对象和一个代表响应消息的ServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
  • WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。

 

五. ServletConfig接口

 

功能:读取web.xml中配置的serlvet信息。

 

Servlet容器将代表当前web应用的对象(ServletContext)和Servlet的配置参数信息一并封装到一个称为ServletConfig的对象中,并在初始化Servlet实例对象时调用init(ServletConfig  config)方法将ServletConfig对象传递给Servlet。

 

常见方法(可在初始化时通过传入的参数ServletConfig  config调用):

  • getServletName()                      获取当前Servlet在web.xml中配置的名字
  • getServletContext()           获取代表当前web应用的ServletContext对象
  • getInitParameter(String)   获取当前Servlet指定名称的初始化参数的值
  • getInitParameterNames()  获取当前Servlet所有初始化参数的名字组成的枚举

配置web.xml

    <servlet>

         <servlet-name>secondServlet</servlet-name>

         <servlet-class>com.qibao.servlet.SecondServlet</servlet-class>

         <init-param>

             <param-name>username</param-name>

             <param-value>admin</param-value>

         </init-param>

         <init-param>

             <param-name>password</param-name>

             <param-value>123456</param-value>

         </init-param>

    </servlet>

    <servlet-mapping>

         <servlet-name>secondServlet</servlet-name>

         <url-pattern>/second.do</url-pattern>

    </servlet-mapping>

在init(ServletConfig  config)方法中调用:

    @Override

    public void init(ServletConfig config) throws ServletException {

         System.err.println("在配置文件中的名称:" + config.getServletName());

         //获取所有初始化参数的名字组成的枚举

         Enumeration<String> en = config.getInitParameterNames();

         while (en.hasMoreElements()) {

             String nm = (String) en.nextElement();

             // 根据初始化的名字获取值

             String value = config.getInitParameter(nm);

             System.err.println(nm + ":" + value);

         }

    }

 

六. GenericServlet

 

开发Servlet的第二种方式——继承GenericServlet类。

省略在web.xml中配置的环节,直接看代码

public class SecondServlet extends GenericServlet{

    private static final long serialVersionUID = 1L;

    @Override
    public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {}

}
  1. GenericServlet提供除service()方法外所有Servlet接口中方法的缺省实现,GenericServlet的方法,只有service(req,res)是抽象方法,只需要实现这个方法就好
  2. GenericServlet也实现了ServletConfig接口,处理初始化参数和servlet上下文,提供对授权传递到init()方法中的ServletConfig对象的获取方法getServletConfig()。
  3. 如果要做初始化操作,可重写GenericServlet中的init()方法 。而非init(servleconfig)带参数的方法。 init() --- 此方法不是serlvet的生命周期方法,只是被GenericSerlvet中的init(servleconfig)再次调用的方法 。

1:实现了javax.serlvet.Selvet接口,用户只需要重写service方法;

2:包装了SevletConfig用户可直接调用。

 

七. HttpServlet

 

开发Servlet的第三种方式——继承HttpServlet类。

  1. HttpServlet是GenericServlet的子类
  2. HttpServlet 类通过调用指定到HTTP请求的方法实现service()
  3. 通过HttpServlet去开发servlet,需要重写doGet、doPost方法
@WebServlet("/thirdServlet")

public class ThirdServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public ThirdServlet() {super();}



    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

         response.getWriter().append("Served at: ").append(request.getContextPath());

    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

         doGet(request, response);

    }

}

  • 调用 MyServlet的service(ServletRequest, ServletResponse)方法,但MyServlet没有重写这个方法,所以到MyServlet的父类HttpServlet去找;
  • 调用HttpServlet的service(ServletRequest, ServletResponse)方法,它又调用了service(HttpServletRequest, HttpServletResponse);
  • HttpServlet的service(HttpServletRequest, HttpServletResponse)方法,它先对请的方法进行判断,如果是GET请求,则调用doGet()方法,如果是POST请求,则调用doPost()方法;
  • 如果在MyServlet中重写了 doGet(),doPost()方法,则会调用MyServlet中的重写的响应的doGet(),doPost()方法。

注:必须要重写至少一个doXXX方法,如果没有重写doXXX方法,则会报405错误

 

八. 线程安全问题

 

servlet不是线程安全的。Servlet体系结构建立在Java多线程机制之上,它的生命周期由Web容器负责。当客户端第一次请求某个Servlet时,Servlet容器将会根据配置文件实例化这个Servlet类。当有新的客户端请求该Servlet时,一般不会再实例化该Servlet类,也就是有多个线程在使用这个实例。当两个或多个线程同时访问同一个Servlet时,可能会发生多个线程同时访问同一资源的情况,数据可能会变得不一致。可参考售票系统.

解决方法:

  • 使用 synchronized同步代码块。效率太低,不建议使用
  • 不依赖实例全局成员变量,将接收参数的变量声明成局部变量。因为,局部变量默认就是线程安全的。局部变量在线程的栈中,先进后出。

 

九. ServletContext接口

 

ServletContext是一个全局的储存信息的空间,服务器开始就存在,服务器关闭才释放。

一个web项目,只存在一个ServletContext实例,每个Servlet都可以访问到它,用于共享数据。        

获取方法:

ServletConfig和GenericServlet的getServletContext()方法

功能:

  • 获取WEB应用程序的初始化参数。
  • //配置全局初始化参数

<context-param>

         <param-name>name</param-name>

         <param-value>张三</param-value>

</context-param>

//获取全局初始化参数

ServletContext ctx = getServletContext();

Enumeration<String> en = ctx.getInitParameterNames();

while (en.hasMoreElements()) {

  String nm = (String) en.nextElement();

  //根据初始化的名字获取值

  String value = ctx.getInitParameter(nm);

  out.print(nm+":"+value+"<hr>");

}

 

  • 获取项目的真实的路径。

 

//获取真实路径(在服务器上的绝对路径)

response.getWriter().print(ctx.getRealPath("/imgs")+"<hr>");

//获取项目应用上下文(/webapp名称)

response.getWriter().print(ctx.getContextPath()+"<hr>");

 

  • 做为域对象,保存多个客户共享的数据。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章