Reputation: 31
I am currently trying to create a Controller to handle all unknown URLs globally. So what I did was create a controller similar to the one below
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("/**")
public class UnknownUrlController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public String getError404() {
return "/error404";
}
}
My intention was to ensure that the default servlet which just returns a String "Not Found" to the browser was not invoked. This strategy worked since all unknown URL was handled by this Controller.
However the issue was that the controller was also invoked for all my static resources (images, js and css files) I had configured in my WebMvcConfigurerAdapter as follows
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/img/**").addResourceLocations("/img/");
}
so instead of my static files served to the browser, my error pages were served in its place. Although I later understood that controllers mappings take precedence over static resources from this answer . This is the reason I would like to know how to exclude my resources url mappings from being handled by this controller so it would only be concerned with trapping the unknown URLs.
Before proceeding with this strategy I had tried some other things that I could not get to work (I am probably missing something)
All my configuration are Java based without any xml files and would prefer to keep it that way.
Upvotes: 3
Views: 6645
Reputation: 31
Finally found out how to fix the issue. The solution was to remove the default servlet handler in my Java configuration. In my Java configuration class (the one that extends WebMvcConfigurerAdapter) I had earlier enabled the default Servlet as follows
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
This configures a DefaultServletHttpRequestHandler with a URL mapping of /** as explained in this section of the Spring mvc documentation. This was the reason why no exception was thrown when no handler was found for a URL even though I had set the throwExceptionIfNoHandlerFound
of my DispatcherServlet
to true as I stated in my question.
After removing the configuration from my class. I created a global Exception handler class and added a method for NoHandlerFoundException
cases. This is the exception that is thrown when no Controller handler is found for a URL mapping. The sample code is shown below. This is also well explained in this section of the spring mvc documentation.
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
@RequestMapping( value = {"/*","/**"},method = RequestMethod.GET)
public String handle(HttpServletRequest request, NoHandlerFoundException ex) {
return "error-404";
}
}
Upvotes: 0
Reputation: 2693
Spring Boot 1.4+ supports declarative error pages based on HTML status code.
Upvotes: 1
Reputation: 1615
There is a better way to write custom error handlers in Spring. See this below:
@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public String handleResourceNotFoundException() {
return "notfound";
}
It as a nice blog entry about exception handlers in Spring MVC.
If the dispatcherServlet does not throw an exception in the case of 404, then you should turn it on using the setThrowExceptionIfNoHandlerFound() method of the DispatcherServlet.
Here you can find more information about, how to turn it on
Upvotes: 2