Servlet

180 阅读14分钟

B/S 结构的通信原理

WEB 系统的访问过程
1:打开浏览器
2:找到地址栏
3:输入一个合法的地址
4:回车
5: 在浏览器上响应搜索内容



关于域名:
 https://www.baidu.com/f
 www.baidu.com 是一个域名
 在浏览器地址栏上输入一个域名,回车后,域名解析器会将域名解析出来一个具体的IP地址和端口号等。
 解析结果也许是: http://110.242.68.3:80/index.html
 
 IP地址是啥?
 计算机在网络当中的身份证号,同一个网络当中,IP地址是唯一的。
 A计算机想要和B计算机通信,首先你需要知道B计算机的IP地址,有了IP地址才能建立连接
 
 端口号是啥?
 一个端口代表一个软件(一个端口代表一个应用,一个端口仅代表一个服务).
 在一个计算机当中有很多软件,每个软件启动之后都有一个端口号。
 一个WEB系统的通信原理?通信步骤:
 第一步:用户输入网址(URL)
 第二部域名解析器进行域名解析
 第三步:浏览器在网络中搜索解析出的ip对应的主机,知道找到这台主机
 第四步:定位对应ip的主机上的服务器软件,根据端口找到对应的服务器软件
 第五步:服务器软件得知浏览器想要的资源
 第六步:浏览器接收到服务器软件返回的资源
 第七步:浏览器解析出服务器返回的资源,进行展示

 
 

Tomcat

 tomcat 是一款开源免费的轻量级WEB服务器
 tomcat 只实现了Servlet+jsp的规范
 tomcat 是用java语言写的。
 tomcat 想要运行,需要先有jre,所有要先安装JDK,配置java运行环境
启动Tomcat
bin目录下有一个文件:startup.bat 通过它可以启动tomcat服务器
xxx.bat 文件是一个什么文件?bat文件是windows操作系统专用的,bat文件是批处理文件,这种文件可以编写大量的windows的dos命令,然后执行bat文件,就相当于执行多个dos命令
xxx.sh 这个文件在windows下不可以执行,sh文件是linux操作系统专用的,sh文件可以编写大量的linux的shell命令,然后执行sh文件,就相当于执行多个shell命令

tomcat提供了bat和sh,说明tomcat服务器的通用性
分析startup.bat 可知,最终执行的是 catlina.bat 文件

启动Tomcat服务器只配置path对应的bin是不行的,还需要配置
JAVA_HOME和CATALINA_HOME(配置tomcat的根目录)
并将bin中的shutdown.bat 改名为stop.bat ,因为和Windows的关机命令冲突


关于tomcat的目录
bin:这个目录是tomcat服务器的命令文件存放的目录,比如,启动tomcat,关闭tomcat等等
conf:这个目录是tomcat配置文件的存放目录(server.xml中可以修改服务器的端口号,tomcat默认端口8080)
lib:  这个是tomcat服务器的核心程序目录,因为tomcat服务器是java语言写的,这里的jar包里面都是class文件
logs:tomcat的日志目录,tomcat服务器启动等信息都会在这个目录下生成日志文件
temp:tomcat服务器的临时目录,存储临时文件。
webapps:这个目录就是用来存放大量的webapp(web application)
work:这个目录是用来存放jsp文件翻译之后的java文件以及编译之后的class文件

开发带有Servlet的web App

   开发步骤

   1:在webapps目录下新建一个目录,起名crm(这个crm就是webapp的名字)。当然也可以是其他项目,银行系统创建一个bank
   注意:crm就是webapp的根
   
   2:在webapp的根下新建一个目录:WEB-INF
   注意:这个目录的名字是Servlet规范中规定的,必须全部大写,必须一模一样。
   3:在WEB-INF 目录下新建一个目录:classes
   注意:这个目录必须是小写的classes。这个也是Servlet规范中规定的。(存放的是字节码文件)
   4:在WEB-INF 目录下新建一个目录:lib
   注意:这个目录不是必须的,但是如果一个webapp需要第三方jar包的话,这个jar包要放到这个lib目录下,这个目录的名字也不能随意些,必须是小写的lib,例如java语言连接数据库的驱动jar包。那么这个jar就应该放到这个lib目录下。这是Servlet规范中规定的。
   5:在WEB-INF目录下新建一个文件:web.xml
   注意:这个文件是必须的,这个文件名必须叫做web.xml.这个文件必须放在这里。一个合法的webapp,web.xml文件是必须的,这个web.xml文件就是一个配置文件,在这个配置文件中描述了请求路径和Servlet类之间的对照关系。
   这个文件最好从其他的webapp中拷贝,最好别手写,没必要,直接复制。
   
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
                     https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
 version="5.0"
 metadata-complete="true">
