Java案例怎么实现Session存储?

wen java案例 24

本文目录导读:

Java案例怎么实现Session存储?

  1. 基本Session存储(HttpSession)
  2. Redis存储Session(分布式场景)
  3. 数据库存储Session
  4. 最佳实践建议
  5. 注意事项

我来详细说明Java中实现Session存储的几种常见方式。

基本Session存储(HttpSession)

使用Servlet API的HttpSession

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SessionServlet extends HttpServlet {
    // 存储数据到Session
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws IOException {
        // 获取Session(如果没有则创建)
        HttpSession session = request.getSession();
        // 设置Session过期时间(秒),默认30分钟
        session.setMaxInactiveInterval(3600); // 1小时
        // 存储数据
        session.setAttribute("username", "张三");
        session.setAttribute("userRole", "admin");
        // 存储对象
        User user = new User("张三", "zhangsan@example.com");
        session.setAttribute("user", user);
        response.getWriter().println("Session存储成功!");
    }
    // 读取Session数据
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws IOException {
        HttpSession session = request.getSession(false);
        if (session != null) {
            String username = (String) session.getAttribute("username");
            User user = (User) session.getAttribute("user");
            response.getWriter().println("用户名: " + username);
            response.getWriter().println("用户信息: " + user);
        } else {
            response.getWriter().println("Session不存在或已过期");
        }
    }
}

Redis存储Session(分布式场景)

添加依赖(Maven)

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
    <version>2.7.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800) // 30分钟
public class RedisSessionConfig {
    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer serializer = new DefaultCookieSerializer();
        serializer.setCookieName("SESSIONID");
        serializer.setCookiePath("/");
        serializer.setDomainName("example.com");
        serializer.setUseHttpOnlyCookie(true);
        serializer.setUseSecureCookie(false);
        return serializer;
    }
}

使用Redis存储Session

import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpSession;
@RestController
@RequestMapping("/session")
public class SessionController {
    @PostMapping("/save")
    public String saveSession(HttpSession session) {
        // 存储到Redis
        session.setAttribute("userId", "12345");
        session.setAttribute("loginTime", System.currentTimeMillis());
        session.setAttribute("userInfo", new UserInfo("张三", "admin"));
        return "Session已保存到Redis,Session ID: " + session.getId();
    }
    @GetMapping("/get")
    public Object getSession(HttpSession session) {
        String userId = (String) session.getAttribute("userId");
        Long loginTime = (Long) session.getAttribute("loginTime");
        UserInfo userInfo = (UserInfo) session.getAttribute("userInfo");
        return String.format("用户ID: %s, 登录时间: %d, 用户信息: %s", 
                           userId, loginTime, userInfo);
    }
    @PostMapping("/clear")
    public String clearSession(HttpSession session) {
        session.invalidate(); // 销毁Session
        return "Session已清除";
    }
}
// 用户信息类(必须实现序列化)
class UserInfo implements java.io.Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private String role;
    public UserInfo(String name, String role) {
        this.name = name;
        this.role = role;
    }
    // getters and setters
}

数据库存储Session

创建Session表

CREATE TABLE user_sessions (
    session_id VARCHAR(100) PRIMARY KEY,
    user_id VARCHAR(50),
    session_data BLOB,
    created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_access_time TIMESTAMP,
    expiry_time TIMESTAMP
);

JDBC Session实现

import java.sql.*;
import java.util.Date;
public class DatabaseSessionManager {
    private Connection connection;
    public DatabaseSessionManager(Connection connection) {
        this.connection = connection;
    }
    // 保存Session
    public void saveSession(Session session) throws SQLException {
        String sql = "INSERT INTO user_sessions (session_id, user_id, session_data, last_access_time, expiry_time) " +
                    "VALUES (?, ?, ?, ?, ?) " +
                    "ON DUPLICATE KEY UPDATE session_data = ?, last_access_time = ?, expiry_time = ?";
        try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
            pstmt.setString(1, session.getId());
            pstmt.setString(2, session.getUserId());
            pstmt.setObject(3, serialize(session.getData()));
            pstmt.setTimestamp(4, new Timestamp(System.currentTimeMillis()));
            pstmt.setTimestamp(5, new Timestamp(session.getExpiryTime().getTime()));
            pstmt.setObject(6, serialize(session.getData()));
            pstmt.setTimestamp(7, new Timestamp(System.currentTimeMillis()));
            pstmt.setTimestamp(8, new Timestamp(session.getExpiryTime().getTime()));
            pstmt.executeUpdate();
        }
    }
    // 读取Session
    public Session getSession(String sessionId) throws SQLException {
        String sql = "SELECT * FROM user_sessions WHERE session_id = ? AND expiry_time > NOW()";
        try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
            pstmt.setString(1, sessionId);
            ResultSet rs = pstmt.executeQuery();
            if (rs.next()) {
                Session session = new Session();
                session.setId(rs.getString("session_id"));
                session.setUserId(rs.getString("user_id"));
                session.setData(deserialize(rs.getBlob("session_data")));
                session.setLastAccessTime(rs.getTimestamp("last_access_time"));
                session.setExpiryTime(rs.getTimestamp("expiry_time"));
                return session;
            }
        }
        return null;
    }
    // 删除过期Session
    public void cleanExpiredSessions() throws SQLException {
        String sql = "DELETE FROM user_sessions WHERE expiry_time < NOW()";
        try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
            int deleted = pstmt.executeUpdate();
            System.out.println("清理了 " + deleted + " 个过期Session");
        }
    }
    // 序列化方法
    private byte[] serialize(Object obj) {
        // 实现对象序列化逻辑
        return new byte[0];
    }
    private Object deserialize(Blob blob) {
        // 实现对象反序列化逻辑
        return null;
    }
}
// Session实体类
class Session {
    private String id;
    private String userId;
    private Object data;
    private Date lastAccessTime;
    private Date expiryTime;
    // getters and setters
}

最佳实践建议

Session配置优化

// application.yml配置
spring:
  session:
    store-type: redis  # 可选:redis, jdbc, hazelcast
    timeout: 1800      # Session超时时间(秒)
    redis:
      namespace: myapp:session  # Redis key前缀
      flush-mode: on-save       # 保存策略:immediate/on-save

Session工具类

import javax.servlet.http.HttpSession;
import java.util.Optional;
public class SessionUtil {
    // 安全获取Session属性
    public static <T> T getAttribute(HttpSession session, String key, Class<T> type) {
        return Optional.ofNullable(session)
                      .map(s -> s.getAttribute(key))
                      .filter(type::isInstance)
                      .map(type::cast)
                      .orElse(null);
    }
    // 带默认值的获取
    public static <T> T getAttributeOrDefault(HttpSession session, String key, 
                                            Class<T> type, T defaultValue) {
        T value = getAttribute(session, key, type);
        return value != null ? value : defaultValue;
    }
    // 批量添加属性
    public static void addAttributes(HttpSession session, java.util.Map<String, Object> attributes) {
        if (session != null && attributes != null) {
            attributes.forEach(session::setAttribute);
        }
    }
}

注意事项

  1. 序列化要求:存储的对象必须实现 Serializable 接口
  2. 性能考虑:避免存储大数据对象(如大图片)
  3. 安全问题:敏感信息加密存储
  4. 过期策略:合理设置Session超时时间
  5. 分布式环境:使用Redis等集中式存储方案

选择合适的Session存储方式取决于你的应用场景:

  • 单机应用:使用默认的HttpSession
  • 分布式应用:推荐使用Redis
  • 需要持久化:使用数据库存储

抱歉,评论功能暂时关闭!