I have a controller like this:
@Controller
public class HomeController {
@RequestMapping(value = "/update", method = RequestMethod.POST)
public String update(@RequestParam("user") User user, ModelMap model){
SaveUserToDatabase(user);
return "index";
}
@ModelAttribute("user")
String getUser() {
return LoadCurrentUserFromDataBase();
}
}
In short, my views would render user
in almost every actions in HomeController
,
but I don't want to code:
model.addAttribute("user", LoadCurrentUserFromDataBase())
in every actions, instead I'm seeking a way like @ModelAttribute
to expose user
to all my views.
However, according to the docs, @ModelAttribute
methods in a controller are invoked before @RequestMapping
methods, within the same controller.
As to my code, getUser
is called before update
, but i'd like to get the updated user.
Is there a way to expose the user
attribute after actions without explicitly call model.addAttribute
in every actions?
Each time you do a POST
, make a redirection. That way, your POST
method will only be responsible for updating the data, and the updated data will be loaded by the target controller.
So in this case, the update()
method would redirect to another controller which would call the getUser()
method before its GET
method.
The Post / redirect / GET solution is valid if it works for you.
However, I had a similar situation where I had model attributes that needed to be written by all my controllers, after request processing (tracking information mostly). What I did was to register a custom interface (e.g. AdditionalModelDataSupplier
), which I apply to all controllers that need to provide additional data. The interface would have a method like this:
void provideAdditionalData(Model model, HttpServletRequest request);
Now, I wrote an interceptor that in the postHandle
method checks the Controller bean for this interface and calls this method:
@Override
public void postHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler,
final ModelAndView modelAndView) throws Exception {
AdditionalModelDataSupplier modelDataSupplier = findAdditionalModelDataSupplier(handler);
if (modelDataSupplier != null) {
final ModelMap modelMap = modelAndView.getModelMap();
final Model targetModel;
if (modelMap instanceof Model) {
targetModel = (Model) modelMap;
} else {
// the modelmap doesn't implement model, so we need to provide a wrapper view
targetModel = new ForwardingModel(modelMap);
}
modelDataSupplier.provideAdditionalData(targetModel, request);
}
}
@Nullable
private static AdditionalModelDataSupplier findAdditionalModelDataSupplier(final Object handler) {
if (handler instanceof AdditionalModelDataSupplier) {
return (AdditionalModelDataSupplier) handler;
}
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Object bean = handlerMethod.getBean();
if (bean instanceof AdditionalModelDataSupplier) {
return (AdditionalModelDataSupplier) bean;
}
}
return null;
}
(the ForwardingModel
class mentioned above is trivial to create, it just delegates everything to the ModelMap
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With