</web-app>
    6:编写一个java程序,这个小java程序也不能随意开发,这个小java程序必须实现Servlet接口。
    这个Servlet接口不在jdk中(因为Servlet不是JavaSE了,Servlet)
    Servlet接口是Oracle提供的
    Servlet接口是javaEE规范中的一员
    Tomcat服务器实现了Servlet规范,所以Tomcat服务器也需要使用Servlet接口。Tomcat服务器中应该有这个接口,Tomcat服务器的CATALINA_HOME/lib 目录下有一个servlet-api.jar之后,你会看到里面有一个Servlet.class 文件。
    重点:从jarkartaEE9开始,Servlet接口全名变了:jakarta.servlet.Servlet
    注意:编写java小程序的时候,java源代码位置无所谓,只需要将java源代码编译之后的class文件放到classes目录下即可。
    7:编写HelloServlet
    重点:怎么让Servlet编译通过呢?配置环境变量CLASSPATH
    CLASSPATH=.;%JAKARTA_HOME%lib\servlet-api.jar
    配置这个CLASSPATH跟tomcat能否运行没有关系,只是为了在文本编译器中使用servlet-api.jar中的类编译通过
    
HelloServlet.java

package com.bjpowernode.servlet;

import java.io.IOException;
import jakarta.servlet.Servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.ServletConfig;

public class HelloServlet implements Servlet{
 public void init(ServletConfig config) throws ServletException{
     
 }
 public void service(ServletRequest request,ServletResponse response)
 throws ServletException,IOException{
     System.out.println("My First Servlet,Hello Servlet");
 }
 public void destroy(){}
 public String getServletInfo(){  return "";  }
 public ServletConfig getServletConfig(){
     return null;
 }
}

    8:将以上编译通过的class复制到WEB-INF/classes 目录下
    9.编写web.xml,将servlet与浏览器path绑定
    10.以后我们不需要编写main,Tomcat启动会自动启动main方法,我们只需要编写Servlet
    总结:一个完整的webapp的目录结构
    
    webapproot
        |-------WEB-INF
                    |-------classes(存放字节码)
                    |-------lib(第三方jar包)
                    |-------web.xml(注册servlet)
        |-------html
        |-------css
        |-------javascript
        |-------image
        .....
  浏览器发送请求,到最终服务器调用servlet中的方法,是怎样的一个过程?(以下过程为粗糙的描述)
  
  
       用户输入URL,或者直接点击超链接http://127.0.0.1:8080/crm/hello
   然后tomcat服务器接收到请求,截取路径:/crm/hello
   Tomcat服务器找到CRM项目
   Tomcat服务器在web.xml文件中查找对应的/hello 对应的Servlet是com.bjpowernode.servlet.HelloServlet
   Tomcat服务器通过反射机制,创建了com.bjpowernode.servlet.HelloServlet对象
   Tomcat服务器调用com.bjpowernode.servlet.HelloServlet对象的service方法
    
 <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
                     https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
 version="5.0"
 metadata-complete="true">
 <!--servlet 配置信息-->
 <servlet>
 <!--任何一个servlet都对应一个servlet-mapping-->
   <servlet-name>hello</servlet-name>
   <!--这里必须是带有包名的全限定类名-->
   <servlet-class>com.bjpowernode.servlet.HelloServlet</servlet-class>
 </servlet>
 <servlet-mapping>
 <!--这里随便写,但是要和对应的servlet name相同-->
   <servlet-name>hello</servlet-name>
   <!--这个是浏览器中访问的路径,唯一要求要以 / 开头-->
   <url-pattern>/hello</url-pattern>
 </servlet-mapping>

</web-app>
    10: 启动Tomcat服务器
    11: 打开浏览器,在浏览器地址栏上输入一个URL,这个URL必须是:http://127.0.0.1:8080/crm/hello
    非常重要的一件事:浏览器上的请求路径不能随便写,必须和url-pattern 中的path一样
    
    
    关于JavaEE的版本
    javaEE 目前最高版本不是JavaEE8
    javaEE 被Oracle捐献了,Oracle将JavaEE捐献给了Apache
    Apache把javaEE换名了,以后不叫javaEE了,以后叫做jakarta EE。
    以后没有javaEE了,以后叫做jakartaEE了
    javaEE8版本升级后不叫javaEE9 叫做jakartaEE9
    javaEE8 对应的Servlet类名是:javax.servlet.Servlet
    javaEE9 对应的Servlet类名是:
    jakarta.servlet.Servlet(包名都换了)
    如果之前使用的项目还是使用的javax.servlet.Servlet,那么项目无法直接部署到tomcat10以上了
    jakartaEE9以上Servlet包名为 jakarta.servlet.Servlet
    

