Struts 2 - Post/Redirect/Get
Redisplaying a Form
Page designs aren't always simple
Struts 2 is a popular MVC framework for Java-based web applications. Its basic workflow is displaying a form for editing, processing a submitted form, and displaying the results but even something this straightforward requires some bespoke code.
Consider the screenshot of a simple form below. A viewer Action to display this will read the appropriate record from a database and the JSP page will construct the form to edit it. When a form is successfully submitted, the database is updated, and the browser can redirect to the viewer Action, which re-reads the database and displays an updated form. If the form submission fails, the browser redirects to the viewer Action, which redisplays a form based on the database record, not what the user submitted. This can frustrate users to the point where they refuse to use the application.
Examining the solution
The interceptors for preserving forms described in Post/Redirect/Get
would appear to solve this problem but it can go wrong. It injects the form into the viewer Action before the
execute function runs, which must realise it's received a form it shouldn't replace. That's more
bespoke code for what's supposed to be straightforward workflow. The interceptor could inject the form after
invocation.invoke() line, so the viewer Action
execute function is already done by
that point but that means the Action wasted its time reading the database.
The problem is constructing the forms is particular to the viewer Actions, and can't be inherently known by the Struts 2 framework. This suggests a finer Inversion of Control design where the viewer Action supplies code for each form and an interceptor calls each except for the injected form. This is starting to sound like over-engineering and hard to read code.
Perhaps the problem should be ignored and the form injected after the viewer Action's
but unnecessary database strain should be avoided. Database strain can be mitigated with caching but the
tradeoffs of caching are peculiar to each application and can't be required by the framework.
Continued in Use ModelDriven, which explains reducing checks for injected forms to one simple if statement per form.