百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

JavaWeb - Servlet:重定向和转发,状态管理

wxin55 2024-10-27 15:57 18 浏览 0 评论


Servlet + JDBC 应用

在 Servlet 中可以使用 JDBC 技术访问数据库,常见功能如下:

  • 查询 DB 数据,然后生成显示页面,例如:列表显示功能。
  • 接收请求参数,然后对 DB 操作,例如:注册、登录、修改密码等功能。

为了方便重用和便于维护等目的,经常会采用 DAO(Data Access Object)模式对数据库操作进行独立封装。

DAO 工厂(工厂模式):工厂类封装了对象的创建细节,为调用者提供符合要求的对象。


重定向和转发

重定向的概述

概念

首先客户浏览器发送 http 请求,当 web 服务器接受后发送 302 状态码响应及对应新的 location 给客户浏览器,客户浏览器发现是 302 响应,则自动再发送一个新的 http 请求,请求 url 是新的 location 地址,服务器根据此请求寻找资源并发送给客户。

实现

实现重定向需要借助 javax.servlet.http.HttpServletResponse 接口中的方法:

void sendRedirect(String location) 使用指定的重定向位置 URL 向客户端发送临时重定向响应

原理

当执行添加页面功能时,浏览器发送 add.do 请求给 Tomcat 服务器;

Tomcat 服务器的 AddServlet 收到 add.do 请求后,先访问数据库 DB 执行插入新数据的操作,然后发送 302 状态码及重定向的新地址 Location: list.do 信息到浏览器;

浏览器根据新地址发送 list.do 请求给 Tomcat 服务器;

Tomcat 服务器的 ListServlet 收到 list.do 请求后,先访问数据库 DB 获取 list 数据,然后发送 200 状态码及 list 数据到浏览器;

浏览器根据 list 数据展示页面。

特点

重定向之后,浏览器地址栏的 URL 会发生改变。

重定向过程中会将前面 Request 对象销毁,然后创建一个新的 Request 对象。

重定向的 URL 可以是其它项目工程。

转发的概述

转发的概念

一个 Web 组件(Servlet/JSP)将未完成的处理通过容器转交给另外一个 Web 组件继续处理,转发的各个组件会共享 Request 和 Response 对象。

转发的实现

  • 绑定数据到 Request 对象

Object getAttribute(String name) 将指定属性值作为对象返回,若给定名称属性不存在,则返回空值

void setAttribute(String name,Object o) 在此请求中存储属性值

  • 获取转发器对象

RequestDispatcher getRequestDispatcher(String path) 返回一个 RequestDispatcher 对象,该对象充当位于给定路径上的资源的包装器

  • 转发操作

void forward(ServletRequest request, ServletResponse response) 将请求从一个 servlet 转发到服务器上的另一个资源(Servlet、JSP文件或HTML文件)

转发的特点

转发之后浏览器地址栏的 URL 不会发生改变。

转发过程中共享 Request 对象。

转发的 URL 不可以是其它项目工程。

重定向和转发的比较

  1. 重定向访问服务器两次,转发只访问服务器一次。
  2. 转发页面的 URL 不会改变,而重定向地址会改变。
  3. 转发只能转发到自己的 web 应用内,重定向可以重定义到任意资源路径。
  4. 转发过程中共享 request 对象;而重定向会产生一个新的 request,不能共享 request 域信息与请求参数。
  5. 转发相当于服务器内部方法调用,转发后面的代码仍然会执行;而重定向操作是方法执行完成之后才进行。
  6. 无论是 RequestDispatcher.forward 方法,还是 HttpServletResponse.sendRedirect 方法,在调用它们之前,都不能有内容已经被实际输出到了客户端。如果缓冲区中已经有了一些内容,这些内容将被从缓冲区中移除。


Servlet 线程安全

服务器在收到请求之后,会启动一个线程来进行相应的请求处理。

默认情况下,服务器为每个 Servlet 只创建一个对象实例。当多个请求访问同一个 Servlet 时,会有多个线程访问同一个 Servlet 对象,此时就可能发生线程安全问题。

多线程并发逻辑,需要使用 synchronized 对代码加锁处理,但尽量避免使用。


状态管理

Web 程序基于 HTTP 协议通信,而 HTTP 协议是”无状态”的协议,一旦服务器响应完客户的请求之后,就断开连接,而同一个客户的下一次请求又会重新建立网络连接。

服务器程序有时是需要判断是否为同一个客户发出的请求,比如客户的多次选购商品。因此,有必要跟踪同一个客户发出的一系列请求。

