Tránh re-submit form trong Spring bằng cách sử Flash Attribute

Kể từ phiên bản Spring MVC 3.1 đã được bổ sung 1 thuộc tính rất hữu ích đó chính là Flash attribute nhằm giải quyết các vấn đề về POST/Redirect/GET pattern.

Trong một ứng dụng Web thông thường, với mỗi một form submitted POST dữ liệu lên server, Spring controller sẽ lấy dữ liệu request từ form gửi lên, sau đó tiến hành các thao tác thêm/sửa/xóa. Một khi xử lý dữ liệu form thành công hay thất bại đều sẽ trả về 1 trang thông báo. Trong cách tiếp cận pattern POST/Forward/GET này sẽ làm nảy sinh ra một số vấn đề vể việc re-submit khi người dùng nhấn F5 liên tục.

Đề giải quyết vấn đề này. pattern POST/Redirect/GET được sử dụng trong ứng dụng.Khi đó mỗi khi người dùng submit 1 form POST lên thành công, ta sẽ redirect sang một trang thông báo thành công khác. Browser sẽ tạo mới 1 request GET để load lên trang. Vì vậy việc refresh trang (F5) sẽ chỉ đơn giản là request load lại trang chứ không phải là submit lại form.

Screenshot from 2016-11-30 00:30:45.png

Trong cách tiếp cận này, trông mọi thứ có vẻ hoàn hảo, giải quyết được các vấn đề về việc submit form nhiều lần, nhưng nó vướng phải một số vấn đề về việc lấy các dữ liệu attribute và parameter. Vì việc redirect sang một 1 request khác, dữ liệu lưu trữ trong 1 request trước đó sẽ bị mất, và không thể access được.

Flash attribute giúp khắc phục triệt để các hạn chế trên, Flash attribute cung cấp cho ta cách truyền các attribute từ request này sang request khác. Flash attribute sẽ lưu các dữ liệu tạm thời trong session, trước khi redirect, và được xóa ngay khi sau khi redirect.

spring-mvc-flash-map-manager.png

Để làm được điều này, Flash sử dụng 2 collections. FlashMap được sử dụng để tổ chức các thuộc tính. Trong khi FlashMapManager được sử dụng để lưu trữ, truy suắt và quản lý đối tượng FlashMap

Mối một request "input" flash map tạo ra, được lưu trữ flash attribute từ bất kỳ request kể trước. Request "output" của flash map được tạo và lưu trữ bất kỳ thông tin trên chính request hiện tại.

#Ví dụ một form submit đơn giản sử dụng Flash Atribute:

Book.java

public class Book {
	private String title;
	private String author;
    private BigDicimal price;

    // getter, setter methods

Controller:

@RequestMapping(value = "books/create", method = RequestMethod.POST)
   public String saveBook(@RequestParam String action, Model model, @Valid @ModelAttribute Book book,
			RedirectAttributes redirectAttributes) {
	redirectAttributes.addFlashAttribute("book",book);
    return "redirect:books/show";
@RequestMapping(value="books/show", method=RequestMethod.GET)
	public String showBook(@ModelAttribute("book") Book book) {
        // preview title groupbook.
		System.out.println("book title :" + book.getTitle());
		return "show_book";
	}

View - Form submit

<html>
<body>
	<h1>New groubook</h1>
	<form:form action="books/create" method="POST">
	<table>
		<tr>
			<td><form:label path="title">Title</form:label></td>
			<td><form:input path="title" /> </td>
		</tr>
		<tr>
			<td><form:label path="author">Lastname</form:label></td>
			<td><form:input path="author" /> </td>
		</tr>
       <form:form
    </body>
</html>