I am new to Spring MVC with annotation and I am just trying a basic example for it. But I am receiving HTTP Stats 404 error. My files are as below :
It is a maven project. Request mapping is the part of controller which is used and jsp page only list.jsp to show that message.
errors-HTTP Status 404 - /test1/view/list.jsp
public class ADConfiguration extends WebMvcConfigurerAdapter{
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
System.out.println("hjshjshdjkah");
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/view/");
viewResolver.setSuffix(".jsp");
registry.viewResolver(viewResolver);
}
#RequestMapping(value = "/list", method = RequestMethod.GET)
public ModelAndView list() {
System.out.println("####################Controller part methods###");
String message = "HELLO SPRING MVC HOW R U";
return new ModelAndView("list", "message", message);
}
public class ADInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { ADConfiguration.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected Filter[] getServletFilters() {
Filter [] singleton = { new com.admin.configuration.CORSFilter() };
return singleton;
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
/*// TODO Auto-generated method stub
super.onStartup(servletContext);*/
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(ADConfiguration.class);
ctx.setServletContext(servletContext);
ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
}
}
It can't find the right response path.Not you're annotation wrong
I want to post http://localhost:8080/TestSpringMVCAndStuff/hi/zzz?input=abcdef&crap=1234567 to a /hi/* address.
However, I keep getting 404 error.
Is there a way to make this work?
WebAppInitializer
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(WebAppConfiguration.class);
ctx.setServletContext(container);
{
ServletRegistration.Dynamic servlet = container.addServlet(
"dispatcherHi", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/hi/*");
}
}
}
AnotherController
#Controller
#RequestMapping("/hi/*")
public class AnotherController {
#Autowired(required=false)
#RequestMapping(method = RequestMethod.POST)
public void processRequest(HttpServletRequest request, HttpServletResponse response) {
try{
response.getOutputStream().write("hello world!".getBytes());
}
catch(Exception e){
e.printStackTrace();
}
}
}
WebAppConfiguration
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.test.springmvc")
public class WebAppConfiguration extends WebMvcConfigurerAdapter {
/*
* Configure View Resolver
*/
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
/*
* Configure MessageSource to provide internationalized messages
*
*/
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
/*
* Configure ResourceHandlers to serve static resources like CSS/ Javascript etc...
*
*/
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
}
}
In this Context Initializer servlet mapping is /hi/* so each and every request to the server will be like http://localhost:8080/TestSpringMVCAndStuff/hi
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(WebAppConfiguration.class);
ctx.setServletContext(container);
{
ServletRegistration.Dynamic servlet = container.addServlet(
"dispatcherHi", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/hi/*");
}
}
}
so that there is no need of #RequestMapping("/hi/*") this because /hi is already appended in context path so after hi/ only need a request Mapping #RequestMapping( value="/zzz")
#Controller
#RequestMapping("/**")
public class AnotherController {
#RequestMapping(value="/zzz",method = RequestMethod.POST)
#ResponseBody
public String processRequest(HttpServletRequest request, HttpServletResponse response) {
String result="";
try{
result="hello world";
}
catch(Exception e){
e.printStackTrace();
}
return result;
}
}
inCase he change servlet Mapping like this means servlet.addMapping("/") he should Map Request for /hi in Controller and futher request also
As you know, in XML, the way to configure this is:
<error-page>
<error-code>404</error-code>
<location>/my-custom-page-not-found.html</location>
</error-page>
But I haven't found a way to do it in Java config. The first way I tried was:
#RequestMapping(value = "/**")
public String Error(){
return "error";
}
And it appeared to work, but it has conflicts retrieving the resources.
Is there a way to do it?
In Spring Framework, there are number of ways of handing exceptions (and particularly 404 error). Here is a documentation link.
First, you can still use error-page tag in web.xml, and customize error page. Here is an example.
Second, you can use one #ExceptionHandler for all controllers, like this:
#ControllerAdvice
public class ControllerAdvisor {
#ExceptionHandler(NoHandlerFoundException.class)
public String handle(Exception ex) {
return "404";//this is view name
}
}
For this to work, set throwExceptionIfNoHandlerFound property to true for DispatcherServlet in web.xml:
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
You can also pass some objects to error view, see javadoc for this.
The most clean solution since spring 4.2 RC3 is using the new createDispatcherServlet hook within the class extending AbstractDispatcherServletInitializer (or indirectly through extending AbstractAnnotationConfigDispatcherServletInitializer) like this:
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
/* ... */
#Override
protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
final DispatcherServlet dispatcherServlet = super.createDispatcherServlet(servletAppContext);
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
return dispatcherServlet;
}
}
Then you can use a global #ControllerAdvice (a class that is annotated with #ControllerAdvice) as described in the reference docs. Within the advice you can handle the NoHandlerFoundException with an #ExceptionHandler as described here.
This could look something like this:
#ControllerAdvice
public class NoHandlerFoundControllerAdvice {
#ExceptionHandler(NoHandlerFoundException.class)
public ResponseEntity<String> handleNoHandlerFoundException(NoHandlerFoundException ex) {
// prepare responseEntity
return responseEntity;
}
}
Simple answer for 100% free xml:
Set properties for DispatcherServlet
public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { RootConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {AppConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
boolean done = registration.setInitParameter("throwExceptionIfNoHandlerFound", "true"); // -> true
if(!done) throw new RuntimeException();
}
}
Create #ControllerAdvice:
#ControllerAdvice
public class AdviceController {
#ExceptionHandler(NoHandlerFoundException.class)
public String handle(Exception ex) {
return "redirect:/404";
}
#RequestMapping(value = {"/404"}, method = RequestMethod.GET)
public String NotFoudPage() {
return "404";
}
}
Use code-based Servlet container initialization as described in the doc and override registerDispatcherServlet method to set throwExceptionIfNoHandlerFound property to true:
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected void registerDispatcherServlet(ServletContext servletContext) {
String servletName = getServletName();
Assert.hasLength(servletName, "getServletName() may not return empty or null");
WebApplicationContext servletAppContext = createServletApplicationContext();
Assert.notNull(servletAppContext,
"createServletApplicationContext() did not return an application " +
"context for servlet [" + servletName + "]");
DispatcherServlet dispatcherServlet = new DispatcherServlet(servletAppContext);
// throw NoHandlerFoundException to Controller
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
Assert.notNull(registration,
"Failed to register servlet with name '" + servletName + "'." +
"Check if there is another servlet registered under the same name.");
registration.setLoadOnStartup(1);
registration.addMapping(getServletMappings());
registration.setAsyncSupported(isAsyncSupported());
Filter[] filters = getServletFilters();
if (!ObjectUtils.isEmpty(filters)) {
for (Filter filter : filters) {
registerServletFilter(servletContext, filter);
}
}
customizeRegistration(registration);
}
}
Then create an exception handler:
#ControllerAdvice
public class ExceptionHandlerController {
#ExceptionHandler(Exception.class)
public String handleException(Exception e) {
return "404";// view name for 404 error
}
}
Don't forget about using #EnableWebMvc annotation on your Spring configuration file:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages= {"org.project.etc"})
public class WebConfig extends WebMvcConfigurerAdapter {
...
}
In your web configuration class,
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter
Declare a bean as follows,
#Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
#Override
public void customize(ConfigurableEmbeddedServletContainer container)
{
ErrorPage error401Page = new ErrorPage(HttpStatus.UNAUTHORIZED, "/401.html");
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/404.html");
ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/500.html");
container.addErrorPages(error401Page,error404Page,error500Page);
}
};
}
Add the mentioned html files(401.html .etc) to /src/main/resources/static/ folder.
Hope this helps
For Java config there is a method setThrowExceptionIfNoHandlerFound(boolean throwExceptionIfNoHandlerFound) in DispatcherServlet. By settting it to true I guess you are doing same thing
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
then you can can this NoHandlerFoundException.class in controller advice as stated in above answer
it will be like something
public class WebXml implements WebApplicationInitializer{
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext context = getContext();
servletContext.addListener(new ContextLoaderListener(context));
DispatcherServlet dp = new DispatcherServlet(context);
dp.setThrowExceptionIfNoHandlerFound(true);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", dp);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping(MAPPING_URL);
}
}
The solution proposed in comments above really works:
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration)
{
registration.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}
A solution for Spring 5 and Thymeleaf 3.
In MyWebInitializer, enable exception throwing with setThrowExceptionIfNoHandlerFound(). We need to do casting to DispatcherServlet.
#Configuration
public class MyWebInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
...
#Override
protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
var dispatcher = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
dispatcher.setThrowExceptionIfNoHandlerFound(true);
return dispatcher;
}
}
Create a controller advice with #ControllerAdvice and add error message to the ModealAndView.
#ControllerAdvice
public class ControllerAdvisor {
#ExceptionHandler(NoHandlerFoundException.class)
public ModelAndView handle(Exception ex) {
var mv = new ModelAndView();
mv.addObject("message", ex.getMessage());
mv.setViewName("error/404");
return mv;
}
}
Create 404 error template, which displays the error message. Based on my configuration, the file is src/main/resources/templates/error/404.html.
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>Resource not found</title>
</head>
<body>
<h2>404 - resource not found</h2>
<p>
<span th:text="${message}" th:remove="tag"></span>
</p>
</body>
</html>
For completeness, I add the Thymeleaf resolver configuration. We configure the Thymeleaf templates to be in templates directory on the classpath.
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {
#Autowired
private ApplicationContext applicationContext;
...
#Bean
public SpringResourceTemplateResolver templateResolver() {
var templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("classpath:/templates/");
templateResolver.setSuffix(".html");
return templateResolver;
}
...
}
In springboot it is even simplier. Because of Spring autoconfiguration stuff, spring creates a bean org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties. This class is annotated with #ConfigurationProperties(prefix = "spring.mvc") and therefore it will seek for properties with spring.mvc prefix.
Part from javadoc:
Annotation for externalized configuration. Add this to a class definition or a
* #Bean method in a #Configuration class if you want to bind and validate
* some external Properties (e.g. from a .properties file).
You just have to add to your i.e. application.properties file following properties:
spring.mvc.throwExceptionIfNoHandlerFound=true
spring.resources.add-mappings=false //this is for spring so it won't return default handler for resources that not exist
and add exception resolver as follows:
#ControllerAdvice
public class ExceptionResponseStatusHandler {
#ExceptionHandler(NoHandlerFoundException.class)
public ModelAndView handle404() {
var out = new ModelAndView();
out.setViewName("404");//you must have view named i.e. 404.html
return out;
}
}
I want to handle 404 page not found exception in my Spring MVC web app, I'm using SPRING 4.2.5.RELEASE, I had read several question regarding this topic but the similar questions are using a different spring java configuration.
I have a Global Exception Handler Controller class that have all my Exceptions, this class works fine but I can't handle a 404 page not found exception.
This is the approach that I take following a tutorial
1) I created a class named ResourceNotFoundException that extends from RuntimeException and I putted this annotation over the class definition #ResponseStatus(HttpStatus.NOT_FOUND)
like this:
#ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
}
2) I created this method in my exception's controller class
#ExceptionHandler(ResourceNotFoundException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public String handleResourceNotFoundException() {
return "notFoundJSPPage";
}
But still when I put a URL that doesn't exist I get this error "No mapping found for HTTP request with URI"
The questions that I had read said that I need to enable to true an option for the Dispatcher but since my configuration it's different from the other questions and I don't have a Web.xml I couldn't apply that.
Here it's my Config.java
#EnableWebMvc
#Configuration
#ComponentScan({"config", "controllers"})
public class ConfigMVC extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/WEB-INF/resources/");
}
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
}
Here is my WebInitializer
public class WebInicializar implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(ConfigMVC.class);
ctx.setServletContext(servletContext);
Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
}
Here is my Global Exception Handler Controller
#ControllerAdvice
public class GlobalExceptionHandlerController {
#ExceptionHandler(value = NullPointerException.class)
public String handleNullPointerException(Exception e) {
System.out.println("A null pointer exception ocurred " + e);
return "nullpointerExceptionPage";
}
#ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler(value = Exception.class)
public String handleAllException(Exception e) {
System.out.println("A unknow Exception Ocurred: " + e);
return "unknowExceptionPage";
}
#ExceptionHandler(ResourceNotFoundException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public String handleResourceNotFoundException() {
return "notFoundJSPPage";
}
}
And the class I created that extends Runtime Exception
#ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException{
}
I solved the problem by putting this line in my onStartup method in the WebApplicationInitializer.class
this it's the line I add servlet.setInitParameter("throwExceptionIfNoHandlerFound", "true");
this is how it looks the complete method with the new line I added
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(ConfigMVC.class);
ctx.setServletContext(servletContext);
Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
servlet.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}
Then I created this controller method in my GlobalExceptionHandlerController.class
#ExceptionHandler(NoHandlerFoundException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public String handle(NoHandlerFoundException ex) {
return "my404Page";
}
and that solved my problem I deleted the handleResourceNotFoundException controller method in my GlobalExceptionHandlerController.class since it wasn't necessary and also I deleted the exception class ResourceNotFoundException.class that I created
You can also extend AbstractAnnotationConfigDispatcherServletInitializer and override this method:
#Override
protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
final DispatcherServlet dispatcherServlet = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
return dispatcherServlet;
}
OR this one:
#Override
public void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}
And finally in your ControlerAdvice use this:
#ExceptionHandler(NoHandlerFoundException.class)
public String error404(Exception ex) {
return new ModelAndView("404");
}
Add following code in any controller and create a 404 page
#GetMapping("/*")
public String handle() {
return "404";
}
I found that the answer by zygimantus didnt work for some reason, so if you also have the same problem , then instead of declaring an "#ExceptionHandler", add one of these to a "#Configuration" class instead. I put mine in my WebMvcConfigurerAdapter
#Bean
public HandlerExceptionResolver handlerExceptionResolver(){
HandlerExceptionResolver myResolver = new HandlerExceptionResolver(){
#Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) {
//return your 404 page
ModelAndView mav = new ModelAndView("404page");
mav.addObject("error", exception);
return mav;
}
};
return myResolver;
}
But make sure you also follow the rest of zygimantus ie
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
I'm trying to implement what Bryan Hansen taught in his spring mvc video serie for internationalization; I'm writing the same code as e does but mine does not work properly and I'm getting the following error message :
No message found under code 'student.name' for locale 'en_US'
my startup class is as follow :
public class Startup implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
//get the context :
WebApplicationContext context = this.getContext();
//creates a listener :
ContextLoaderListener listener = new ContextLoaderListener(context);
servletContext.addListener(listener);
//register as servlet :
ServletRegistration.Dynamic dispatcherServlet = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
dispatcherServlet.setLoadOnStartup(1);
dispatcherServlet.addMapping("/");
}
private WebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(WebConfig.class);
return context;
}
}
and my web config class is as follow :
#Configuration
#ComponentScan(basePackages = "ga.shahab.controllers")
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry resource) {
resource.addResourceHandler("/res/**").addResourceLocations("/resources/");
resource.addResourceHandler("/app/*.js").addResourceLocations("/resources/app/");
}
// START : Internationalization I18n
#Bean
public MessageSource MessageSource() {
// ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
#Bean
public LocaleResolver localResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(Locale.ENGLISH);
return localeResolver;
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
LocaleChangeInterceptor changeInterceptor = new LocaleChangeInterceptor();
changeInterceptor.setParamName("language");
registry.addInterceptor(changeInterceptor);
}
// END : Internationalization I18n
#Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/Views/");
resolver.setSuffix(".jsp");
return resolver;
}
}
I'm using spring messages like this :
<spring:message code="student.name"></spring:message>
and the structure of my project is as follow :
1.src/main/java
2.src/main/resources
my internationalization files are in the second folder( resources )
and finally my messages file includes just one line of code :
student.name=Name
but my project does not work for internationalization.
what's wrong with my sample ?!