把浏览器与服务器之间多次交互作为一个整体,将多次交互所涉及的数据保存下来,即状态管理。

多次交互的数据状态可以在客户端保存,也可以在服务器端保存。

状态管理主要分为两类:

  • 客户端管理 - 将状态保存在客户端。基于 Cookie 技术实现。
  • 服务器管理 - 将状态保存在服务器端。基于 Session 技术实现。


Cookie 技术

基本概念

Cookie 表示客户端以“名-值”形式进行保存的一种技术。

浏览器向服务器发送请求时,服务器将数据以 Set-Cookie 消息头的方式响应给浏览器,然后浏览器会将这些数据以文本文件的方式保存起来。

当浏览器再次访问服务器时,会将这些数据以 Cookie 消息头的方式发送给服务器。

相关的方法

  • 使用 javax.servlet.http.Cookie 类的构造方法实现 Cookie 的创建。

Cookie(String name, String value) 根据参数指定数值构造对象

  • 使用 javax.servlet.http.HttpServletResponse 接口的成员方法实现 Cookie 的添加。

void addCookie(Cookie cookie) 添加参数指定的对象到响应

  • 使用 javax.servlet.http.HttpServletRequest 接口的成员方法实现 Cookie 对象的获取。

Cookie[] getCookies() 返回此请求中包含的所有 Cookie 对象

  • 使用 javax.servlet.http.Cookie 类的构造方法实现 Cookie 对象中属性的获取和修改。

String getName() 返回此 Cookie 对象中的名字

String getValue() 返回此 Cookie 对象的数值

void setValue(String newValue) 设置 Cookie 的数值

Cookie 的生命周期

  • 默认情况下,浏览器会将 Cookie 信息保存在内存中,只要浏览器关闭,Cookie 信息就会消失。
  • 如果希望关闭浏览器后 Cookie 信息仍有效,可以通过 Cookie 类的成员方法实现。

int getMaxAge() 返回cookie的最长使用期限(以秒为单位)

void setMaxAge(int expiry) 设置cookie的最长保留时间(秒)

Cookie 的路径问题

  • 浏览器在访问服务器时,会比较 Cookie 的路径与请求路径是否匹配,只有匹配的 Cookie 才会发送给服务器。
  • Cookie 的默认路径等于添加这个 Cookie 信息时的组件路径,例如:/项目名/目录/add.do 请求添加了一个 Cookie 信息,则该 Cookie 的路径是 /项目名/目录。
  • 访问的请求地址必须符合 Cookie 的路径或者其子路径时,浏览器才会发送 Cookie 信息。如果访问请求地址为 项目名/test.html,则路径为 项目名 的 Cookie 信息会被发送到服务器;如果访问请求地址为 项目名/目录/test.html,则路径为 项目名 和 项目名/目录 的 Cookie 信息会被发送到服务器。

void setPath(String uri) 设置 Cookie 的路径信息

Cookie 的特点

Cookie 技术不适合存储所有数据,程序员只用于存储少量、非敏感信息,原因如下:

  • 将状态数据保存在浏览器端,不安全
  • 保存数据量有限制,大约 4 KB 左右
  • 只能保存字符串信息
  • 可以通过浏览器设置为禁止使用


Session 技术

基本概念

Session 是用来维护一个客户端和服务器关联的一种技术。

浏览器访问服务器时,服务器会为每一个浏览器都在服务器端的内存中分配一个空间,用于创建一个 Session 对象,该对象有一个 id 属性且该值唯一,我们称为 SessionId,并且服务器会将这个 SessionId 以 Cookie 方式发送给浏览器存储。

浏览器再次访问服务器时会将 SessionId 发送给服务器,服务器可以依据 SessionId 查找相对应的 Session 对象。

相关的方法

  • 使用 javax.servlet.http.HttpServletRequest 接口的成员方法实现 Session 的获取。

HttpSession getSession() 返回此请求关联的当前 Session,若此请求没有则创建一个

  • 使用 javax.servlet.http.HttpSession 接口的成员方法实现判断和获取。

boolean isNew() 判断是否为新创建的 Session

String getId() 获取 Session 的编号

  • 使用 javax.servlet.http.HttpSession 接口的成员方法实现属性的管理。

Object getAttribute(String name) 返回在此会话中用指定名称绑定的对象,如果没有对象在该名称下绑定,则返回空值

void setAttribute(String name, Object value) 使用指定的名称将对象绑定到此会话

void removeAttribute(String name) 从此会话中删除与指定名称绑定的对象

