Why doesn't DispatcherServlet invoke my HandlerInterceptor? - java

I know that in JavaEE, filters can intercept any request to a servlet. But Interceptors in Spring MVC are not exactly the same. If you look at the diagram below, you will see that Interceptors come after Dispatcher Servlet.
Let me give you an example before I ask my question.
I have a controller, which has 2 methods in it that are mapped to two different requests. One accepts GET requests and other accepts POST requests. Now if I add an interceptor in my web application, that interceptor will sit before Controller. Meaning that before controller method is hit, first a request will hit my interceptor's preHandle method.
Now say that in my app, two controllers methods look like this:
#Controller
public class myController{
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String test1(){
return "abc";
}
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String test1(){
return "xyz";
}
And lets say I have a simple interceptor like this:
public class URLInterceptors extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("REQUESTED SERVLET PATH IS: " + request.getServletPath());
return true;
}
}
Now, if I make a GET request to /test, my interceptor is hit and it prints the servlet path, but when I make a GET request to /login, I know it will fail because my method that handles /login mapping accepts only POST requests, however before it throws '405 Request method 'GET' not supported' error, it should at least hit first my interceptor? It doesn't. I I don't want to change POST to GET. So the question is why?

Part of this is explained in
Why does Spring MVC respond with a 404 and report "No mapping found for HTTP request with URI [...] in DispatcherServlet"?
In summary, the DispatcherServlet attempts to find an appropriate handler for your request by using a HandlerMapping (see your graphic). These handlers are actually adapters that wrap the actual handler method (a #RequestMapping annotated method in this case) with the interceptors you've registered. If this handler is found, then the DispatcherServlet can proceed, invoke interceptors, and, if required, invoke your handler method.
In your case, because your #RequestMapping is restricted to POST requests and your request is a GET, the DispatcherServlet fails to find an appropriate handler and therefore returns an error before it's had a chance to invoke any interceptors.
Note that the javadoc states
A HandlerInterceptor gets called before the appropriate HandlerAdapter
triggers the execution of the handler itself.
but your DispatcherServlet never found a handler to begin with.
You might want to consider using a Servlet Filter instead.

Related

405 Method not allowed in Spring Boot and Ajax

Hi I am having request mapping like this
#RequestMapping(value = "/pendodnp/{visitorId}/{content}")
public ResponseEntity<Object> setPendoDNP(#PathVariable String visitorId, #PathVariable String content, final HttpSession session, final HttpServletRequest request) throws PendoException {
LOGGER.info("### pendodnp");
_splitService.updateDNP(visitorId, content);
return ResponseEntity.ok().body(content);
}
but when I hit this URL from an angular function, it gives "405 method not allowed" error.
$http.get("pendodnp/"+visitorId+"/"+dnpValue, JSON.stringify(dnpValue))
.success(function(response) {
Here is screenshot of how the request is going, can someone tell me what i am missing here?
You haven't specified which HTTP method (GET, POST, PUT, DELETE, etc) the mapping should handle. To do that either use #GetMapping or change your #RequestMapping so it includes the method parameter.
#GetMapping("/pendodnp/{visitorId}/{content}")
Or
import static org.springframework.web.bind.annotation.RequestMethod.GET;
...
#RequestMapping(method = GET, path = "/pendodnp/{visitorId}/{content}")
Using #RequestMapping without a method parameter is usually only done at the class level, not individual methods. #GetMapping (or #PostMapping, #PutMapping, etc) are more common on controller methods.

Spring GET and POST mappings in separate classes

We are attempting to separate our GET and POST #RequestMapping methods in our Spring controllers into two separate classes.
The reason is that we want the POST calls to have an exception handler which serializes responses as JSON payloads, while the GET calls should be bubbled up through the Spring stack.
However, when we attempt to separate these, we receive errors suggesting that the mappings are being registered twice:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping#0' defined in OSGi resource[classpath:/dispatcher-servlet.xml|bnd.id=21|bnd.sym=com.company.application]: Initialization of bean failed; nested exception is java.lang.IllegalStateException: Cannot map handler 'settingsController' to URL path [/settings.html]: There is already handler of type [class com.company.application.controller.SettingsModelAndViewController$$EnhancerBySpringCGLIB$$54324809] mapped.
Is it possible to separate GET and POST request mappings into two different classes? Basically we want (excuse the pseudo-naming conventions):
class PostHandler {
#ExceptionHandler
public void handleException(...) { // Serialize to JSON }
#RequestMapping(value = "/settings.html", method = RequestMethod.POST)
public void saveChanges() { ... }
}
class GetHandler {
#RequestMapping(value = "/settings.html", method = RequestMethod.GET)
public ModelAndView getSettings() { ... }
}
But currently are unable to find a way around Spring's double-mapping complaints.
Looking at the design and code for DispatcherServlet that routes a URL to a Controller (actually to a HandlerAdapter interface), it certainly seems possible, but not easy and not by existing HandlerMapping classes (look at existing classes implementing this interface at https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/HandlerMapping.html). You would have to write a HandlerMapping class (existing handler mappings' code can guide you with this), which would return the right controller based on the URL and HTTP method and configure it (this link should help with HandlerMapping configuration: http://www.baeldung.com/spring-handler-mappings). None of the current HandlerMapping classes look at the HTTP method when choosing a controller for a URL.
You may be able to tweak the GET and POST request mapping, by adding let's say a wildcard to one of the HTTP method handlers (e.g. How do I set priority on Spring MVC mapping?), but not by using the exact same URL in 2 different controllers.

Spring MVC custom authorization/security for controller methods

Looking to create a custom implementation to authorize requests.
I am evaluating options to avoid using annotations on every method in the controller.
Instead, I am exploring the possibility centralizing this feature via a filter that checks if the logged in user has the required permission for the URL
We are using Spring 3.2.5.RELEASE
I intend to create a database table that has a mapping between a permission and the relevant URL.
I am looking for a way to get the request mapping information for the current URL.
For E-g :
In my database, I have:
URL=/view/{id} , permission=VIEW_USER
If the current URL is :
/app/user/view/1
, a method annotated with
#RequestMapping(value = "/view/{id}", method = RequestMethod.GET)
will be invoked. But before this happens, I need to verify if the logged in user has the permission to view user details.
In my filter, I can get the current URL (/app/user/view/1) , how do I get the corresponding mapping (/view/{id}) ? Is there a mechanism to match a URL to its corresponding MVC request mapping ?
I have looked/am looking at related posts on SO and also looked at Spring code but am yet to find a way.
If you want to do it that way, you could register MVC interceptor instead of servlet filter.
Create a class that extends HandlerInterceptorAdapter and in preHandle method you will have access to controller's method and it's annotation. Prehandle method of your interceptor could look something like this:
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod) handler;
if (method.getMethod().isAnnotationPresent(RequestMapping.class)) {
RequestMapping rqm = method.getMethodAnnotation(RequestMapping.class);
String[] urlMappings = rqm.value();
//do security logic
}
}
...
}
Then you need to register the interceptor. If you use xml config it's done like this:
<mvc:interceptors>
<bean class="com.example.MySecurityInterceptor" />
...
</mvc:interceptors>
Please note that your approach will be difficult, you'll need to handle all the request mapping cases that spring supports. For example, #RequestMapping that's annotated on class level. Or #RequestMapping annotated on parent class of the controller etc..

RestEasy custom action on every request

I would like to invoke some custom method when a REST call has finished, looking up annotations on the originating method and the generated response.
I know you can use the PostProcessInterceptor or MessageBodyWriterInterceptor for this task but they do not get invoked in case of an exception.
My current solution is such that every method throws a special exception which is then handled by a custom ExceptionMapper, but there I have no information about the original request and where it came from.
Is there a global wide handler you can bind to in order to get the information about the original request in case of an exception?
And yes I know about this question: RestEasy Post Process Interceptor chain not traversed when response created by ExceptionMapper
To answer my own question.
One can inject the original request into the ExceptionMapper and react or perform a custom action accordingly.
#Provider
public class MyExceptionMapper implements ExceptionMapper<Throwable> {
#Context
private HttpServletRequest request;
#Override
public Response toResponse(Throwable exception)
{
// trigger event
triggerOnExceptionEvent(request, exception);
}
...
}

How is used #RequestAttribute and #ModelAttribute annotation in this Spring MVC showcase example?

I am pretty new in Spring MVC.
In this period I am studying the Spring MVC showcase example downlodable from STS dashboard.
I am having some problems understanding how Custom Resolvable Web Arguments are handled in this example.
In practice I have the following situation:
In my home.jsp view I have the following link:
<a id="customArg" class="textLink" href="<c:url value="/data/custom" />">Custom</a>
This link generate an HTTP Request towards the URL: "/data/custom"
The controller class that contains the method that handles this request has the following code:
#Controller
public class CustomArgumentController {
#ModelAttribute
void beforeInvokingHandlerMethod(HttpServletRequest request) {
request.setAttribute("foo", "bar");
}
#RequestMapping(value="/data/custom", method=RequestMethod.GET)
public #ResponseBody String custom(#RequestAttribute("foo") String foo) {
return "Got 'foo' request attribute value '" + foo + "'";
}
}
The method that handles this HTTP Request is custom()
So when the previous link is clicked the HTTP Request is handled by the custom method...
I am having problems understanding what the #RequestAttribute annotation.
I think that, in this case, it binds the request attribute named foo to a new String foo variable.
But... where is this attribute taken from? Is this variable taken by Spring?
Ok...my idea is that this request attribute is taken from a HttpServletRequest object...
I think this because, in this class, I have also have the beforeInvokingHandlerMethod() method that have a speacking name...so it seems that this method seta an attribute, that have name=foo and value=bar, inside an HttpServletRequest object...and then so the custom() method can use this value...
In fact my output is:
Got 'foo' request attribute value 'bar'
Why is the beforeInvokingHandlerMethod() called before the custom() method?
And why is the beforeInvokingHandlerMethod() annoted by #ModelAttribute annotation? What does this case mean?
You are correct in assumption of #RequestAttribute, it need not be set in beforeInvokingHandlerMethod. Assume you have a method mapped to /data/init which forwards request to /data/custom. In this case request attribute can be set in init method also.
Why the beforeInvokingHandlerMethod() is called before the custom() method?
And why the beforeInvokingHandlerMethod() is annoted by #ModelAttribute annotation? what means in this case?
you will get the reason here
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-ann-modelattrib-methods
An #ModelAttribute on a method indicates the purpose of that method is to add one or more model attributes. Such methods support the same argument types as #RequestMapping methods but cannot be mapped directly to requests. Instead #ModelAttribute methods in a controller are invoked before #RequestMapping methods, within the same controller.

Categories