In the first part of this article (read it here) I tried to explain how to write simple Spring MVC controllers that could be intercepted (AOP) or used by DWR (AJAX calls) without adding any complexity. Some people asked about adding form controllers to the mix. In fact, the first article didn't cover them at all as Form controllers perform a very specific task (submit data) and, generally speaking, won't be the core of the MVC. But, without doubt, they will show sooner or later during development, and it can be useful to intercept calls.
The problems to handle form controllers (SimpleFormController for example) and AOP are more or less the same, just only aggravated by the fact that Spring deals with lots of work (binding, validation, views) internally. As nobody probably wants to loose this functionality (leaving implementing Controller out of question) some new approach has to be devised.
As always we are constraint by the final method declarations up in the hierarchy so extending the classes is not an option. The next idea would be the Decorator patter (see it described here), trying to add behaviour at runtime. Unfortunately, it won't be of help here as this pattern forces the code to implement the same public interface (not the Java interfaces) of the object and that poses the same problem as subclassing.
The idea of wrapping the object is good though. We just need to be able to intercept the handleRequest and the doSubmitAction methods and be able to forward the rest of the calls to the proxied object. An abstract class will take this task:
The problems to handle form controllers (SimpleFormController for example) and AOP are more or less the same, just only aggravated by the fact that Spring deals with lots of work (binding, validation, views) internally. As nobody probably wants to loose this functionality (leaving implementing Controller out of question) some new approach has to be devised.
As always we are constraint by the final method declarations up in the hierarchy so extending the classes is not an option. The next idea would be the Decorator patter (see it described here), trying to add behaviour at runtime. Unfortunately, it won't be of help here as this pattern forces the code to implement the same public interface (not the Java interfaces) of the object and that poses the same problem as subclassing.
The idea of wrapping the object is good though. We just need to be able to intercept the handleRequest and the doSubmitAction methods and be able to forward the rest of the calls to the proxied object. An abstract class will take this task:
public class AbstractAdvisableFormController extends AbstractRequestHandler {
private SimpleFormController formController = new SimpleFormController();
public ModelAndView handleRequest(
HttpServletRequest request, HttpServletResponse response) {
ModelAndView mv = formController.handleRequest(request, response);
if (mv.getViewName().equals(getSuccessView()))
doSubmitAction(mv.getModel().get(getCommandName()));
return mv;
}
public void doSubmitAction(Object command) {
return;
}
...
}
private SimpleFormController formController = new SimpleFormController();
public ModelAndView handleRequest(
HttpServletRequest request, HttpServletResponse response) {
ModelAndView mv = formController.handleRequest(request, response);
if (mv.getViewName().equals(getSuccessView()))
doSubmitAction(mv.getModel().get(getCommandName()));
return mv;
}
public void doSubmitAction(Object command) {
return;
}
...
}
The complete code is available here but the bread and butter is that. The handleRequest function will forward the call to the form controller and then process the result in case the original call returned a success. The doSubmitAction should be overridden by the concrete class later. An AOP form can be later defined as
@UrlMapping("form.action")
@AutowireToController(controllerBean="actionController")
public class FormAction extends AbstractAdvisableFormController {
@LogDebug(loggerClass=FormAction.class)
public ModelAndView handleRequest(
HttpServletRequest request, HttpServletResponse response) {
log.info("Do stuff");
return super.handleRequest(request, response);
}
@Override
public void doSubmitAction(Object command) {
log.info("Do more stuff");
}
}
@AutowireToController(controllerBean="actionController")
public class FormAction extends AbstractAdvisableFormController {
@LogDebug(loggerClass=FormAction.class)
public ModelAndView handleRequest(
HttpServletRequest request, HttpServletResponse response) {
log.info("Do stuff");
return super.handleRequest(request, response);
}
@Override
public void doSubmitAction(Object command) {
log.info("Do more stuff");
}
}
And there it is, a full SimpleFormController auto-mapped (wired to a MultiActionController!), that can be intercepted and supports all the configuration options as can be seen in the following code snippet:
<bean id="aForm" class="test.web.FormAction">
<property name="sessionForm" value="false" />
<property name="commandName" value="trivialObjectBean" />
<property name="commandClass" value="test.dwr.TrivialObject" />
<property name="validator" ref="trivialValidator" />
<property name="formView" value="trivialForm" />
<property name="successView" value="trivialSuccess" />
</bean>
<property name="sessionForm" value="false" />
<property name="commandName" value="trivialObjectBean" />
<property name="commandClass" value="test.dwr.TrivialObject" />
<property name="validator" ref="trivialValidator" />
<property name="formView" value="trivialForm" />
<property name="successView" value="trivialSuccess" />
</bean>

No hay comentarios:
Publicar un comentario en la entrada