Session 的生命周期

  • 为了节省服务器内存空间资源,服务器会将空闲时间过长的 Session 对象自动清除掉,服务器默认的超时限制一般是 30 分钟。
  • 使用 javax.servlet.http.HttpSession 接口的成员方法实现失效实现的获取和设置。

int getMaxInactiveInterval() 获取失效时间

void setMaxInactiveInterval(int interval) 设置失效时间

  • 可以配置 web.xml 文件修改失效时间。
<session-config>
    <session-timeout>30</session-timeout>
</session-config>

Session 的特点

数据比较安全。

能够保存的数据类型丰富,而 Cookie 只能保存字符串。

能够保存更多的数据,而 Cookie 大约保存 4 KB。

数据保存在服务器端会占用服务器的内存空间,如果存储信息过多、用户量过大,会严重影响服务器的性能。

想了解更多,欢迎关注我的微信公众号:Renda_Zhang

相关推荐

ES6中 Promise的使用场景?(es6promise用法例子)

一、介绍Promise,译为承诺,是异步编程的一种解决方案,比传统的解决方案(回调函数)更加合理和更加强大在以往我们如果处理多层异步操作,我们往往会像下面那样编写我们的代码doSomething(f...

JavaScript 对 Promise 并发的处理方法

Promise对象代表一个未来的值,它有三种状态:pending待定,这是Promise的初始状态,它可能成功,也可能失败,前途未卜fulfilled已完成,这是一种成功的状态,此时可以获取...

Promise的九大方法(promise的实例方法)

1、promise.resolv静态方法Promise.resolve(value)可以认为是newPromise方法的语法糖,比如Promise.resolve(42)可以认为是以下代码的语...

360前端一面~面试题解析(360前端开发面试题)

1.组件库按需加载怎么做的,具体打包配了什么-按需加载实现:借助打包工具(如Webpack的require.context或ES模块动态导入),在使用组件时才引入对应的代码。例如在V...

前端面试-Promise 的 finally 怎么实现的?如何在工作中使用?

Promise的finally方法是一个非常有用的工具,它无论Promise是成功(fulfilled)还是失败(rejected)都会执行,且不改变Promise的最终结果。它的实现原...

最简单手写Promise,30行代码理解Promise核心原理和发布订阅模式

看了全网手写Promise的,大部分对于新手还是比较难理解的,其中几个比较难的点:状态还未改变时通过发布订阅模式去收集事件实例化的时候通过调用构造函数里传出来的方法去修改类里面的状态,这个叫Re...

前端分享-Promise可以中途取消啦(promise可以取消吗)

传统Promise就像一台需要手动组装的设备,每次使用都要重新接线。而Promise.withResolvers的出现,相当于给开发者发了一个智能遥控器,可以随时随地控制异步操作。它解决了三大...

手写 Promise(手写输入法 中文)

前言都2020年了,Promise大家肯定都在用了,但是估计很多人对其原理还是一知半解,今天就让我们一起实现一个符合PromiseA+规范的Promise。附PromiseA+规范地址...

什么是 Promise.allSettled()!新手老手都要会?

Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的pr...

前端面试-关于Promise解析与高频面试题示范

Promise是啥,直接上图:Promise就是处理异步函数的API,它可以包裹一个异步函数,在异步函数完成时抛出完成状态,让代码结束远古时无限回掉的窘境。配合async/await语法糖,可...

宇宙厂:为什么前端离不开 Promise.withResolvers() ?

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。1.为什么需要Promise.with...

Promise 新增了一个超实用的 API!

在JavaScript的世界里,Promise一直是处理异步操作的神器。而现在,随着ES2025的发布,Promise又迎来了一个超实用的新成员——Promise.try()!这个新方法简...

一次搞懂 Promise 异步处理(promise 异步顺序执行)

PromisePromise就像这个词的表面意识一样,表示一种承诺、许诺,会在后面给出一个结果,成功或者失败。现在已经成为了主流的异步编程的操作方式,写进了标准里面。状态Promise有且仅有...

Promise 核心机制详解(promise机制的实现原理)

一、Promise的核心状态机Promise本质上是一个状态机,其行为由内部状态严格管控。每个Promise实例在创建时处于Pending(等待)状态,此时异步操作尚未完成。当异步操作成功...

javascript——Promise(js实现promise)

1.PromiseES6开始支持,Promise对象用于一个异步操作的最终完成(包括成功和失败)及结果值的表示。简单说就是处理异步请求的。之所以叫Promise,就是我承诺,如果成功则怎么处理,失败怎...

取消回复欢迎 发表评论: