JavaEE day3:Servlet

为什么要用Servlet?

因为企业级应用工作时,需要实现以下三步
- 和客户端建立tcp连接
- 解析http请求报文(真正拿到客户端发送的数据)
- 实现产品的业务逻辑
而每个应用都实现第一、第二步的话效率很低
那么我们需要引入一个集成1、2步的服务器程序Servlet

此时我们就可以自己写程序实现自己的产品的业务逻辑

client发出http请求报文——client和tomcat建立tco连接——tomcat解析http请求报文——并且应用拿到解析好的http请求——应用根据业务逻辑来处理请求-tomcat将应用处理的结果封装到http响应报文——Tomcat将响应报文发送给客户端

  • 那么我们如何拿到tomcat帮助我们解析好的http请求
  • tomcat就是把请求报文转化成第一个表示http请求的对象
    public abstract void service (ServletRequest req.ServletResponse res)throws ServletException,java.io.IOException

Servlet简介

  • Servlet是一门用于开发动态web资源(Servlet根据不同的请求产生不同的响应的)的技术

使用javac来编译java程序

-如果还是用的是之前的jdk的版本会无法找到Servlet类

JavaEE day3:Servlet

  • 此时要将tomcat的lib目录里的Servlet-api导入jdk运行环境中(jdk1.8-jre-lib-ext)

实现Servlet

  • 编写一个java类,实现Servlet接口
  • 把开发好的java类部署到web服务器中
    • 将Servlet编译之后生成的字节码文件放到应用的web-inf目录下的classes目录中
    • (解决的核心问题是,让tomcat找到合适的Servlet,将请求交给专们用来处理这个请求的Servlet)

通过WEB-INF里的web.xml里的Servlet和Servlet-mapping,告诉tomcat哪个Servlet处理哪种请求

JavaEE day3:Servlet

  • Servlet /servlet作了映射:将Servlet的字节码的全类名,映射到一个名称,就是给字节码对应的Servlet起了个名字
  • servlet-maping /servlet-maping 将一个url映射到Servlet的名称
  • 这样就可以通过url访问Servlet的名称,在通过Servlet的名称访问 class文件(这里比较绕)
  • 如果想输出到客户端,需要使用ServletResponse res调用getWriter().println();
  • 通过形参中的req拿到请求,res将处理结果给到客户端

Servlet生命周期

创建—调用—销毁
- 懒加载:我们定义的MyFirstServlet什么时候被实例化呢?第一次被请求的时候,这样做的好处(壁纸与气动tomcat就实例化MyFirstServlet),其实是对资源利用的一种优化。
- 什么时候执行service方法(执行业务逻辑呢?)http请求一次,处理一次
- 什么时候被销毁呢?应用退出,被undeploy(和部署web应用相反),redeloy=先undeloy再deploy

  • 客户端发出请求http://localhost:8080/MyFirstServlet/haha,服务器根据web.xml文件的配置,找到url-pattern子元素的值“haha”的servlet-mapping元素
  • 读取servlet-mapping元素的servlet-name子元素的值,由此确定Servlet的名字为”haha”
  • 找到servlet-name值为haha的servlet元素,其类名为servletA
  • 读取servlet元素的servlet-class子元素的值,由此确定Servlet的类名(全类名)为bamzhy.MyFirstServlet.servletA。
  • 到Tomcat安装目录/webapps/app/WEB-INF/classes/bamzhy/MyFirstServlet目录下查找到servletA.class文件
  • 初始化,并执行这个类的 service方法。

Servlet的运行过程

Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
- Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
装载并创建该Servlet的一个实例对象。
- 调用Servlet实例对象的init()方法。
- 创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
- WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。

Servlet的一些细节

  • doPost方法专门用来处理post提交的请求
  • doGet方法专门用来处理get提交的请求
  • 这两种方法必须被overide
  • 值得一提的时候,我由于在注解中的urlpattern里边忘记前置“/”导致了Servlet没有部署 成功

    JavaEE day3:Servlet

  • 同时,同一个Servlet可以由多个urlpattern映射;
    JavaEE day3:Servlet
  • 在Servlet映射到的URL中也可以使用 ” * ” 通配符,但是只能有两种固定的格式:
    一种格式是“*.扩展名”,
    一种格式是以正斜杠(/)开头并以“/*”结尾。

  • 对于如下的一些映射关系:
    Servlet1 映射到 /abc/*
    Servlet2 映射到 /*
    Servlet3 映射到 /abc
    Servlet4 映射到 *.html
    JavaEE day3:Servlet

  • 如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就会成为当前web应用程序的缺省Servlet

  • 凡是在web.xml文件中找不到匹配的servlet-mapping元素的url,它们的访问请求都将交给缺省Servlet处理。

关于匹配方面的结论:

  • 可以精确匹配,就用最精确的匹配
  • /的优先级要高于.html

如何为Servlet配置启动时装载

  • 在Servlet元素汇总配置一个load-on-startup元素,那么web应用程序在启动时,就会装载并创建Servlet的实例对象以及调用Servlet实例对象的init方法
  • 可以使得当前Servlet配置为启动时装载,为整个web应用创建必要的数据库表和数据

ServletConfig对象

  • 在Servlet的配置文件中,可以使用一个或多个init-param标签为 某个servlet配置一些初始化参数。
    JavaEE day3:Servlet
  • 阅读ServletConfig API,并举例说明该对象的作用:
    获得字符集编码
    获得数据库连接信息

ServletContext对象

servletContext=一个web应用
- WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
JavaEE day3:Servlet
- 由于一个web应用中的所有Servlet共享同一个ServletContext对象,因此Servlet可以通过ServletContext对象来实现通讯
- ServletContext对象通常也被称之为context域对象(整个web应用)
ServletContext的应用
- 获取web应用的初始化参数(多个Servlet获取相同参数)
- 多个Servlet通过ServletContext对象实现数据共享
- 实现Servlet的转发(request)

几个疑难问题

我们配置的默认Servlet是否会真正覆盖tomcat的默认的Servlet?

  • tomcat在接收请求之后,首先会将url中拿到的url-pattern去和url指明的应用中匹配urlpattern,如果在已经配置了应用的默认Servlet的前提下,在访问tomcat中不存在的应用(不是当前应用时),tomcat的默认Servlet会接收请求并且处理。所以我们应用的默认Servlet并未真正覆盖tomcat的默认的Servlet。

/* 和/ 有没有优先级之分?

  • /* 要比/优先级高

正确获取资源的绝对路径

  • ServletContext的getRealPath方法能够帮助我们获取正确的绝对路径