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

Spring MVC请求转发疑问:清空AdDto标题后转发仍带旧值?

为什么Spring MVC转发后仍能获取到旧的DTO属性值?

问题场景

我在Spring MVC开发中实现了如下修改广告的接口:

@RequestMapping("/modify")
public String modifyAd(AdDto adDto, Model model){
    if (adService.modifyAd(adDto)){
        adDto.setTitle("");
        model.addAttribute(PageCodeEnum.KEY,PageCodeEnum.MODIFY_SUCCESS);
    }else {
        model.addAttribute(PageCodeEnum.KEY,PageCodeEnum.MODEFY_FAILED);
    }
    return "forward:search";
}

从JSP获取的adDto.title值为'芒果冰淇淋11',我已经将其设置为空字符串,随后转发至标注@RequestMapping(value = "/search",method = RequestMethod.POST)的queryByTitle方法,但该方法中仍能获取到旧的标题值,这是为什么?


问题原因

嘿,这个问题我之前踩过坑,其实本质是Spring MVC转发时的请求参数绑定逻辑在搞鬼:

你在modifyAd方法里修改的adDto.setTitle(""),只是修改了当前方法内存中的AdDto对象实例,但当你用forward:search做服务器内部转发时,Spring MVC会重新执行一次请求参数绑定流程——它会从原始的HttpServletRequest请求对象里读取参数,重新创建并填充一个新的AdDto对象,然后传给queryByTitle方法。而原始请求里的title参数还是最初从JSP传过来的'芒果冰淇淋11',所以新的AdDto自然还是旧值。

简单说:你改的是内存里的临时对象,转发时用的是原始请求里的参数,两者不是一回事。


解决方案

给你几个可行的解决思路,按需选择:

方案一:改用重定向(推荐,符合PRG模式)

转发是服务器内部复用原始请求,而重定向是让客户端发起全新的请求,原始请求参数不会被携带。这种方式还能避免表单重复提交的问题:

@RequestMapping("/modify")
public String modifyAd(AdDto adDto, RedirectAttributes redirectAttrs){
    if (adService.modifyAd(adDto)){
        // 用FlashAttribute传递提示信息,重定向后不会丢失
        redirectAttrs.addFlashAttribute(PageCodeEnum.KEY,PageCodeEnum.MODIFY_SUCCESS);
    }else {
        redirectAttrs.addFlashAttribute(PageCodeEnum.KEY,PageCodeEnum.MODIFY_FAILED);
    }
    // 重定向到search接口,新请求无旧title参数
    return "redirect:search";
}

方案二:清空请求中的title参数

如果你一定要用转发,可以通过包装HttpServletRequest来修改请求参数:

@RequestMapping("/modify")
public String modifyAd(AdDto adDto, Model model, HttpServletRequest request){
    if (adService.modifyAd(adDto)){
        // 用包装类覆盖title参数的取值
        HttpServletRequest wrappedRequest = new HttpServletRequestWrapper(request) {
            @Override
            public String getParameter(String name) {
                if ("title".equals(name)) {
                    return "";
                }
                return super.getParameter(name);
            }

            @Override
            public String[] getParameterValues(String name) {
                if ("title".equals(name)) {
                    return new String[]{""};
                }
                return super.getParameterValues(name);
            }
        };
        model.addAttribute(PageCodeEnum.KEY,PageCodeEnum.MODIFY_SUCCESS);
        // 转发时使用包装后的请求对象
        ModelAndView mv = new ModelAndView("forward:search");
        mv.addAllObjects(model.asMap());
        return mv.getViewName();
    }else {
        model.addAttribute(PageCodeEnum.KEY,PageCodeEnum.MODIFY_FAILED);
    }
    return "forward:search";
}

方案三:让search方法优先从Model获取AdDto

在modifyAd方法里把修改后的AdDto放到Model中,然后在queryByTitle方法里用@ModelAttribute注解指定从Model中获取对象,跳过请求参数绑定:

// 修改modify方法,将修改后的adDto存入Model
@RequestMapping("/modify")
public String modifyAd(AdDto adDto, Model model){
    if (adService.modifyAd(adDto)){
        adDto.setTitle("");
        model.addAttribute("adDto", adDto); // 存入Model
        model.addAttribute(PageCodeEnum.KEY,PageCodeEnum.MODIFY_SUCCESS);
    }else {
        model.addAttribute(PageCodeEnum.KEY,PageCodeEnum.MODIFY_FAILED);
    }
    return "forward:search";
}

// search方法通过@ModelAttribute获取Model中的adDto
@RequestMapping(value = "/search",method = RequestMethod.POST)
public String queryByTitle(@ModelAttribute("adDto") AdDto adDto, Model model){
    // 这里的adDto就是modify方法里修改后的对象,title为空
    // 后续业务逻辑...
}

内容的提问来源于stack exchange,提问作者武新楠

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:01:42