使用IDEA工具开发Servlet

 1.New Project(习惯新建一个Empty Project),然后再空工程下新建Module(模块),不是必须的,可以直接新建project。这个EmptyProject 起名为javaweb不是必须的,只是一个项目名字而已)一般情况下新建的projec的名字最好和目录名字一致。
 2.New Module
     这里新建的是一个普通的java SE模块
     这个Module自动会被放在javaweb目录下
     Module 起名为servlet01
 
 3.将模块变成javaEE模块。(让Model变成webapp的模块,符合webapp规范和servlet规范的Module)
     在Module上点击右键:Add Framework Support
     再弹出的窗口中选择Web Application(选择的是webapp的支持
     选择这个webapp的支持后,IDEA会自动给你生成一个符合servlet规范的webapp目录结构。
     重点,需要注意的: 在IDEA工具中根据Web Application模板生成的目录中有一个web目录,这个目录就代表webapp的根目录。
  4. 根据Web Application生成的资源中有一个index.jsp文件,这里我选择删除这个index.jsp文件。
  5. 编写Servlet
  这时候发现Servlet.class 文件没有,将CATALINA_HOME/lib下的servlet-api.jar和jsp-api.jar 添加到classpath中(这里指的是IDEA classpath)
  6. 在servlet 中编写业务代码(这里我们连接数据库)
  7. 在WEB-INF目录下创建lib(这个目录名不可以随便写,必须是全部小写的lib),并且将连接数据库的驱动jar包放到lib目录下
  8. 在web.xml 文件中完成StudentServlet类的注册。(请求路径和Servlet之间对应起来)
<?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>userlist</servlet-name>
       <servlet-class>com.bjpowernode.servlet.UserServlet</servlet-class>
   </servlet>
   <servlet-mapping>
       <servlet-name>userlist</servlet-name>
       <url-pattern>/userlist</url-pattern>
   </servlet-mapping>
</web-app>
     9. 给一个HTML页面,在HTML页面中编写一个超链接,用户点击这个超链接,发送请求,Tomcat执行后台的StudentServlet。
     student.html
     这个文件不能放到WEB-INF目录里面,只能放到WEB-INF目录外面
    

Student.html内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Index</title>
</head>
<body>
<!--/user表示项目名称,目前项目名无法动态获取,先写死 ,userlist代表web.xml中配置的servlet名称-->
<a href="/user/userlist">用户列表</a>

</body>
</html>

Servlet 生命周期

  • 什么是Servlet的生命周期?
    • Servlet对象什么时候被创建
    • Servlet对象什么时候被销毁
    • Servlet对象创建了几个?
    • Servlet对象的生命周期表示:一个Servlet对象从出生到最后的死亡,整个过程是怎样的。
  • Servlet对象由谁来维护?
    • Servlet对象的创建,对象方法的调用,对象最终的销毁,javaweb程序猿是无权干预的。
    • Servlet对象的生命周期是有Tomcat服务器(WebServer,例如Tomcat,jetty)全权负责的
    • Tomcat服务器通常我们又称为WEB容器。
    • Web容器来管理Servlet对象的死活
  • 思考:我们自己new的Servlet对象受WEB容器的管理吗?
    • 我们自己new的Servlet对象是不受WEB容器管理的。
    • WEB容器创建的Servlet对象,这些Servlet对象都会被放到一个集合当中(HashMap),只能放到这个Map中的Servlet才能够被WEB容器管理,自己new的Servlet对象不会被WEB容器管理(自己new的servlet 对象不在这个容器当中)
    • WEB容器底层应该有一个HashMap这样的集合,在这个集合当中存储了Servlet对象和请求路径之间的关系
  • 研究:服务器在启动的时候,Servlet有没有被创建(默认情况下)?
    • 经过测试服务器启动的时候Servlet并没有被实例化
    • 这个设计是合理的。用户没有发送请求之前,如果提起那创建出来所有的Servlet对象,必然是耗费内存的,并且创建出来的Servlet对象没有用户访问 ,显然常见出来是浪费系统资源的
    • 在servlet标签中添加子标签,在该标签中填写整数,越小的整数优先级越高
<?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>aservlet</servlet-name>
        <servlet-class>com.bjpowernode.servlet.AServlet</servlet-class>
        <load-on-startup>0</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>aservlet</servlet-name>
        <url-pattern>/a</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>bservlet</servlet-name>
        <servlet-class>com.bjpowernode.servlet.BServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>bservlet</servlet-name>
        <url-pattern>/b</url-pattern>
    </servlet-mapping>
</web-app>
  • Servlet对象生命周期

    • 默认情况下服务器启动的时候Servlet并不会实例化
    • 用户第一次发送请求的时候会依次执行 constructor -> init() -> service()
    • 用户再次发送请求不会重新创建Servlet,会复用之前的Servlet,并且只会执行Servlet实例的service()方法
    • Servlet 对象是单例的。但是要注意:Servlet对象是单实例的,但是Servlet并不符合单例模式。我们称为假单例。之所以是单例是因为Servlet的创建是Tomcat管理的,Tomcat只创建了一个,所以导致了单例,但是属于假单例。真单例模式,构造方法是私有的。
    • 无参数方法,init方法只在第一次用户发送请求的时候执行,也就是说五参数构造只执行一次。init方法也只被Tomcat方法执行一次。
    • 只要用户发送一次请求:service方法必然会被Tomcat请求一次。
    • 关闭服务器的时候,会调用Servlet的destroy方法。
    • Servlet的destroy方法只有在服务器关闭的时候被tomcat调用一次。
    • 当destroy方法调用的时候,Servlet对象还存在,没有被销毁,destroy方法执行结束之后,Aservlet对象的内存才会被释放掉。
  • 当我们Servlet类中编写一个有参数的构造方法,如果没有手动编写无参构造方法会有什么问题?

    • 报错:500
    • 注意:500是一个HTTP协议的错误代码
    • 500一般情况下是因为服务端的java程序出现了异常,(服务器端的错误都是500错误;服务器内部错误)
    • 如果没有无参数的构造方法,会导致500错误,无法实例化Servlet
    • 所以,一定要注意,在Servlet开发当中,不建议程序员定义构造方法,因为定义不当,会导致Servlet无法实例化
  • 思考:Servlet的无参数构造方法是在丢向第一次创建的时候执行,并且只执行一次,init方法也是在对象第一次创建的时候执行,并且只执行一次,那么这个无参数构造方法可以替代init方法吗?

    • 不能。
    • Servlet 规范中有要求:作为javaweb程序员,编写Servlet类,不建议手动编写构造方法,因为编写构造方法,很容易让无参构造方法消失,所以init又存在的必要。
  • init ,service ,destroy方法中使用最多的是哪个方法?

    • 使用最多的是service方法,service方法一定要实现,因为service方法是处理用户请求的核心方法。
    • 什么时候使用init方法
      • 很少用
      • 通常在init方法中做初始化操作,并且这个初始化操作只需要执行一次(例如初始化数据库连接池,初始化线程池)
    • 什么时候使用destroy方法
      • destroy方法也很少用
      • 通常在destroy方法中,进行资源的关闭。马上对象就要被销毁了,还有没有关闭的资源可以关闭,没有保存的资源进行保存。

    Servlet->GenericServlet(抽象类,解决空实现方法问题,不再需要实现所有方法)->

ServletConfig

- ServletConfig 是什么?
    - ServletConfig 是一个接口,是Servlet规范中的一员
- 谁去实现了这个接口?Web服务器去实现了
- 一个Servlet对象中有一个ServletConfig对象,(Servlet和ServletConfig对象是一对一)
- ServletConfit对象是谁创造的?在什么时候创建?
    Tomcat服务器(Web服务器)创建了ServletConfig对象,在创建Servlet对象的时候,同时创建了ServiceConfig对象

- ServletConfig 对象包装了哪些信息?
<servlet>
    <servlet-name>aservlet</servlet-name>
    <servlet-class>com.bjpowernode.servlet.AServlet</servlet-class>
    <load-on-startup>0</load-on-startup>
</servlet>
- ServletConfig 对象包含的信息是<servlet>标签中配置的信息
Tomcat小猫咪解析web.xml文件后,将web.xml 文件中<servlet> 标签中的配置信息包装到ServletConfig对象中。
- ServletConfig对象中有哪些方法?
    - getServletName() 对象<servlet-name>
    - getInitParameterNames() 获取所有的<init-param>中的<param-name> 配置的值
    - getInitParameter(String name) 跟据获取到的<param-name> 获取到<param-value>
    - getServletContext()

image.png

ServletContext

  • ServletContext 是什么?

    • ServletContext 是一个接口,是Servlet规范中的一员
  • 谁去实现了这个接口?Web服务器去实现了

  • 一个Servlet对象中有一个ServletConfig对象,(Servlet和ServletConfig对象是一对一)

  • ServletContext对象是谁创造的?在什么时候创建? Tomcat服务器(Web服务器)启动的时候创建了ServletContext对象,对于一个webapp来说,ServletContext对象只有一个,ServletContext对象在服务器关闭的时候销毁。

  • ServletContext对象怎么理解?

    • context是什么 意思? Servlet对象的环境。(Servlet对象的上下文对象) ServletContext对象其实对应的就是整个web.xml文件 ServletContext对象是所有Servlet对象共享的。