五、Servlet详情

一、Servlet简介

1 . Servlet是Sun公司提供的一项用于开发动态web资源的技术。
2 . Sun公司在其API中提供了一个Servlet接口,用户若想开发一个动态Web资源(即开发一个java程序向浏览器输出数据),需要完成以下两个步骤
第一步:编写一个java类,实现Servlet接口
第二步:把开发好的java类部署到服务器中
3 . Servlet方法,注意生命周期相关方法 init service destroy

方法签名说明
void init(ServletConfig config)生命周期相关方法,servlet被创建时调用该方法进行初始化
void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException生命周期相关方法,servlet收到请求时调用该方法
void destroy()生命周期相关方法,摧毁Servlet时调用该方法
ServletConfig getServletConfig()获取Servlet初始化参数和启动参数
String getServletInfo()获取Servlet描述信息

4 . Hello Word
第一步:继承默认实现类GenericServlet,在service方法中通过ServletResponse对象向浏览器输出Hello Word

public class FirstServlet extends GenericServlet{

    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
        OutputStream out=response.getOutputStream();
        out.write("hello word".getBytes());
    }

}

第二步:在web.xml中配置Servlet,可以参照tomcat config目录下的web.xml来编写自己的web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <servlet>
        <servlet-name>FirstServlet</servlet-name>
        <servlet-class>com.itcast.FirstServlet</servlet-class>
  </servlet>
  <servlet-mapping>
        <servlet-name>FirstServlet</servlet-name>
        <url-pattern>/FirstServlet</url-pattern>
   </servlet-mapping>
</web-app>

第三步:建立好web应用目录,把编译好的Servlet放到WEB-INF/classes中,web.xml文档放在WEB-INF目录下
第四步:启动tomcat,通过浏览器访问

二、Servlet的调用过程和生命周期

继续发扬博主能用图说话尽量不BB的好习惯
1 . 生命周期
这里写图片描述
2. 调用过程
这里写图片描述

三、Servlet的七个细节

1 . Servlet配置
(1)由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须映射到一个URL地址上。这个工作在web.xml中使用< servlet >和< servlet-mapping>元素完成。
(2)< servlet>元素用于注册Servlet,他包含两个主要的子元素:< servlet-name>和< servlet-class>,分别用于设置Servlet的注册名和Servlet的完整类名。
(3)< servlet-mapping>元素用于映射一个已经注册的Servlet的一个对外访问路径,它包含两个子元素:< servlet-name>和< url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。例如:

<web-app>
    <servlet>
        <servlet-name>AnyName</servlet-name>
        <servlet-class>HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>AnyName</servlet-name>
        <url-pattern>/demo/hello.html</url-pattern>
    </servlet-mapping>
</web-app>

2 . Servlet的映射规则

(1)同一个Servlet可以被映射到多个URL上,即多个< servlet-mapping>的子元素< servlet-name>的值可以相同。
(2)Servlet映射到的URL可以使用 * 通配符,但是只能有两种固定的格式:一种格式是“ * .扩展名” ,另一个种格式是以正斜杠“/”开头并以“/ * ”结尾。也就是说“/aa/ * .do”是不被支持的。

