当前位置: 首页 > news >正文

Java Web从入门到精通:全面探索与实战(二)

Java Web从入门到精通:全面探索与实战(一)-CSDN博客 

 

目录

四、Java Web 开发中的数据库操作:以 MySQL 为例

4.1 MySQL 数据库基础操作

4.2 JDBC 技术深度解析

4.3 数据库连接池的应用​

五、Java Web 中的会话技术:Cookie 与 Session​

5.1 Cookie 详解​

5.2 Session 详解​


四、Java Web 开发中的数据库操作:以 MySQL 为例

4.1 MySQL 数据库基础操作

MySQL 作为一种广泛使用的开源关系型数据库管理系统,在 Java Web 开发中扮演着举足轻重的数据存储与管理角色。理解并掌握 MySQL 的基础操作是进行 Java Web 数据库开发的基石。​

数据库在 MySQL 中是数据存储与组织的核心容器,宛如一个大型的仓库,用于存放各类数据。创建数据库时,使用CREATE DATABASE语句,语法为CREATE DATABASE [IF NOT EXISTS] database_name;。其中,IF NOT EXISTS为可选参数,用于避免在数据库已存在时抛出错误。例如,创建一个名为testdb的数据库,代码如下:

CREATE DATABASE IF NOT EXISTS testdb;

若要切换当前操作的数据库,使用USE语句,如USE testdb;,这就像是进入仓库的特定区域进行操作。查看所有数据库,可执行SHOW DATABASES;,它会列出系统中所有的数据库,方便我们了解数据库的整体情况。而当某个数据库不再需要时,可使用DROP DATABASE语句删除,如DROP DATABASE testdb;,但此操作需谨慎,因为一旦执行,数据库及其所有数据将被永久删除。​

表是数据库中数据存储的具体结构,类似于仓库中的一个个货架,每个货架存放特定类型的数据。创建表时,需定义表名及各列的名称、数据类型和约束条件。例如,创建一个名为users的表,用于存储用户信息,包含id(用户 ID,整数类型,自动递增且为主键)、username(用户名,可变长度字符串,最大长度为 50)、email(邮箱,可变长度字符串,最大长度为 100)和password(密码,可变长度字符串,最大长度为 50),代码如下:

CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(50),email VARCHAR(100),password VARCHAR(50)
);

查看数据库中的所有表,执行SHOW TABLES;,它会展示当前数据库中所有的表名。若要查看某个表的结构,使用DESCRIBE语句,如DESCRIBE users;,它会详细列出表中各列的信息,包括列名、数据类型、是否允许为空等,帮助我们了解表的设计。当表不再需要时,使用DROP TABLE语句删除,如DROP TABLE users;,同样,此操作会删除表及其所有数据,需谨慎使用。​

在数据库中插入数据是常见操作,向users表中插入一条用户数据,包含用户名john_doe、邮箱john@example.com和密码password123,代码如下:

INSERT INTO users (username, email, password) VALUES 
('john_doe', 'john@example.com', 'password123');

若要插入多条数据,可在VALUES关键字后用逗号分隔多个值列表,如:

INSERT INTO users (username, email, password) VALUES 
('jane_smith', 'jane@example.com', 'password456'),
('tom_wilson', 'tom@example.com', 'password789');

从数据库中查询数据是获取信息的关键操作。查询users表中所有用户的信息,使用SELECT语句,代码如下:

SELECT * FROM users;

这里的*表示选择所有列。若只查询部分列,如只查询username和email列,代码为:

SELECT username, email FROM users;

若要根据条件查询,如查询用户名为john_doe的用户信息,使用WHERE子句,代码如下:

SELECT * FROM users WHERE username = 'john_doe';

还可以对查询结果进行排序,如按username升序排序,代码为:

SELECT * FROM users ORDER BY username ASC;

ASC表示升序,DESC表示降序。​

更新数据库中的数据用于修改现有记录。将users表中用户名为john_doe的用户邮箱更新为new_john@example.com,代码如下:

UPDATE users SET email = 'new_john@example.com' WHERE username = 'john_doe';

删除数据库中的数据用于移除不再需要的记录。删除users表中用户名为tom_wilson的用户记录,代码如下:

DELETE FROM users WHERE username = 'tom_wilson';

4.2 JDBC 技术深度解析

JDBC(Java Database Connectivity)是 Java 语言中用于连接和操作数据库的重要 API,它为 Java 开发者提供了一种统一的方式来与各种不同类型的数据库进行交互,使得 Java 应用程序能够方便地访问和管理数据库中的数据,就像一座桥梁,连接着 Java 程序与数据库。​

JDBC 的核心接口和常用类构成了其强大功能的基础。DriverManager类是 JDBC 的管理层,负责管理数据库驱动程序的加载和建立数据库连接。它就像是一个交通枢纽管理员,协调着 Java 程序与不同数据库之间的连接。例如,在加载 MySQL 数据库驱动时,使用Class.forName("com.mysql.cj.jdbc.Driver");语句,告知DriverManager要使用的数据库驱动类。​

Connection接口代表与数据库的连接,它是与数据库交互的基础。通过DriverManager.getConnection(url, username, password)方法获取连接对象,其中url为数据库连接字符串,username和password分别为数据库的用户名和密码。例如:

String url = "jdbc:mysql://localhost:3306/testdb";
String username = "root";
String password = "password";
Connection connection = DriverManager.getConnection(url, username, password);

Statement接口用于执行 SQL 语句,它可以直接执行静态 SQL 语句。通过Connection对象的createStatement()方法创建Statement对象,如Statement statement = connection.createStatement();。然后使用statement.executeQuery(sql)方法执行查询语句,返回ResultSet结果集;使用statement.executeUpdate(sql)方法执行插入、更新、删除等语句,返回受影响的行数。​

