Servlet 技术

Servlet

Servlet Applet 运行在服务端的小程序

概念

Server Applet 是--->使用java语言编写的运行在服务端上(web服务器/应用服务器)的程序。它是作为浏览器客户端和服务器端上的数据库或者程序之间的中间层,起到一个桥梁的作用,使用Servlet可以做到获取浏览器客户端中的表单数据和客户端发送的一些请求信息,关联后端数据库做完业务处理,把处理后的结果值再返回给浏览器客户端展示。

  • 快速入门:

    • 步骤:

      • 第一步:先部署当前的项目到tomcat服务器中

      • 第二步:让浏览器客户端找到项目中对外提供的某个服务 路径映射 url-pattern

      • 第三步:启动tomcat服务器 

  • Servlet的内部实现原理:

    Servlet是sun提供的一套规范

    Servlet规范:包含三个技术点:servlet技术、filter(过滤器)技术、listener(监听器)技术

    原理:

    当客户端发送一个请求过来时,tomcat会先解析请求的url路径,在web.xml文件中去找对应的路径

    <url-pattern></url-pattern>,如果找到了,就会读取<servlet-name></servlet-name>

    的名字,通过servlet-name找到对应的服务类,记载该服务类信息,tomcat会创建该类的对象,调用service()方法,

    执行service()方法中的内容,如果该服务类是被第一次请求,那么会先调用init()方法,初始化该类对象的信息,然再调用service()方法。

Servlet的生命周期

  • 第一个方法:init()初始化Servlet类对象信息,当Servlet对象创建的时候被调用,而且只会调用一次。

    • Servlet类对象什么时候会被创建出来?

    • 默认情况下,该Servlet类被第一次访问的时候,Servlet对象被创建

    • 手动指定Servlet类对象创建时间。

      • 通过在<Servlet>标签中配置<load-on-startup>标签
        1.第一次访问时被创建出来。
        <load-on-startup>标签的值为负数

        ​2.在服务器启动的时候,被创建出来 <load-on-startup>的值为0或者负整数。 注意:

        • load-on-startup是用来标记容器是否在启动的时候就加载这个Servlet(实例化并执行init方法)

        • load-on-start 它的值必须是一个整数,表示这个Servlet类加载的顺序

        • 当值为>= 0的时候,表示容器在应用启动的时候就加载并初始化这个Servlet类

        • 当值为<0的时候,表示容器在该Servlet类被选择的时候才会去加载。

        • 整数的值越小,表明该Servlet类中的优先级越高,应用启动的时候就越先加载

        • 当值相同的时候,容器会自己选择一个Servlet去加载

        备注:

        • Servlet接口中的init方法,只会执行一次,说明一个Servlet在内存当中只会存在一个对象。Servlet是单例的。

          • 狭义:一个类在内存当中有且仅有一个类对象,而且这个类对象自始至终都是同一个对象 做法:把该类的构造器私有化,new的动作只能在类内部使用。

          • 广义:只要满足在整个系统中或者应用中有且仅有一个示例即可。不保证是同一个。

          • 在Servlet 3.1规范中,当自定义Servlet类没有实现SingleThreadModel接口的时候,Servlet类才是单例的。

          • 如果实现该接口,那么每次请求该Servlet类的时候,容器都会创建一个新的Servlet类对象

          • 面试题:Servlet容器如何保证在多线程环境下访问数据的安全性问题?

            • Servlet默认情况下采用单例多线程方式处理多个请求

            • 当web容器启动的时候(或者客户端发送请求的时候),Servlet就会被加载并实例化

            • 容器初始化Servlet主要就是读取配置文件(web.xml),在tomcat容器中也有一个web.xml,在Server.xml中可以设定线程池中的数目,初始化线程池通过web.xml

            • 当客户端请求到达时,Servlet容器可以通过线程调度它管理下的线程池中的等待执行的线程

            • 当线程执行完毕,归还线程到线程池中

            • 当多个用户同时访问同一个Servlet类的时候,可能会存在线程数据安全的问题 做法:不要在Servlet中定义成员变量,如果定义了,也不要去修改成员变量值。

  • Servlet类中的Service():当客户端发送请求的时候,会执行service方法,而且会执行多次

  • Servlet类中的destroy():当Servlet类对象被销毁的时候,会调用它

    • 当服务器正常关闭的时候,就会调用destroy方法

    • 当Servlet类被修改的时候,也会执行destroy方法

Servlet3.0

提供了注解配置

  • 好处:不需要再到web.xml文件去注册Servlet类信息

  • 步骤:

    • 选择JavaEE项目 Servlet3.0版本以上,创建一个Servlet类,

    • 在该Servlet类上面添加@WebServlet

    • 在该注解中配置客户端url请求资源路径

    • @WebServlet(“/请求资源路径”)

      @Target({ElementType.TYPE})
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      public @interface Webservlet {
      String name()default"";//相当于<servlet-name>
      string[] value() default ();//代表urlpatterns属性
      string[] urlpatterns() default 0;// 相当于 <url-pattern>
      int loadonstartup() default -1;//相当于<load-on-startup>

欢迎界面

当我们向浏览器中输入我们的服务器地址,路径url格式:http://localhost:8080/day48/,此时tomcat会自动按照在web.xml文件中配置的<welcom-file-list>列表从上到下依次查找对应的web资源,如果全部找完没有发现对应的资源,服务器会给浏览器客户端返回一个404状态码(404表示web资源没找到),表明web资源路径不匹配。如果找到了,就是我们需要的欢迎界面。

注意:

  • 访问的是当前web应用根目录下的文件资源,一般情况下我们访问的是web文件夹下面的资源

  • 有一个文件下面的资源直接通过浏览器是访问不到的 WEB-INF(安全目录、保护目录)

  • 只能通过服务器内容来访问。

  • <welcome-file-list>标签内部配置的欢迎界面是一种服务器行为,在浏览器客户端上直接访问WEB-INF里面的资源是不可行的。

Servlet相关配置

我们主要配置<url-pattern>客户端访问web应用资源的路径

  • String[] urlPatterns():一个Servlet可以配置多个访问路径 @WebServlet({“/demo01”,“/demo02”,“/demo03”…})

  • 路径定义的规则:

    • /xxx:路径匹配/完全匹配

    • /xxx/yyy/…:多层路径匹配,目录匹配

    • /缺省配置 当访问web应用中的资源(Servlet)都不匹配,此时会找缺省配置的Servlet信息,让这个缺省配置的Servlet来处理这个请求,当前Servlet它能够处理资源包括Servlet和静态资源,jsp资源解决不了

    • /* 全部处理 处理包含静态资源和jsp资源,需要借助于Servlet中访问方式:内部转发和重定向。

    • *.do , *.action 扩展名匹配 一般要写具体的哪一个服务 如:userEdit.do、userEdit.action

HTTP

Hyper Text Transport Protocol 超文本传输协议,是互联网中应用最广泛地一种网络协议。

传输协议:定义了客户端和服务器端通信时,发送数据的格式。

  • 特点:

    • 基于TCP/IP的协议

    • 默认的端口号是80

    • 基于请求与响应的模型的,一次请求对应一次响应

    • 无状态的:每次请求之间是相互独立的,每次请求之间不能进行数据的交互

  • 历史版本:

    • 1.0 每一次请求与响应都需要建立一次连接,请求与响应结束后连接随之断开,每次建立的连接都是新连接

    • 1.1 持久连接

      • 1.1版本最大的变化就是引入持久连接:请求响应结束后,默认情况下是不断开的,可以被多个请求所复用 不用再声明:Connection:keep-alive。

      •   客户端和服务器端发现对方有一段时间没有活动,就会主动关闭连接。如果在客户端发送最后一个请求时,这个请求发送了Connection:close,明确要求服务器关闭TCP连接

        • 目前大多数浏览器,对于同一个域名最多同时允许建立6个持久连接,提高了带宽的利用率

        • 加入了管道机制。在同一个连接里面,允许同时发送多个请求,增加了并发性。改善了HTTP协议的效率。

          1.1版本作为目前主流的版本

    • 2.0

      • 为了解决利用率不高,继续优化,提出了2.0版本。增加了双工模式。即不仅客户端能够同时发送多个请求,服务器端也同时处理多个请求。解决了对头堵塞问题。

  • 协议的组成与过程

    Http协议是由HTTP请求和HTTP响应组成的。当在客户端中输入一个url地址回车,浏览器会将你的请求消息封装为一个HTTP请求的格式发送给服务器端,服务器端收到这个消息之后,解析这个请求消息将它装配到ServletRequest,做完业务逻辑之后组织响应数据封装为一个HTTP响应的格式返回给浏览器客户端,这个过程就是请求与响应的过程,如果没有请求就没有响应。

HTTP协议

  • 抓包分析 使用Chome自带的工具可以看到数据之间相互传输的过程

    • HTTP请求: 请求行:请求方式,请求的路径(请求的数据)HTTP版本号 请求头:主机名 连接方式 客户端浏览器内核内容 接收数据类型 压缩格式 语言。。。 请求体:如果是post请求,会有请求的数据,如果get请求没有 请求空行

 

HTTP请求

get请求----HTTP默认的请求方式是get请求(直接在客户端的地址栏中输入url和使用<a href = "请求资源路径"></a>),对于form表单可以指定请求的方式为post
// 请求行:请求方式   请求路径  http版本号
GET /checkUser?username=admin&password=123456 HTTP/1.1
// 本机服务器的ip地址  域名    
Host: localhost:8080
// 连接的方式  长连接    
Connection: keep-alive
// 告诉服务器,自己支持你这中操作,我能读懂服务器发送的的信息,建议使用https而不是用http    
Upgrade-Insecure-Requests: 1
//用户使用的浏览器客户端的内核 还包括操作系统相关的信息
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36
// 接收的数据格式   
// 告诉服务器端浏览器客户端能够接收的哪种类型的数据
Accept:
// mime类型  大范围/小范围
text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
// 来源地--->浏览器通知服务器,当前的请求时来自于哪个地方
// Referer:经常用于防盗链  防止盗取我的连接信息 如果你是直接请求资源,没有referer
Referer: http://localhost:8080/
// 接收的压缩格式  浏览器通知服务器我可以接收哪些类型压缩格式的数据
Accept-Encoding: gzip, deflate, br
// 浏览器可支持的语言
Accept-Language: zh-CN,zh;q=0.9
// Cookie  JSESSIONID
Cookie: Idea-ac70df0d=96318eda-906d-4909-81b5-89db73f5358a; JSESSIONID=43EE4E93151302CD4B10579871CB8328

post请求

POST /checkUser HTTP/1.1
Host: localhost:8080
Connection: keep-alive
// 内容的长度    
Content-Length: 30
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://localhost:8080
// 如果是post请求在请求体中的数据使用url编码
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:8080/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: Idea-ac70df0d=96318eda-906d-4909-81b5-89db73f5358a; JSESSIONID=43EE4E93151302CD4B10579871CB8328
// 请求体内容
username=admin&password=123456

HTTP响应

// 响应行   http协议   状态码
HTTP/1.1 200
// 响应头 
// 响应正文的内容长度    当前为0
Content-Length: 0
// 响应的时间    
Date: Tue, 12 Jan 2021 07:49:14 GMT
Keep-Alive: timeout=20
Connection: keep-alive

常用的状态码

常用状态码描述
200 请求成功
302 重定向
304 读取本地缓存的文件
404 请求的web资源找不到
405 请求方式不对,如:客户端使用的是get请求,服务器端接收采用post
500 服务器端程序代码错误

Servlet体系结构

  在实际开发中,我们创建一个Servlet类大多数使用的都是service()方法,由于必须遵从Servlet接口规范而不得不去重写其他的抽象方法,这些方法大多时候是闲置不用的,在Servlet体系结构有一个类HTTPServlet,封装了Servlet接口当中的抽象方法,我们以后可以定义一个类去继承该类即可。

GenericServlet它将Servlet接口中的抽象方法基本实现了,有一个service方法没有实现,需要子类来实现,
但是由于客户端发送请求时有请求方式的区别,在service方法中还要做具体的判断,不方便,
在它的子类HttpServlet当中实现了service方法,做了区分不同请求方式的实现,对外提供了七个请求方式的方法, 由于目前阶段我们只使用get和post请求方式,所以关注的重点是doGet和doPost方法

  • 查看源码发现doGet和doPost方法中的两个参数分别是HttpServletRequest和HttpServletResponse,就是我们需要的请求对象和响应对象 

 

Response对象

  • 作用:设置响应的消息

    • 响应头 setHeader(String name,String value) "Content-type"

    • 响应行 http版本 状态码 setStatus(int code)

    • 响应体 getWriter() getOutputStream()------>write()

域对象

request对象也是一个域对象,在这个域对象中可以存放一些数据
  • 数据的存储、读取、删除

    • 向request域对象中存储一些值:setAttribute(String key,Object obj)

    • 从request域对象中读取一些值:getAttribute(String key)

    • 从request域对象中删除指定的值:removeAttribute(String key)

  • request域对象的生命周期

    • 创建:第一次访问该Servlet服务的时候

    • 销毁:一次请求结束后就自动销毁了

    • 重定向获取不到request域对象中的值

ServletContext域对象,代表的是整个web应用对象,在这个对象内部封装了web应用的一些信息,注意:这个ServletContext对象不论何时何地获取的都是同一个对象。单例 Servlet
  • ServletContext对象生命周期

    • 创建:web应用已启动,该对象就随之创建,随着服务器的启动而创建

    • 销毁:服务器关闭的时候、web应用从服务器移除的时候

  • 如何获取ServletContext对象

    • 通过当前的Servlet对象来获取ServletContext对象 this.getServletContext()

    • 该对象在整个应用中始终是唯一的。

  • 常用的api方法

    • removeAttribute() 删除

    • getAttribute() 获取

    • setAttribute() 设置

  • ServletContext作用

    • 配置web应用的参数信息,因为该对象是随着服务器的启动而创建

    • Spring框架 ----->xml配置文件----->对象管理容器

    • applicationContext.xml

    • 该对象中存储的值可以被整个应用所共享

会话技术

由于HTTP协议是无状态的协议,就是说每次客户端请求服务器端,对于服务器端来说都是新的,他并不知道是谁在访问我,如果需要保证服务器来识别到底是哪一个客户端来访问我的,就需要会话技术来实现。

  • 什么是会话

    从用户打开客户端访问我们应用开始,到用户关闭客户端这个过程称之为一次会话。

    从客户端访问web应用开始,这时候就会在系统中开辟一个内存空间存储访问过程中的产生的数据,直到用户关闭浏览器,内存中的数据才会被清除掉。

  • 会话技术的分类

    • Cookie:把数据存储到客户端本地中,减少了服务器端存储数据的压力,安全性不高,客户端也可以手动清除掉Cookie值

    • Session:把数据存储到web应用服务器中,安全性较高,服务器压力较大

  • Cookie

    • 把数据存到客户端本地中

    • 存储过程

      服务器端经常需要把程序中的数据放到cookie中,通过响应头形式发送给客户端,客户端收到这个头信息,

      就会将头信息中的数据保存起来,客户端再次请求服务器端将cookie信息放到请求头中,那么服务器端获取请求头,请求头中有cookie信息,这样就能区分不同的用户

  • Session

    将数据保存到服务器端,它会给每一个客户端创建一块独自的内存空间,在用户第一次请求的过来的时候通过响应头形式将这块内存空间的编号发送给客户端,客户端每次请求时会携带JESSIONID放到请求头中访问服务器。

    服务器会找对应的JESSIONID识别是哪一块的内存空间。

  • 获取Session对象 getSession()

    • 两件事:

      1. 获取当前会话的Session对象,如果服务器端没有session对象,服务器自动创建一个新的session对象,如果有就获取对应的session对象

      2. 并将session中的JESSIONID放入cookie中,并设置的携带路径为当前web应用,自动通过response对象返回。

原文地址:https://www.cnblogs.com/lk625/p/14274534.html