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 的工作原理如下:
- 用户首次访问服务器时,服务器会创建一个新的 Session 对象,并生成一个唯一的 Session ID。
- 服务器将 Session ID 通过 Cookie 发送给客户端浏览器,这个 Cookie 的名称通常为JSESSIONID。
- 客户端浏览器在后续的请求中,会将包含JSESSIONID的 Cookie 发送回服务器。
- 服务器接收到请求后,根据 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从入门到精通:全面探索与实战(一)-CSDN博客 目录 四、Java Web 开发中的数据库操作:以 MySQL 为例 4.1 MySQL 数据库基础操作 4.2 JDBC 技术深度解析 4.3 数据库连接池的应用 五、Java Web 中的会话技术ÿ…...
基于大模型的阵发性室上性心动过速风险预测与治疗方案研究
目录 一、引言 1.1 研究背景与意义 1.2 研究目的与目标 1.3 研究方法与数据来源 二、阵发性室上性心动过速概述 2.1 定义与分类 2.2 发病机制与流行病学 2.3 临床表现与诊断方法 三、大模型在阵发性室上性心动过速预测中的应用 3.1 大模型技术原理与特点 3.2 模型构…...
秒杀业务的实现过程
一.后台创建秒杀的活动场次信息,并关联到要秒杀的商品或服务; 二.通过定时任务,将秒杀的活动信息和商品服务信息存储到redis; 三.在商品展示页的显眼位置加载秒杀活动信息; 四.用户参与秒杀,创建订单,将…...
spring mvc @ResponseBody 注解转换为 JSON 的原理与实现详解
ResponseBody 注解转换为 JSON 的原理与实现详解 1. 核心作用 ResponseBody 是 Spring MVC 的一个注解,用于将方法返回的对象直接序列化为 HTTP 响应体(如 JSON 或 XML),而不是通过视图解析器渲染为视图(如 HTML&…...
TDengine.C/C++ 连接器
简介 C/C 开发人员可以使用 TDengine 的客户端驱动,即 C/C 连接器(以下都用 TDengine 客户端驱动表示),开发自己的应用来连接 TDengine 集群完成数据存储、查询以及其他功能。TDengine 客户端驱动的 API 类似于 MySQL 的 C API。…...
[docker] 简单操作场景
Docker的简单操作场景 1 安装 暂时没空写~ 2 登陆 一共4步: ~$ sudo docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d765d4c1eb5f ubuntu:24.04 "/bin/bash" …...
skynet.rawcall使用详解及应用场景
目录 核心特性函数原型使用场景场景 1:高性能二进制传输(如文件转发)场景 2:自定义序列化协议(如 Protocol Buffers)场景 3:跨服务共享内存(避免拷贝) 配套接收方实现与 …...
使用SpringSecurity下,发生重定向异常
使用SpringSecurity下,发生空转异常 环境信息: Spring Boot 3.4.4 , jdk 17 , springSecurity 6.4.4 问题背景: 没有自定义controller ,改写了login 页面,并且进行了成功后的跳转处理…...
gbase8s之逻辑导出导入脚本(完美版本)
该脚本dbexport.sh用于快速导出库和导入库(使用多并发unload,和多并发dbload的方式) #!/bin/sh #脚本功能:将数据导出成文本,迁移至其他实例 #最后更新时间:2023-12-19 #使用方法: #1.执行该脚…...
Elasticsearch | ES索引模板、索引和索引别名的创建与管理
关注:CodingTechWork 引言 在使用 Elasticsearch (ES) 和 Kibana 构建数据存储和分析系统时,索引模板、索引和索引别名的管理是关键步骤。本文将详细介绍如何通过 RESTful API 和 Kibana Dev Tools 创建索引模板、索引以及索引别名,并提供具…...
【Easylive】视频删除方法详解:重点分析异步线程池使用
【Easylive】项目常见问题解答(自用&持续更新中…) 汇总版 方法整体功能 这个deleteVideo方法是一个综合性的视频删除操作,主要完成以下功能: 权限验证:检查视频是否存在及用户是否有权限删除核心数据删除&…...
力扣hot100_回溯(2)_python版本
一、39. 组合总和(中等) 代码: class Solution:def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:ans []path []def dfs(i: int, left: int) -> None:if left 0:# 找到一个合法组合ans.append(pa…...
SGLang实战:从KV缓存复用到底层优化,解锁大模型高效推理的全栈方案
在当今快速发展的人工智能领域,大型语言模型(LLM)的应用已从简单对话扩展到需要复杂逻辑控制、多轮交互和结构化输出的高级任务。面对这一趋势,如何高效地微调并部署这些大模型成为开发者面临的核心挑战。本文将深入探讨SGLang——这一专为大模型设计的高…...
LPDDR4内存颗粒命名规则全解析:三星、镁光、海力士、南亚、长鑫等厂商型号解码与选型指南
由于之前DDR的系列选型文章有很好的反馈,所以补充LPDDR4低功耗内存的选型和命名规则,总结了目前市面上常用的内存,供硬件工程师及数码爱好者参考。 在智能手机、平板电脑和低功耗设备中,LPDDR4 SDRAM凭借其高带宽、低功耗特性成为…...
特权FPGA之Johnson移位
完整代码: module johnson(clk,rst_n,led,sw1_n,sw2_n,sw3_n);input clk; //时钟信号,50MHz input rst_n; //复位信号,低电平有效 output[3:0] led; //LED控制,1--灭…...
网络安全小知识课堂(最终完结版)
网络安全入门 :从 “小白” 到 “守护者” 的蜕变之旅 写在完结之际 历经 13 篇的深度探索,我们从 DDoS 攻击的 “流量洪水” 一路闯关到 HTTPS 的 “加密堡垒”,揭开了网络安全世界的层层面纱。感谢每一位读者的陪伴与互动,你们…...
2025年AI生成引擎搜索发展现状与趋势总结
2025年AI生成引擎搜索发展现状与趋势总结 一、国内外AI生成引擎搜索发展现状 1. 国内动态 社交搜索崛起:小红书2024年Q4日均搜索量达6亿次,用户更依赖社交平台UGC内容进行决策(如购物、旅游场景)&#…...
【杂谈】Godot4.4导出到Android平台(正式导出)
学博而后可约,事历而后知要。 目录 一、准备二、Gradle构建三、配置Java SDK四、配置Android SDK五、配置密钥 一、准备 本文在前文【杂谈】Godot4.4导出到安卓平台(调试导出)的基础上,进行正式导出。调试导出并不是真正的编译导…...
VBA将Word文档内容逐行写入Excel
如果你需要将Word文档的内容导入Excel工作表来进行数据加工,使用下面的代码可以实现: Sub ImportWordToExcel()Dim wordApp As Word.ApplicationDim wordDoc As Word.DocumentDim excelSheet As WorksheetDim filePath As VariantDim i As LongDim para…...
基于AI设计开发出来的业务系统是什么样的?没有菜单?没有表格?
基于AI设计开发出的业务系统仍然会包含菜单、表格等传统UI元素,但AI技术会显著改变它们的实现方式和交互逻辑。以下是具体分析: 一、传统元素的持续存在 功能刚需性 • 菜单承担着系统导航的核心功能,表格则是结构化数据展示的基础载体。根…...
C++ -异常之除以 0 问题(整数除以 0 编译时检测、整数除以 0 运行时检测、浮点数除以 0 编译时检测、浮点数除以 0 运行时检测)
一、整数除以 0(编译时检测) 1、演示 #include <iostream>using namespace std;int main() {int result 10 / 0;cout << result << endl;return 0; }程序无法运行,输出结果 error C2124: 被零除或对零求模2、演示解读 …...
数字足迹管理(DFM):你的网络隐身指南
数字足迹管理(DFM):你的网络隐身指南 你可能不知道,你的姓名、电话、住址正在网上被“明码标价” ——而这一切,可能只是因为你点过外卖、寄过快递,甚至注册过一个网站。 一、什么是数字足迹管理&#…...
如何避免“过度承诺”导致的验收失败
如何避免“过度承诺”导致的验收失败?关键在于: 评估可行性、设置合理目标、高频沟通反馈、阶段性验收、做好风险管理。其中设置合理目标至关重要,很多团队往往在项目初期为迎合客户或领导而报出“最理想方案”,忽略了资源、技术及…...
MySQL学习笔记集--游标
游标 在MySQL中,游标(Cursor)是一种数据库对象,它允许您逐行处理查询结果集。游标通常与存储过程一起使用,因为它们需要在存储过程或函数中声明和操作。游标的使用涉及几个步骤:声明游标、打开游标、从游标…...
紧跟数字人热潮:123 数字人分身克隆系统源码部署与风口洞察
在当今数字化浪潮中,数字人技术无疑已成为最具活力与潜力的领域之一,正以迅猛之势席卷多个行业,重塑着人们的交互方式与商业运作模式。C 站作为技术交流的前沿阵地,汇聚了众多关注前沿科技的开发者与技术爱好者,今天来…...
QT控件 修改QtTreePropertyBrowser自定义属性编辑器源码,添加第一列标题勾选,按钮,右键菜单事件等功能
头阵子遇到一个需要修改QtTreePropertyBrowser控件的需求,QT开发做这么久了,这个控件倒是第一次用,费了点时间研究,在这里做个简单的总结。 QtTreePropertyBrowser控件 是 Qt 解决方案 (Qt Solutions) 中的一个组件,用…...
Excel 日期值转换问题解析
目录 问题原因 解决方案 方法1:使用 DateTime.FromOADate 转换 方法2:处理可能为字符串的情况 方法3:使用 ExcelDataReader 时的处理 额外提示 当你在 Excel 单元格中看到 2024/12/1,但 C# 读取到 45627 时,这是…...
0. 七小时挑战:自研企业级任务调度器--前言
在软件开发的世界里,有一个亘古不变的问题:“为什么不直接用现成的?”这句话听起来合理、理性、务实,甚至有点老道。毕竟,时间宝贵、预算有限,轮子已经造好了,何必再动手? 但有时候…...
Spring 核心注解深度解析:@Autowired、@Repository 与它们的协作关系
引言 在 Spring 框架中,依赖注入(DI) 是实现松耦合架构的核心机制。Autowired 和 Repository 作为两个高频使用的注解,分别承担着 依赖装配 和 数据访问层标识 的关键职责。本文将深入探讨它们的功能特性、协作模式…...
开源模型应用落地-模型上下文协议(MCP)-从数据孤岛到万物互联(一)
一、前言 当开发者还在为每个AI工具编写臃肿的API适配器时,一场关于「连接」的技术革命已悄然降临。模型上下文协议(MCP)正在用一套全新的交互语法,重新定义人工智能与物理世界的对话方式。MCP协议如同为AI系统装上了“万能接口”…...