<servlet-mapping>
    <servlet-name>AnyName</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
       <servlet-name>AnyName1</servlet-name>
    <url-pattern>/action/*</url-pattern>
</servlet-mapping>

3 . Servlet的映射优先级

由于通配符*的存在,一个url可能同时匹配多个servlet,匹配规则如下:
(1)*.do的优先级别最低
(2)除(1)以外的情况,匹配度高的先匹配

思考题:
对于如下的一些映射关系
  Servlet1 映射到 /abc/*
  Servlet2 映射到 /*
  Servlet3 映射到 /abc
  Servlet4 映射到 *.do
当请求URL为/abc/a.html,/abc/* 和/* 都匹配,哪个servlet响应?
  答:Servlet1。
当请求URL为/abc时,abc/* 和/abc 都匹配,哪个servlet响应?
  答:Servlet3。
当请求URL为“abc/a.do时,/abc/* 和*.do都匹配,哪个servlet响应?
  答:Servlet1。
当请求URL为/a.do时,/* 和*.do都匹配,哪个servlet响应?
  答:Servlet2。
当请求URL为/xxx/yyy/a.do时,/* 和*.do都匹配,哪个servlet响应?
  答:Servlet2。

4 . Servlet的调用

(1)Servlet是一个供其他java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度。
(2)针对客户端的多次Servlet请求,通常情况下服务器只会创建一个Servlet实例对象,也就是说Servlet实例一旦创建,它就会驻留在内存中,为后续的其他请求服务,直至web容器退出,Servlet实例才会销毁。
(3)在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对于一个Servlet的每次访问都导致Servlet引擎调用一次Servlet的service方法。对于每一次访问请求,Servlet引擎都会创建一个新的ServletRequest请求对象和一个新的ServletResponse响应对象,然后将这两个对象作为参数传递给被访问的Servlet的service方法。如果是HttpServlet,service方法会根据请求方式不同调用doXXX方法,如doGet doPost。request response对象在请求返回后会被销毁。

5 . 配置web应用启动时创建并初始化Servlet

(1)如果在< servlet>元素中配置了一个< load-on-startup>元素,那么web应用程序在启动时,就会装载并创建servlet的实例对象,并调用servlet实例对象的init()方法。< load-on-startup>元素值为正整数,数值越小优先级别越高。

<servlet>
    <servlet-name>invoker</servlet-name>
    <servlet-class>org.apache.catalina.servlets.InvokerServlet</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>

(2)用途:为web应用写一个InitServlet,这个Servlet配置为启动时装载,为整个web应用初始化必要的数据和资源。

6 . 缺省Servlet

(1)如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前web应用的缺省Servlet。
(2)凡是在web.xml中找不到匹配的< servlet-mapping> 元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说缺省Servlet用于处理其他Servlet都不处理的访问请求。
(3)在{tomcat安装目录}\conf\web.xml中注册了一个名为default的servlet,它的完整类名为org.apache.catalina.servlets.DefaultServlet,并将这个Servlet设置为了缺省Servlet。({tomcat的安装目录}\conf\web.xml文件的配置为所有web应用所共享)
(4)当访问tomcat服务器中的某个静态html文件和图片时,实际上是在访问这个缺省Servlet。

思考题:如果在自己的web应用中配置一个缺省servlet会怎么样?
答:如果在自己的web应用中配置缺省Servlet会覆盖服务器的缺省Servlet,那么以后访问静态web资源的时候就会调用自己的缺省Servlet,而自己的缺省Servlet如果没有实现读取静态web资源的功能,就会导致静态web资源无法访问,所以一般在开发中应该避免配置缺省Servlet的情况。

7 . 线程安全

(1)当多个客户端并发访问同一个servlet时,web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上调用servlet的service方法,因此service方法内如果访问了同一个资源的话,就有可能引发线程安全问题。
(2)如果某个Servlet实现了SingleThreadModel接口,那么servlet引擎将以单线程模式来调用其service方法。
(3)SingleThreadModel接口中没有定义任何方法,只要在servlet类的定义中增加实现SingleTreadModel接口的声明即可。
(4)对于实现了SingleThreadModel接口的servlet,Servlet引擎仍然支持对该servlet的多线程并发访问,其采用的方式是产生多个servlet实例对象,并发的每个线程分别调用一个独立的servlet实例对象。
(5)实现SingleThreadModel接口并不能真正解决servlet的线程安全问题,因为servlet引擎会创建多个servlet实例对象,而真正意义上解决多线程安全问题是指解决一个servlet实例被多个线程同时调用的问题。事实上,在Servlet API 2.4中,已经将SingleThreadModel标记为deprecated(过时的)。

四、ServletConfig和ServletContext

1 . ServletConfig介绍
(1)在servlet的配置中,可以使用一个或者多个< init-param>标签为servlet配置一些初始化参数。
(2)当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并调用Servlet的init方法将ServletConfig对象传递给Servlet。进而,程序员通过ServletConfig对象就可以得到当前servlet的初始化参数。
2 . ServletContext介绍
(1)web容器在启动时,它会为每个web应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
(2)ServletContext对象被包含在ServletConfig对象中,开发人员在编写Servlet时,可以通过ServletConfig.getServletContext()方法获得对servletContext对象的引用。HttpServlet提供了getServletContext()方法更方便的获取servletContext对象。
(3)由于一个web应用中的所有Servlet共享同一个servletContext对象,因此servlet对象之间可以通过servletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。
3 . ServletContext应用
(1)多个servlet通过ServletContext对象实现数据共享。
(2)获取web应用的初始化参数。
(3)实现servlet的转发。
(4)利用ServletContext对象读取资源文件。

4 . 小实验
(1)ServletConfig获取servlet初始化参数

 <servlet>
    <servlet-name>servlet4</servlet-name>
    <display-name>servlet4</display-name>
    <description></description>
    <servlet-class>com.yd.testhttp.Servlet4</servlet-class>
    <init-param>
      <param-name>dataBaseUrl</param-name>
      <param-value>localhost:3306</param-value>
    </init-param>
  </servlet>
String dataBaseUrl=this.getServletConfig().getInitParameter("dataBaseUrl");

(2)ServletContext实现数据共享

servlet1向ServletContext对象添加数据

//获取servletContext的两种方式
ServletContext context=this.getServletConfig().getServletContext();
//ServletContext context1=this.getServletContext();
//向servletContext对象添加数据
context.setAttribute("data", "data from servlet1");

servlet2从servletContext中获取servlet1存放的数据

ServletContext context=this.getServletContext();
System.out.println(context.getAttribute("data"));

(3)ServletContext获取web应用的初始化参数
  

<context-param>
    <param-name>dataBaseUrl</param-name>
    <param-value>localhost:3306</param-value>
  </context-param>
  <context-param>
    <param-name>dataBaseUsername</param-name>
    <param-value>root</param-value>
  </context-param>
  <context-param>
    <param-name>dataBasePassword</param-name>
    <param-value>111</param-value>
  </context-param>
ServletContext context=this.getServletContext();
String dataBaseUrl=context.getInitParameter("dataBaseUrl");
String dataBaseUsername=context.getInitParameter("dataBaseUsername");
String dataBasePassword=context.getInitParameter("dataBasePassword");

(4)实现Servlet的转发
   
servlet5

//servlet收到请求产生数据,然后转交给jsp显示
String data = "data from servlet5";
this.getServletContext().setAttribute("data", data);
RequestDispatcher rd = this.getServletContext().getRequestDispatcher("/view.jsp");
rd.forward(request, response);

view.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<%
 String str=(String)application.getAttribute("data");
%>
<%= str%>
</body>
</html>

(5)读取资源文件

//第一种方式:getResourceAsStream
InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
Properties prop = new Properties();  //map
prop.load(in);
System.out.println(prop.getProperty("xx"));
//第二种方式:通过绝对路径读取
ServletContext context = this.getServletContext();
String realpath = context.getRealPath("/db.properties");  
String filename = realpath.substring(realpath.lastIndexOf("\\")+1);
System.out.println("当前读到的文件是:" + filename);
//第三种方式:getResource
URL url = context.getResource("/WEB-INF/classes/db.properties");
InputStream in1 = url.openStream();
Properties prop1 = new Properties();  //map
prop1.load(in1);
System.out.println(prop1.getProperty("xx"));

(5)web应用中普通java类读取资源文件

ClassLoader loader = StudentDao.class.getClassLoader();
InputStream in = loader.getResourceAsStream("/db.properties");  
Properties prop = new Properties();  //map
prop.load(in);
System.out.println(prop.getProperty("xx"));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ni0224

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值