在Spring中重复的表单提交

6 浏览
0 Comments

在Spring中重复的表单提交

在Spring中,避免重复提交表单的最佳方式是什么?这个框架是否提供了处理这个问题的特殊功能(例如像Struts中的Synchronizer Token)?

0
0 Comments

在Spring中遇到(Duplicate form submission)问题时,出现的原因是用户重复提交表单。为了解决这个问题,可以在表单提交成功后进行重定向操作。在返回ModelAndView时,确保View是一个RedirectView。从用户的角度来看,他们提交表单后会被重定向到另一个URL进行"GET"操作,这样就不会重复提交了。

需要注意的是,当使用重定向视图(Redirect View)时,模型属性会作为参数暴露在URL中。因此,你可能希望尽可能保持属性的简洁性。通常我会显示一个页面给用户,页面中并不包含任何唯一信息,只是一个"确认"消息。

代码示例:

@Controller
public class FormController {
    @RequestMapping(value = "/submitForm", method = RequestMethod.POST)
    public ModelAndView submitForm(@ModelAttribute("form") Form form) {
        // 处理表单提交逻辑
        // ...
        // 返回重定向视图
        return new ModelAndView(new RedirectView("/confirm"));
    }
    @RequestMapping(value = "/confirm", method = RequestMethod.GET)
    public String showConfirmPage() {
        return "confirm";
    }
}

在上述示例中,表单提交后将被重定向到"/confirm"这个URL,显示一个"确认"页面给用户。这样即使用户重复提交,也只会重复访问这个确认页面,而不会重复执行表单提交逻辑。

0
0 Comments

在Spring框架中,存在一个问题称为“重复表单提交(Duplicate form submission)”。这个问题的出现原因是用户在提交表单时,可能会多次点击提交按钮或者刷新页面,导致表单数据被重复提交到后端服务器。

解决这个问题的方法是使用Spring提供的同步器令牌(synchronizer token)。同步器令牌是一种在表单中嵌入的隐藏字段,用于标识表单的唯一性。当用户提交表单时,后端服务器会验证同步器令牌的有效性,如果表单已经被提交过一次,后端服务器会拒绝再次提交。

以下是解决方法的具体步骤(代码示例可参考链接):

1. 在表单中添加同步器令牌字段:

<form action="/submit" method="post">
    <input type="hidden" name="token" value="${token}" />
    // 其他表单字段
</form>

2. 在后端控制器中生成和验证同步器令牌:

@Controller
public class FormController {
    
    @Autowired
    private TokenService tokenService;
    
    @GetMapping("/form")
    public String showForm(Model model) {
        String token = tokenService.generateToken();
        model.addAttribute("token", token);
        return "form";
    }
    
    @PostMapping("/submit")
    public String submitForm(@RequestParam("token") String token) {
        if (!tokenService.isValidToken(token)) {
            // 处理重复提交的逻辑
        }
        // 处理表单提交的逻辑
        return "success";
    }
}

3. 在TokenService中实现生成和验证令牌的逻辑:

@Service
public class TokenService {
    
    private Set tokens = new HashSet<>();
    
    public String generateToken() {
        String token = UUID.randomUUID().toString();
        tokens.add(token);
        return token;
    }
    
    public boolean isValidToken(String token) {
        if (tokens.contains(token)) {
            tokens.remove(token);
            return true;
        }
        return false;
    }
}

通过使用同步器令牌,可以防止用户重复提交表单,提高系统的安全性和稳定性。请点击此处了解更多关于Spring MVC同步器令牌的详细信息。

0
0 Comments

在Spring中避免重复提交有多种方法,可以结合使用:

  1. 使用JavaScript在点击后的几毫秒内disable按钮。这将避免因为不耐烦的用户多次点击按钮而导致多次提交。
  2. 提交后发送重定向,也被称为Post-Redirect-Get (PRG)模式。这将避免因为用户在结果页面按下F5并忽略浏览器的重复提交警告,或者在浏览器的前进/后退按钮上来回导航并忽略同样的警告而导致多次提交。
  3. 在页面请求时生成一个唯一的令牌,并将其放在会话范围和表单的隐藏字段中。在处理过程中,检查令牌是否存在,然后立即从会话中删除并继续处理。如果令牌不存在,则阻止处理。这将避免前面提到的问题。

在Spring中,可以使用RedirectView来实现PRG模式(如第2点所述)。其他两个点需要自行实现。

你好,我应用了PRG模式,它运行良好。但是我需要在GET方法中传递一条消息,比如"用户ID 1001创建成功"。为此,我在控制器类中定义了一个变量,在POST方法中设置其值,在GET方法中获取其值。这将为并发用户创建问题。我该如何避免这个问题?

:将其存储在会话或Cookie中。

不,这会占用更多的处理时间。与其我们手动编码,框架应该提供像Struts2.0默认提供的令牌功能。

对于如此好的答案点赞+1

仅供参考,Struts使用了第三种解决方案(dev.anyframejava.org/docs.en/anyframe/plugin/optional/struts/…

关于与C点相关的另一种类似方法,生成一个唯一令牌,并将其作为表单的隐藏字段。现在在Web过滤器中,在finally块中将其放入会话中并删除。同时,如果从请求中获取到相同的令牌,并且会话中存在该令牌,则拒绝。唯一的区别是我们不需要提前存储令牌,而是在需要时存储,比如在POST请求中。

0