PreparedStatement接口继承自Statement接口,它主要用于执行预编译的 SQL 语句。预编译的 SQL 语句可以提高执行效率,并且能有效防止 SQL 注入攻击。通过Connection对象的prepareStatement(sql)方法创建PreparedStatement对象,其中sql为带有参数占位符(?)的 SQL 语句。例如,插入用户数据的预编译 SQL 语句为:

String sql = "INSERT INTO users (username, email, password) VALUES (?,?,?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, "new_user");
preparedStatement.setString(2, "new_user@example.com");
preparedStatement.setString(3, "new_password");
int rowsAffected = preparedStatement.executeUpdate();

ResultSet接口用于存储查询结果集,它提供了一系列方法来遍历和获取结果集中的数据。通过Statement或PreparedStatement执行查询语句后返回ResultSet对象,然后使用while (resultSet.next())循环遍历结果集,通过resultSet.getString("column_name")等方法获取指定列的值。例如:

String sql = "SELECT * FROM users";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {int id = resultSet.getInt("id");String username = resultSet.getString("username");String email = resultSet.getString("email");System.out.println("ID: " + id + ", Username: " + username + ", Email: " + email);
}

接下来,我们通过一个完整的代码示例来展示如何使用 JDBC 连接 MySQL 数据库并执行查询操作:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;public class JdbcExample {public static void main(String[] args) {String url = "jdbc:mysql://localhost:3306/testdb";String username = "root";String password = "password";try {// 加载驱动程序Class.forName("com.mysql.cj.jdbc.Driver");// 获取连接Connection connection = DriverManager.getConnection(url, username, password);// 创建Statement对象Statement statement = connection.createStatement();// 执行查询语句String sql = "SELECT * FROM users";ResultSet resultSet = statement.executeQuery(sql);// 处理结果集while (resultSet.next()) {int id = resultSet.getInt("id");String usernameFromDb = resultSet.getString("username");String email = resultSet.getString("email");System.out.println("ID: " + id + ", Username: " + usernameFromDb + ", Email: " + email);}// 关闭资源resultSet.close();statement.close();connection.close();} catch (Exception e) {e.printStackTrace();}}
}

在上述代码中,首先加载 MySQL 驱动程序,然后通过DriverManager获取与数据库的连接。接着创建Statement对象,执行查询语句并获取结果集。最后,通过循环遍历结果集,输出查询到的用户信息。操作完成后,依次关闭ResultSet、Statement和Connection对象,以释放资源。​

在使用 JDBC 过程中,可能会遇到一些常见问题。例如,驱动程序未找到异常ClassNotFoundException,这通常是因为没有正确添加数据库驱动包或驱动类名写错。解决方法是确保数据库驱动包已正确添加到项目的类路径中,并检查驱动类名是否正确。​

还有连接数据库失败的问题,可能是由于连接字符串错误、用户名或密码错误、数据库服务器未启动等原因导致。此时需要仔细检查连接字符串、用户名和密码,确保数据库服务器处于运行状态。​

SQL 注入攻击也是一个需要关注的问题,如用户输入的数据被恶意拼接在 SQL 语句中,可能导致数据泄露或数据被篡改。使用PreparedStatement代替Statement可以有效防止 SQL 注入攻击,因为PreparedStatement会对参数进行预处理,避免了直接将用户输入的数据拼接到 SQL 语句中。​

4.3 数据库连接池的应用​

在 Java Web 开发中,频繁地创建和销毁数据库连接会带来显著的性能开销,因为建立数据库连接涉及网络通信、数据库认证等复杂操作,耗费时间和资源。数据库连接池技术应运而生,它通过预先创建一定数量的数据库连接,并将这些连接存储在连接池中,当应用程序需要与数据库进行交互时,可以直接从连接池中获取一个可用的连接,而不需要每次都重新建立连接。使用完成后,连接会被返回到连接池中,以便后续使用。这种方式大大减少了连接的建立和销毁的开销,提高了系统的性能和响应速度,就像一个连接的 “仓库”,随时为应用程序提供可用的连接。​

常见的数据库连接池有 HikariCP、C3P0、DBCP 等。HikariCP 以其高性能和低延迟著称,具有快速的连接获取速度、低资源消耗和高并发性能等特点,适用于高并发、高性能需求的应用程序。C3P0 是一个老牌的 Java 数据库连接池,具有较高的稳定性和可靠性,支持自动回收连接、测试连接的有效性等功能,还提供了多种配置选项,用户可以根据具体需求进行灵活配置。DBCP 是 Apache Commons 项目的一部分,具有简单易用、配置灵活等特点,支持连接池的基本功能,如连接回收、连接测试等,同时还提供了一些高级功能,如连接的统计信息、自动重连等。​

接下来,我们以 C3P0 为例,展示如何配置和使用数据库连接池。首先,需要在项目中添加 C3P0 的依赖。如果使用 Maven 项目,在pom.xml文件中添加以下依赖:

<dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.5</version>
</dependency>

然后,在src目录下创建c3p0-config.xml配置文件,进行连接池的配置,示例代码如下:

<c3p0-config><default-config><!-- 数据库驱动名 --><property name="driverClass">com.mysql.cj.jdbc.Driver</property><!-- 数据库的url --><property name="jdbcUrl">jdbc:mysql://localhost:3306/testdb</property><!-- 用户名 --><property name="user">root</property><!-- 密码 --><property name="password">password</property><!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default:3 --><property name="acquireIncrement">5</property><!-- 初始化数据库连接池时连接的数量 --><property name="initialPoolSize">5</property><!-- 数据库连接池中的最小的数据库连接数 --><property name="minPoolSize">5</property><!-- 数据库连接池中的最大的数据库连接数 --><property name="maxPoolSize">10</property><!-- 连接关闭时默认将所有未提交的操作回滚。Default: false --><property name="autoCommitOnClose">false</property><!-- 每60秒检查所有连接池中的空闲连接。Default:0 --><property name="idleConnectionTestPeriod">60</property><!-- 最大空闲时间,指定的时间内未使用则连接被丢弃。若为0则永不丢弃。Default:0 --><property name="maxIdleTime">300</property></default-config>
</c3p0-config>

在上述配置文件中,设置了数据库驱动类、连接 URL、用户名、密码等基本信息,还配置了连接池的一些属性,如初始连接数、最小连接数、最大连接数、获取连接失败后的重试策略等。​

接下来,通过代码获取连接池中的连接并执行数据库操作,示例代码如下:

import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class C3P0Example {public static void main(String[] args) {// 创建C3P0数据源ComboPooledDataSource dataSource = new ComboPooledDataSource();try {// 配置数据源属性(也可通过c3p0-config.xml配置)dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/testdb");dataSource.setUser("root");dataSource.setPassword("password");// 配置连接池属性(也可通过c3p0-config.xml配置)dataSource.setMinPoolSize(5);dataSource.setMaxPoolSize(10);dataSource.setCheckoutTimeout(3000);Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;try {// 从连接池获取连接connection = dataSource.getConnection();// 执行查询String sql = "SELECT * FROM users";preparedStatement = connection.prepareStatement(sql);resultSet = preparedStatement.executeQuery();// 处理查询结果while (resultSet.next()) {int id = resultSet.getInt("id");String username = resultSet.getString("username");String email = resultSet.getString("email");System.out.println("ID: " + id + ", Username: " + username + ", Email: " + email);}} catch (SQLException ex) {ex.printStackTrace();} finally {// 释放资源if (resultSet != null) {try {resultSet.close();} catch (SQLException ex) {ex.printStackTrace();}}if (preparedStatement != null) {try {preparedStatement.close();} catch (SQLException ex) {ex.printStackTrace();}}if (connection != null) {try {connection.close(); // 将连接放回连接池} catch (SQLException ex) {ex.printStackTrace();}}}} catch (PropertyVetoException ex) {ex.printStackTrace();} finally {// 关闭数据源(通常在应用程序关闭时执行)dataSource.close();}}
}

五、Java Web 中的会话技术:Cookie 与 Session​

5.1 Cookie 详解​

Cookie 是一种客户端会话管理技术,它就像是服务器发给客户端浏览器的一张小纸条,用于在客户端存储少量数据。当用户访问服务器时,服务器可以将一些信息以 Cookie 的形式发送给浏览器,浏览器会将这些 Cookie 存储在本地。当下次用户再次访问服务器时,浏览器会自动将这些 Cookie 发送给服务器,服务器可以根据这些 Cookie 来识别用户的身份或获取相关的用户信息。​

Cookie 的主要作用包括:​

  • 会话状态管理:例如用户登录信息的记录,当用户登录成功后,服务器可以将用户的登录状态以 Cookie 的形式发送给浏览器,下次用户访问时,服务器可以通过 Cookie 判断用户是否已经登录,从而决定是否需要用户再次登录。​
  • 个性化设置:存储用户的个性化设置,如用户在网站上设置的语言偏好、主题风格等,服务器可以根据 Cookie 中的设置为用户提供个性化的服务。​
  • 购物车功能:在电商网站中,Cookie 可以用于存储用户购物车中的商品信息,方便用户在不同页面之间切换时,购物车中的商品信息不会丢失。​

在 Java 中,操作 Cookie 主要使用javax.servlet.http.Cookie类。常用的属性和方法如下:​

  • 属性:​
  • name:Cookie 的名称,用于标识 Cookie,名称必须唯一。​
  • value:Cookie 的值,用于存储具体的数据。​
  • maxAge:Cookie 的最大生存时间,以秒为单位。如果设置为正数,Cookie 会在指定的时间后过期;如果设置为负数,Cookie 会在浏览器关闭时过期(默认情况);如果设置为 0,则会立即删除该 Cookie。​
  • path:Cookie 的路径,指定 Cookie 在哪些路径下有效。例如,如果设置为/app,则只有访问/app或其子路径(如/app/products)的请求才会携带该 Cookie;如果设置为/,则整个网站的所有路径下的请求都会携带该 Cookie。​
  • domain:Cookie 的域名,指定 Cookie 在哪个域名下有效。默认情况下,Cookie 只在创建它的域名下有效;如果设置为一级域名(如.example.com),则该域名及其所有子域名(如www.example.com、api.example.com)下的请求都可以访问该 Cookie。​
  • secure:是否仅通过 HTTPS 连接传输 Cookie。如果设置为true,则只有在使用 HTTPS 协议访问时,浏览器才会将该 Cookie 发送给服务器,以提高 Cookie 在传输过程中的安全性;如果设置为false(默认值),则 HTTP 和 HTTPS 连接都可以传输 Cookie。​
  • httpOnly:是否只能通过 HTTP (S) 请求访问 Cookie。如果设置为true,则 JavaScript 代码无法读取或修改该 Cookie,从而增强了 Cookie 的安全性,防止 Cookie 被 JavaScript 脚本窃取或篡改;如果设置为false(默认值),则 JavaScript 代码可以访问 Cookie。​
  • 常用方法:​
  • Cookie(String name, String value):构造方法,用于创建一个 Cookie 对象,传入 Cookie 的名称和值。​
  • void setMaxAge(int expiry):设置 Cookie 的最大生存时间,单位为秒。​
  • String getName():获取 Cookie 的名称。​
  • String getValue():获取 Cookie 的值。​
  • void setValue(String value):设置 Cookie 的值。​
  • void setPath(String path):设置 Cookie 的路径。​
  • void setDomain(String domain):设置 Cookie 的域名。​
  • void setSecure(boolean flag):设置是否仅通过 HTTPS 连接传输 Cookie。​
  • void setHttpOnly(boolean flag):设置是否只能通过 HTTP (S) 请求访问 Cookie。​

下面通过代码示例来展示如何创建、发送和获取 Cookie:

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/cookieExample")
public class CookieExampleServlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 创建一个Cookie对象,名称为username,值为JohnCookie cookie = new Cookie("username", "John");// 设置Cookie的最大生存时间为1小时(3600秒)cookie.setMaxAge(3600);// 设置Cookie的路径为根路径cookie.setPath("/");// 将Cookie添加到响应中,发送给客户端response.addCookie(cookie);response.getWriter().println("Cookie has been set.");}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}
}

上述代码创建了一个名为username,值为John的 Cookie,并设置了它的最大生存时间为 1 小时,路径为根路径,然后将其添加到响应中发送给客户端。​

在另一个 Servlet 中获取 Cookie 的代码如下:

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/getCookieExample")
public class GetCookieExampleServlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 获取客户端发送的所有CookieCookie[] cookies = request.getCookies();if (cookies != null) {for (Cookie cookie : cookies) {// 找到名为username的Cookieif ("username".equals(cookie.getName())) {String username = cookie.getValue();response.getWriter().println("Username from Cookie: " + username);break;}}}}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}
}

这段代码从客户端请求中获取所有的 Cookie,并遍历查找名为username的 Cookie,如果找到则输出其值。​

需要注意的是,在设置 Cookie 的路径时,要根据实际需求进行设置。如果路径设置不当,可能会导致 Cookie 无法在预期的页面中被发送或接收。例如,如果一个 Cookie 的路径设置为/app,那么在访问根路径(/)下的页面时,该 Cookie 不会被发送;只有在访问/app或其子路径下的页面时,该 Cookie 才会被发送。此外,Cookie 的大小有限制,每个 Cookie 通常不能超过 4KB,并且浏览器对同一个域名下的 Cookie 数量也有限制,一般最多为 20 个左右,在使用 Cookie 时要考虑这些限制因素。​

5.2 Session 详解​

Session 是一种服务端会话管理技术,它为每个用户的浏览器创建一个独享的会话空间,用于在服务器端存储用户的会话数据。当用户访问服务器时,服务器会为其创建一个 Session 对象,并分配一个唯一的 Session ID。这个 Session ID 通常会通过 Cookie 发送给客户端浏览器,浏览器在后续的请求中会将这个 Session ID 发送回服务器,服务器根据这个 Session ID 来识别用户的会话,并获取该用户在 Session 中存储的数据。​

Session 的工作原理如下:​

  1. 用户首次访问服务器时,服务器会创建一个新的 Session 对象,并生成一个唯一的 Session ID。​
  2. 服务器将 Session ID 通过 Cookie 发送给客户端浏览器,这个 Cookie 的名称通常为JSESSIONID。​
  3. 客户端浏览器在后续的请求中,会将包含JSESSIONID的 Cookie 发送回服务器。​
  4. 服务器接收到请求后,根据 Cookie 中的JSESSIONID找到对应的 Session 对象,从而获取该用户的会话数据。​

Session 的主要作用是在一次会话中,为用户提供一个可以在不同页面或请求之间共享数据的空间。例如,在一个电商网站中,用户在浏览商品时将商品添加到购物车,这些购物车中的商品信息就可以存储在 Session 中。当用户跳转到结算页面时,服务器可以从 Session 中获取购物车信息,展示给用户并进行结算操作。​

在 Java 中,操作 Session 主要通过HttpSession接口。常用的方法如下:​

  • HttpSession getSession():获取当前请求的 Session 对象。如果当前请求没有 Session 对象,则会创建一个新的 Session 对象。​
  • HttpSession getSession(boolean create):获取当前请求的 Session 对象。如果create参数为true,且当前请求没有 Session 对象,则会创建一个新的 Session 对象;如果create参数为false,且当前请求没有 Session 对象,则返回null。​
  • void setAttribute(String name, Object value):在 Session 中存储一个属性,属性名为name,属性值为value。​
  • Object getAttribute(String name):从 Session 中获取指定属性名的属性值。如果属性不存在,则返回null。​
  • void removeAttribute(String name):从 Session 中移除指定属性名的属性。​
  • String getId():获取 Session 的唯一标识符(Session ID)。​
  • long getCreationTime():获取 Session 的创建时间,返回值为自 1970 年 1 月 1 日 00:00:00 GMT 以来的毫秒数。​
  • long getLastAccessedTime():获取客户端最后一次访问该 Session 的时间,返回值为自 1970 年 1 月 1 日 00:00:00 GMT 以来的毫秒数。​
  • void setMaxInactiveInterval(int interval):设置 Session 的最大非活动间隔时间,单位为秒。如果在这个时间内客户端没有访问该 Session,则 Session 会被销毁。​
  • int getMaxInactiveInterval():获取 Session 的最大非活动间隔时间,单位为秒。​
  • void invalidate():使当前 Session 失效,即销毁 Session 对象及其存储的所有属性。​

下面通过代码示例来展示如何创建、获取和销毁 Session,以及在 Session 中保存和获取数据:

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;@WebServlet("/sessionExample")
public class SessionExampleServlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 获取当前请求的Session对象,如果不存在则创建一个新的HttpSession session = request.getSession();// 在Session中保存一个属性,名称为username,值为Johnsession.setAttribute("username", "John");// 获取Session的IDString sessionId = session.getId();response.getWriter().println("Session ID: " + sessionId);response.getWriter().println("Username saved in Session: " + session.getAttribute("username"));// 设置Session的最大非活动间隔时间为30分钟(1800秒)session.setMaxInactiveInterval(1800);}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}
}

上述代码获取当前请求的 Session 对象,在 Session 中保存了一个名为username,值为John的属性,并输出了 Session ID 和保存的用户名。同时,设置了 Session 的最大非活动间隔时间为 30 分钟。​

在另一个 Servlet 中获取 Session 数据的代码如下:

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;@WebServlet("/getSessionExample")
public class GetSessionExampleServlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 获取当前请求的Session对象HttpSession session = request.getSession(false);if (session != null) {// 从Session中获取名为username的属性值String username = (String) session.getAttribute("username");response.getWriter().println("Username from Session: " + username);} else {response.getWriter().println("Session does not exist.");}}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}
}

这段代码获取当前请求的 Session 对象(如果不存在则不创建),并从 Session 中获取名为username的属性值进行输出。​

销毁 Session 的代码如下:

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;@WebServlet("/destroySessionExample")
public class DestroySessionExampleServlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 获取当前请求的Session对象HttpSession session = request.getSession(false);if (session != null) {// 使Session失效,即销毁Sessionsession.invalidate();response.getWriter().println("Session has been destroyed.");} else {response.getWriter().println("Session does not exist.");}}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}
}

这段代码获取当前请求的 Session 对象(如果不存在则不创建),并调用invalidate方法使 Session 失效,即销毁 Session 及其存储的所有属性。​

Session 与 Cookie 有着密切的关系,Session 的实现依赖于 Cookie 来传递 Session ID。如果客户端禁用了 Cookie,那么 Session ID 就无法通过 Cookie 发送回服务器,服务器也就无法识别用户的会话。为了解决这个问题,可以采用 URL 重写的方式,将 Session ID 附加在 URL 后面进行传递。例如,原本的 URL 为http://example.com/page,经过 URL 重写后变为http://example.com/page;jsessionid=1234567890,这样服务器仍然可以根据 URL 中的 Session ID 来识别用户的会话。不过,这种方式存在一定的安全风险,因为 Session ID 暴露在 URL 中,可能会被恶意用户窃取和利用,所以在实际应用中,应尽量确保客户端启用 Cookie 来传递 Session ID,以提高系统的安全性。

相关文章:

Java Web从入门到精通:全面探索与实战(二)

Java Web从入门到精通&#xff1a;全面探索与实战&#xff08;一&#xff09;-CSDN博客 目录 四、Java Web 开发中的数据库操作&#xff1a;以 MySQL 为例 4.1 MySQL 数据库基础操作 4.2 JDBC 技术深度解析 4.3 数据库连接池的应用​ 五、Java Web 中的会话技术&#xff…...

从个人博客到电商中台:EdgeOne Pages的MCP Server弹性架构×DeepSeek多场景模板实测报告

什么是EdgeOne Pages&#xff1f; EdgeOne Pages 是腾讯云推出的一站式边缘开发与部署平台&#xff0c;基于全球边缘节点网络和 Serverless 架构&#xff0c;为开发者提供从代码托管到全球分发的全流程服务。其核心价值在于将边缘计算能力与现代 Web 开发范式深度融合&#xf…...

【C++】优先级队列+反向迭代器

priority_queue的介绍 通常用堆来实现&#xff0c;能在O(log n)的时间复杂度内插入和提取最高&#xff08;或最低&#xff09;优先级的元素。 优先队列是一种容器适配器&#xff0c;根据严格的弱排序标准&#xff0c;它的第一个元素总是它所包含的元素中最大的(默认情况)。此…...

HOW - 缓存 React 自定义 hook 的所有返回值(包括函数)

目录 场景优化方案示例延伸例子&#xff1a;为什么这很重要&#xff1f;常见的请求 hook 封装优化前优化后优化点一览优化后的 useLoadData使用方式示例&#xff1a;优点回顾 场景 如果你写了一个自定义 Hook&#xff0c;比如 useMyHook()&#xff0c;它暴露出某些值或函数给外…...

AIDD-人工智能药物设计-网络药理学-多组学与网络药理学分析揭示龟龄集治疗少精症的机制

IF6.7|多组学与网络药理学分析揭示龟龄集治疗少精症的机制 2024年10月28日&#xff0c;海军军医大学张卫东教授团队在Phytomedicine&#xff08;IF6.7&#xff09;上发表了题为“Multi-omics and network pharmacology approaches reveal Gui-Ling-Ji alleviates oligoastheno…...

打破单一视角!融合红外和可见光,YOLO算法实现全天候无人机检测

目录 一、摘要 二、系统概述 三、数据集 视频记录 数据集标注 四、数据集分析 五、基于深度学习的无人机探测 基于规则的跟踪方法 六、结论 论文题目&#xff1a;Drone Detection and Tracking with YOLO and a Rule-based Method 论文链接&#xff1a;https://arxiv.…...

Go 语言数据类型

Go 语言数据类型 概述 Go 语言(也称为 Golang)是一种静态强类型、编译型、并发型、具有垃圾回收功能的编程语言。自2009年发布以来,Go 语言因其简洁的语法、高效的执行速度和强大的并发处理能力而广受欢迎。本文将详细介绍 Go 语言中的数据类型,帮助读者更好地理解和掌握…...

<tauri><rust><GUI>基于rust和tauri,将tauri程序打包为window系统可安装的安装包(exe、msi)

前言 本文是基于rust和tauri,由于tauri是前、后端结合的GUI框架,既可以直接生成包含前端代码的文件,也可以在已有的前端项目上集成tauri框架,将前端页面化为桌面GUI。 发文平台 CSDN 环境配置 系统:windows 10平台:visual studio code语言:rust、javascript库:taur…...

ragflow开启https访问:ssl证书为pem文件,window如何添加证书

在 Windows 系统中安装 PEM 格式的证书(通常用于 SSL/TLS 或客户端认证)可以通过以下步骤完成: 方法 1:通过证书管理器(MMC)安装 打开证书管理器 按 Win + R,输入 mmc 回车。点击菜单栏的 文件 > 添加/删除管理单元。选择 证书 > 添加,然后选择 计算机账户 或 当…...

自己搭建cesium应用程序

Cesium项目开发基础(1)——Cesium环境搭建_cesium版本怎么看-CSDN博客 看这篇的时候&#xff1a; 所以要用IIS搭建网站。下载一些东西看这篇的这部分&#xff1a;Tomcat IIS 在局域网中搭建网站&#xff08;最全最详细教程&#xff09;_tomcat iis-CSDN博客 然后在IIS里怎么…...

本地项目HTTPS访问问题解决方案

本地项目无法通过 HTTPS 访问的原因通常是默认配置未启用 HTTPS 或缺少有效的 SSL 证书。以下是详细解释和解决方案&#xff1a; 原因分析 默认开发服务器仅支持 HTTP 大多数本地开发工具&#xff08;如 Vite、Webpack、React 等&#xff09;默认启动的是 HTTP 服务器&#xff…...

软考系统架构设计师之物联网与边缘计算笔记

一、物联网与边缘计算的核心概念 1. 物联网&#xff08;IoT&#xff09; 定义&#xff1a;通过传感器、设备等物理对象接入网络&#xff0c;实现数据采集、传输与智能控制&#xff0c;核心在于物联设备互联与数据驱动决策。架构分层&#xff1a; 感知层&#xff1a;传感器、R…...

已知Word内容格式固定,通过宏实现Word转Excel

文章目录 需求描述一、宏是什么&#xff1f;二、使用步骤1.启用开发工具2.VBA基础知识3.单个Word文件转为Excel4.批量将Word文件转为Excel文件 总结 需求描述 现在有多个Word文档&#xff0c;Word文档格式固定&#xff0c;假如Word内容分为单选题和多选题&#xff0c;每个题目…...

window上 docker使用ros2开发并usbip共享usb设备

曾经参考 https://blog.csdn.net/laoxue123456/article/details/138339029 来共享windows上的usb 发现没有办法成功总是出现 tcp 错误。telnet测试能够正常连接 很是奇怪&#xff0c;window上换成低版本的usbipd仍然是同样的错误&#xff0c;没有办法的情况下参考了docker官方文…...

3D激光轮廓仪知识整理

文章目录 1.原理和应用场景1.1 相机原理1.1.1 测量原理1.1.2 相机激光器1.1.3 沙姆镜头1.1.4 相机标定1.1.5 中心线提取 1.2 应用场景1.2.1 测量相关应用1.2.2 缺陷检测相关应用 2.相机参数介绍及选型介绍2.1 成像原理2.2 原始图成像2.3 生成轮廓图2.4 相机规格参数2.4.1 单轮廓…...

SSH远程工具

一、常见SSH远程工具 工具开源跨平台多标签文件传输高级功能价格Xshell❌Win✔️✔️脚本、会话管理免费/商业版Tabby✔️全平台✔️✔️插件扩展免费MobaXterm❌Win✔️✔️集成工具集免费/付费SecureCRT❌Win/macOS/Linux✔️✔️企业级加密$129+PuTTY✔️全平台❌❌基础连接…...

C++day8

思维导图 牛客练习 练习 #include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> #include <sstream> #include <vector> #include <memory> using namespace std; class user{ public: …...

Vue响应式系统的简单实现

一、什么是副作用函数和响应式数据&#xff1f; 副作用函数&#xff1a; 可以产生副作用的函数&#xff0c;那么什么是副作用呢&#xff1f;举个栗子&#xff1a; let count 1function effect() {count }function fn() {if (count 1) {console.log(执行1)} else {console.l…...

超卖问题解决方案

目录 需求概述 系统需求 提升高并发吞吐量 解决超卖问题 解决方案分析 悲观锁与乐观锁 悲观锁 乐观锁 数据库行级锁 实现悲观锁&#xff08;排他锁&#xff09; 实现乐观锁 悲观锁&乐观锁 Redis分布式锁 Redis原子操作方案 方案分析 技术实现 通过MULTI事务…...

智享AI直播代理:零门槛掘金新风口

智享AI直播代理&#xff1a;零门槛掘金新风口 传统直播困局&#xff0c;AI破局而生 在电商与内容创业井喷的今天&#xff0c;传统直播模式却陷入“三高”泥潭——人力成本高、内容门槛高、运营风险高。一位主播单日直播超8小时即面临状态下滑&#xff0c;而多平台运营更需…...

在huggingface上制作小demo

在huggingface上制作小demo 今天好兄弟让我帮他搞一个模型&#xff0c;他有小样本的化学数据&#xff0c;想让我根据这些数据训练一个小模型&#xff0c;他想用这个模型预测一些值 最终我简单训练了一个小模型&#xff0c;起初想把这个模型和GUI界面打包成exe发给他&#xff0…...

Spring、Spring Boot和 Spring Cloud 的关系

Spring、Spring Boot和 Spring Cloud 的关系 Spring, Spring Boot 和 Spring Cloud 都是 Spring 生态系统中的重要组成部分&#xff0c;它们之间有紧密的关系&#xff0c;但各自有不同的定位和功能。下面是它们之间的关系和区别&#xff1a; 1、Spring Framework&#xff1a;…...

[蓝桥杯] 求和(C语言)

题目链接 P8772 [蓝桥杯 2022 省 A] 求和 - 洛谷 题目理解 这道题就是公式题&#xff0c;我们模拟出公式后&#xff0c;输出最终结果即可。 本题不难&#xff0c;相信很多同学第一次见到这道题都是直接暴力解题。 两个for循环&#xff0c;测试样例&#xff0c;直接拿下。 #in…...

从用户需求到产品迭代:Scrum 实践全流程详解

目录 前言1. 用户需求与产品待办列表的形成1.1 用户需求的来源与整理1.2 构建产品待办列表&#xff08;Product Backlog&#xff09; 2. 迭代计划与目标设定2.1 Sprint 的时间周期设定2.2 设定明确的 Sprint 目标 3. 开发执行与每日站会3.1 高效协作的开发过程3.2 每日站会&…...

windows10安装配置并使用Miniconda3

windows10安装配置并使用Miniconda3 Conda 与 Anaconda 的区别 Conda 是包管理和环境管理工具&#xff0c;Anaconda 在 Conda 的 基础上预装了大量科学计算包 Conda 与 pip 的区别 Conda 是跨语言的包和环境管理器&#xff08;支持 Python/R 等&#xff09;&#xff0c;能安…...

16-产品经理-需求的评审

在创建需求的时候&#xff0c;有一个"不需要评审"的复选框&#xff0c;如果选中该复选框的话&#xff0c;需求的创建成功后状态是激活的。 但大部分情况下面&#xff0c;需求还是需要评审的。 即使产品完全由一个人负责&#xff0c;也可以将一些不成熟的想法存为草…...

【java图形化界面编程】

文章目录 一、GUI简介二、Swing1.容器组件2. 布局管理器&#xff1a;BorderLayout3.代码实现 实验总结&#xff1a; 一、GUI简介 GUI&#xff1a;图形用户界面。通过图形用户界面&#xff0c;程序的输入输出可以脱离控制台JAVA中实现GUI主要使用3种技术&#xff1a;AMT&#x…...

BGP路由协议之属性1

公认属性是所有 BGP 路由器都必须能够识别的属性 公认必遵 (Well-known Mandatory) : 必须包括在每个 Update 消息里公认任意 (Well-known Discretionary) : 可能包括在某些 Update 消息里。 可选属性不需要都被 BGP 路由器所识别 可选过渡(OptionalTransitive) : BGP 设备不…...

架构思维: 数据一致性的两种场景深度解读

文章目录 Pre案例数据一致性问题的两种场景第一种场景&#xff1a;实时数据不一致不要紧&#xff0c;保证数据最终一致性就行第二种场景&#xff1a;必须保证实时一致性 最终一致性方案实时一致性方案TCC 模式Seata 中 AT 模式的自动回滚一阶段二阶段-回滚二阶段-提交 Pre 架构…...

压测工具开发实战篇(四)——client子窗口功能

你好&#xff0c;我是安然无虞。 文章目录 树控件添加文件补充学习: 函数定义中循环体里的局部变量补充学习: 动态添加对象属性 刷新文件上下文菜单 (右键菜单)实现右键菜单功能 编辑节点文本 在学习本篇文章之前, 建议先看一下上篇介绍MDI子窗口的文章: 压测工具开发实战篇(三…...

如何开发 HTML 游戏

开发 HTML 游戏适合初学者学习编程和游戏开发的基础知识。HTML 游戏通常结合了 HTML、CSS 和 JavaScript 技术&#xff0c;利用浏览器的渲染能力来实现交互式的游戏体验。 1. 确定游戏类型 在开始开发之前&#xff0c;你需要明确你的游戏类型。例如&#xff1a; 简单游戏&…...

机器学习 从入门到精通 day_01

1. 机器学习介绍与定义 1.1 机器学习定义 机器学习&#xff08;Machine Learning&#xff09;本质上就是让计算机自己在数据中学习规律&#xff0c;并根据所得到的规律对未来数据进行预测。 机器学习包括如聚类、分类、决策树、贝叶斯、神经网络、深度学习&#xff08…...

React中的跨组件通信

在React中&#xff0c;跨组件通信有几种常见的方式。每种方式适用于不同的场景&#xff0c;下面是几种常见的跨组件通信方法&#xff1a; 1. 通过父子组件传递 Props 父组件可以通过 props 将数据传递给子组件&#xff0c;子组件只能接收和使用这些数据。 父组件&#xff08…...

Vue项目 bug 解决

Vue2项目部署失败 从gitee 上拉下一个前端项目&#xff0c;然后npm install&#xff0c;报错如下&#xff1a; 解决办法&#xff1a; 从 npm切换到cnpm&#xff1a;npm install -g cnpm执行命令export NODE_OPTIONS--openssl-legacy-provider下载依赖&#xff1a;cnpm instal…...

Python 3.13.2 安装教程(附安装包)轻松开启编程之旅

文章目录 前言软件介绍安装步骤1. 下载安装包2. 运行安装程序3. 选择安装选项4. 等待安装完成5. 验证安装结果 前言 在数字化时代&#xff0c;Python 作为一种简洁、高效且功能强大的编程语言&#xff0c;广泛应用于 Web 开发、数据科学、人工智能等诸多领域。无论是编程新手入…...

Meta 最新发布的 Llama 4:多模态开源大模型全面解析

TL;DR 2025 年 4 月 5 日&#xff0c;Meta AI 正式发布了第四代大型语言模型 Llama 4。引入了 Mixture-of-Experts (MoE&#xff0c;专家混合) 架构&#xff0c;同时原生支持多模态输入&#xff0c;最小的 Llama 4 Scout 模型支持 10m 的长文本输入。 Paper name The Llama 4…...

Web开发:常用 HTML 表单标签介绍

在 Web 开发中&#xff0c;HTML 表单是实现用户交互的关键元素&#xff0c;它为用户提供了输入数据的途径&#xff0c;广泛应用于注册登录、搜索查询、问卷调查等功能场景。本文将详细介绍常用的 HTML 表单标签及其使用方法。 表单容器标签 <form> <form>标签用…...

力扣HOT100之链表:2. 两数相加

这道题就是按照正常的数学思维去做的&#xff0c;设置一个标志位flag用来标记进位的情况&#xff0c;当发生进位时设置为1&#xff0c;否则设置为0&#xff0c;初始时设置为0。我们同时遍历两个链表&#xff0c;将两个节点的值相加&#xff0c;再加上上一位的进位flag&#xff…...

Spring Boot 项目集成 License 授权与续期完整指南

一、背景说明 在 Spring Boot 项目中&#xff0c;通过引入第三方 spring-boot-starter-license 组件&#xff0c;可以快速实现系统权限到期控制、License 证书管理等功能。本文详细介绍如何集成 License 功能&#xff0c;并解决证书安装、权限配置、异常拦截及续期流程等关键问…...

2010年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析

2010年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析 全国大学生数学建模竞赛&#xff08;China Undergraduate Mathematical Contest in Modeling&#xff09;是国家教委高教司和中国工业与应用数学学会共同主办的面向全国大学生的群众性科技活动&#xff0c;目的在于激…...

典型的ETL使用场景与数据集成平台的应用

在当今数字化时代&#xff0c;数据已经成为企业决策和运营的核心资产。为了更好地管理和利用数据&#xff0c;企业需要借助高效的数据处理技术。ETL&#xff08;Extract&#xff0c;Transform&#xff0c;Load&#xff09;作为数据处理的核心技术之一&#xff0c;广泛应用于数据…...

深入解析嵌入式Linux系统架构:从Bootloader到用户空间 - 结合B站视频教学

B站视频链接,请多多关注本人B站&#xff1a; &#x1f4cc; Yocto项目实战教程&#xff1a;第二章 视频讲解 目录 第2章 Linux系统架构 2.1 GNU/Linux2.2 Bootloader2.3 内核空间2.4 用户空间 总结 第2章 Linux系统架构 {#linux系统架构} 嵌入式Linux系统是Linux内核的精简版…...

从Oracle和TiDB的HTAP说起

除了数据库行业其他技术群体很多不知道HTAP的 时至今日还是有很多人迷信Hadoop&#xff0c;觉得大数据就是Hadoop。这是不正确的。也难怪这样&#xff0c;很多人OLTP和OLAP也分不清&#xff0c;何况HTAP。 Oracle是垂直方向实现 TiDB是水平方向实现 我个人认为这是两种流派…...

【Vue-路由案例】面经基础版

目录 <<回到导览1.面经基础版1.1.VueCli建项目1.1.1.VueCli 自定义项目1.1.2.ESlint代码规范 1.2.项目路由1.2.1.一级路由配置1.2.2.二级配置路由1.2.3.设置高亮1.2.4.发生请求、渲染1.2.5.跳转传参、再发请求1.2.6.体验优化1.2.7.keep-alive <<回到导览 1.面经基…...

C#调用C++动态库时出现`System.DllNotFoundException`错误的解决思路

文章目录 1. DLL文件路径问题2. 依赖的运行时库缺失3. 平台不匹配&#xff08;x86/x64&#xff09;4. 导出函数名称不匹配5. DLL文件损坏或权限问题6. 运行时库冲突&#xff08;MT/MD不匹配&#xff09;7. 使用DLLImport时的常见错误总结步骤 在C#中调用C动态库时出现System.Dl…...

数据清洗

map阶段&#xff1a;按行读入内容&#xff0c;对内容进行检查&#xff0c;如果字段的个数少于等于11&#xff0c;就删除这条日志&#xff08;不保留&#xff09;去除日志中字段个数小于等于11的日志内容。 <偏移量&#xff0c;第一行的内容> → <通过刷选之后的第一行…...

ubuntu 20.04 编译和运行A-LOAM

1.搭建文件目录和clone代码 mkdir -p A-LOAM/src cd A-LOAM/src git clone https://github.com/HKUST-Aerial-Robotics/A-LOAM cd .. 2.修改代码文件 2.1 由于PCL版本1.10&#xff0c;将CMakeLists.txt中的C标准改为14&#xff1a; set(CMAKE_CXX_FLAGS "-stdc14"…...

Oracle迁移翻车,数据校验没做好...

作为DBA&#xff0c;你是否经历过这样的噩梦&#xff1f;数据库迁移、主从同步、容灾切换后&#xff0c;数据不一致却迟迟无法定位&#xff0c;只能手动写脚本逐表比对&#xff0c;熬到凌晨还在查差异… Oracle GoldenGate Veridata&#xff08;OGG Veridata&#xff09; 就是…...

小刚说C语言刷题——第17讲 循环之for语句

在生活中&#xff0c;我们经常会碰到重复去做某一件事。例如&#xff0c;一个人绕着操场跑圈&#xff0c;一天24小时往复。这些周而往复的事&#xff0c;我们称为循环。 1.循环的作用 在编程时&#xff0c;我们用循环的目的有两个。一个是减少循环时代码量&#xff0c;一个是通…...

如何使用 Coze 的 HTTP 请求节点实现高效数据交互

如何使用Coze的HTTP请求节点实现高效数据交互 在自动化工作流开发中&#xff0c;与外部服务进行数据交互是核心需求之一。Coze平台的HTTP请求节点提供了强大的解决方案&#xff0c;支持通过HTTP协议实现数据的获取、提交、更新和删除等操作。本文将结合官方文档&#xff0c;详…...