views:

330

answers:

1

hi,

I'm currently migrating a project that is using Spring MVC without annotations to Spring MVC with annotations. This is causing less problems than expected but I did come across one issue.

In my project I have set up an access mechanisme. Whether or not a User has access to a certain view depends on more than just the role of the User (e.g. it also depends on the status of the entity, the mode (view/edit), ...). To address this I had created an abstract parent controller which has a method hasAccess. This method calls also other methods like getAllowedEditStatuses which are here and there overridden by the child controllers.

The hasAccess method gets called from the showForm method (below code was minimized for your readability):

@Override
protected ModelAndView showForm(final HttpServletRequest request,
                                final HttpServletResponse response,
                                final BindException errors) throws Exception {
    Integer id = Integer.valueOf(request.getParameter("ID"));
    Project project = this.getProject(id);
    if (!this.hasAccess(project, this.getActiveUser())) {
        return new ModelAndView("errorNoAccess", "code", project != null ? project.getCode() : null);
    }
    return this.showForm(request, response, project, errors);
}

So, if the User has no access to the view then he gets redirected to an error page.

Now the 'pickle': how to set this up when using annotations. There no longer is a showForm or other method that is always called by the framework.
My (and maybe your) first thought was: simply call this method from within each controller before going to the view. This would of course work but I was hoping for a nicer, more generic solution (less code duplication). The only other solution I could think of is preceeding the hasAccess method with the @ModelAttribute annotation but this feels a lot like raping the framework :-).

So, does anyone have a (better) idea?

thanks, Stijn

+3  A: 

A nicer solution would be the use a HandlerInterceptor, which each request "passes through" on the way to the controller. This is would potentially be a nicer solution that your iriginal subclass-based one.

You would want to implement the preHandle method on the interceptor interface. The downside is that the interface isn't as nice as using annotated controllers, but it's a trivial matter for your interceptor to forward the request to an error page.

skaffman
Some of the required information to determine if a User has access is 'stored' inside the (child) controllers. Do I have a reference to this controller inside the HandlerInterceptor? + Do you mean this solution can't be used when working with annotated controllers? Tx.
TheStijn
how is info "stored inside" a controller? do you mean that the logic is in the controller itself? I agree with skaffman that this sounds like cross-cutting info (i.e., applies to more than just one controller) and an interceptor is a good idea
matt b
'stored inside' means that the child controllers can override methods like getAllowedEditStatuses or isAdminEditAllowed, ... . I do not dislike the interceptor idea, as long as can still access this information inside the controller that is called? Tx.
TheStijn
@TheStijn: Refactor your code so that the logic you're referring to is in an object that can be equally wired into the controller, or into the interceptor. Both are just beans, so you can wire them up any way you choose.
skaffman
It took a while before I got around to the practical implementation but it works as promised. Tx!
TheStijn