You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Session存Redis时重定向发Flash对象遇类型转换异常

问题描述

在登录校验场景中,添加spring-session-data-redis依赖实现会话持久化与多设备踢除功能后,使用redirectAttributes.addFlashAttribute传递校验失败消息时抛出ClassCastException,异常栈核心信息如下:

Caused by: java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class org.springframework.web.servlet.FlashMap (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; org.springframework.web.servlet.FlashMap is in unnamed module of loader 'app')
    at org.springframework.web.servlet.support.AbstractFlashMapManager.getExpiredFlashMaps(AbstractFlashMapManager.java:130) ~[spring-webmvc-6.2.1.jar:6.2.1]
    at org.springframework.web.servlet.support.AbstractFlashMapManager.retrieveAndUpdate(AbstractFlashMapManager.java:99) ~[spring-webmvc-6.2.1.jar:6.2.1]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-6.2.1.jar:6.2.1]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.2.1.jar:6.2.1]
    ... 42 common frames omitted

注释掉addFlashAttribute相关代码后,重定向流程正常但无法展示提示消息,现需明确该异常的根本原因。


核心配置与代码

pom.xml关键依赖

<?xml version="1.0" encoding="UTF-8"?>
<project ...>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.1</version>
        <relativePath/>
    </parent>
    ...
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-core</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>3.4.1</version>
        </dependency>
        <!-- 新增的Redis会话持久化依赖 -->
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
            <version>3.4.1</version>
        </dependency>
    </dependencies>
    ...
</project>

LoginController核心逻辑

@Controller
public class LoginController {
    @GetMapping("login")
    public String getLogin() {
        return "login";
    }

    @PostMapping("login")
    public RedirectView postLogin(@Valid @ModelAttribute LoginRequest loginRequest, HttpServletRequest request,
                                  RedirectAttributes redirectAttributes) {
        String alertMessage = null;
        String username = loginRequest.getUsername();
        User user = userService.selectByUsernameAndPassword(username, loginRequest.getPassword());

        if (Objects.isNull(user)) {
            alertMessage = "Invalid username/password.";
        } else if (user.getEnableFlag() != EnableToggle.ENABLE) {
            alertMessage = "User account is disabled.";
        }

        if (StringUtils.isBlank(alertMessage)) {
            HttpSession currentSession = request.getSession();
            // 多设备会话踢除标记
            currentSession.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username);
            return new RedirectView("/", true);
        } else {
            redirectAttributes.addFlashAttribute("username", username);
            redirectAttributes.addFlashAttribute("alert", alertMessage);
            return new RedirectView("/login", true);
        }
    }
}

异常原因分析

该ClassCastException的根源是Spring Session使用Redis存储会话时,默认序列化机制无法正确还原FlashMap类型,具体逻辑链如下:

  1. 调用redirectAttributes.addFlashAttribute时,Spring Web会将闪存数据封装为FlashMap对象,并存入当前HttpSession。
  2. 添加spring-session-data-redis后,会话数据被持久化到Redis,默认使用的序列化器(如JdkSerializationRedisSerializer或未开启类型信息的GenericJackson2JsonRedisSerializer)会将FlashMap序列化为通用的LinkedHashMap结构,丢失了原始类型信息。
  3. 重定向后的请求尝试从Redis中读取并反序列化闪存数据时,得到的是LinkedHashMap实例,但AbstractFlashMapManager期望的是FlashMap类型,因此抛出类型转换异常。

本质上,Spring Web的FlashMap并非为分布式会话场景设计,默认序列化机制无法处理其类型识别需求,导致反序列化失败。


内容的提问来源于stack exchange,提问作者Gideon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 14:30:07