unable to inject bean in simple spring mvc application - spring

I am trying a simple application in the spring mvc using annotations only. In my service class, I am unable to inject DAO class even though I have used relevant annotations.Please let me know what mistake I am doing. Below are my class definitions.
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { SpringRootConfig.class };
//return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { SpringWebConfiguration.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="com.emp.controller")
public class SpringWebConfiguration extends WebMvcConfigurerAdapter{
#Bean
public InternalResourceViewResolver jspViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="com.emp.svc,com.emp.dao")
public class SpringRootConfig {
}
package com.emp.svc;
import org.springframework.beans.factory.annotation.Autowired;
import com.emp.dao.LoginDAO;
public class LoginSvc {
#Autowired
private LoginDAO dao;
public boolean validateLogin(){
System.out.println("In the svc method");
return dao.validateLogin();
}
}
package com.emp.dao;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
#Repository
public class LoginDAO {
public boolean validateLogin(){
System.out.println("In the DAO method");
return true;
}
}
package com.emp.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.emp.forms.LoginForm;
import com.emp.svc.LoginSvc;
#Controller
public class LoginController {
#RequestMapping(value = {"/login"},method = RequestMethod.GET)
public ModelAndView launchLoginPage(){
ModelAndView model = new ModelAndView();
model.setViewName("login");
return model;
}
#RequestMapping(value = {"/welcome"},method = RequestMethod.GET)
public ModelAndView validateLogin(#ModelAttribute LoginForm form){
ModelAndView model = new ModelAndView();
LoginSvc svc = new LoginSvc();
if(svc.validateLogin()){
model.setViewName("welcome");
}
else
{
model.setViewName("login");
}
return model;
}
LoginSvc is called from controller. I am expecting that in LoginSvc, LoginDAO will be injected and hence the call to dao dao.validateLogin() will be successful. But what I am getting is Null pointer at dao.validateLogin(), indicating LoginDAO is not injected.
If you can let me know what I am missing, it will be great help.

Add #Service annotation in your LoginSvc class.
package com.emp.svc;
import org.springframework.beans.factory.annotation.Autowired;
import com.emp.dao.LoginDAO;
#Service
public class LoginSvc {
#Autowired
private LoginDAO dao;
public boolean validateLogin(){
System.out.println("In the svc method");
return dao.validateLogin();
}
}
And autowire LoginSvc inside your controller. As you are creating the object yourself invoking constructor of LoginSvc, spring will not provide you autowire candidate.
#Controller
public class LoginController {
#Autowired
private LoginSvc svc;
#RequestMapping(value = {"/login"},method = RequestMethod.GET)
public ModelAndView launchLoginPage(){
ModelAndView model = new ModelAndView();
model.setViewName("login");
return model;
}
#RequestMapping(value = {"/welcome"},method = RequestMethod.GET)
public ModelAndView validateLogin(#ModelAttribute LoginForm form){
ModelAndView model = new ModelAndView();
if(svc.validateLogin()) {
model.setViewName("welcome");
} else {
model.setViewName("login");
}
return model;
}
}

Related

SpringBoot handle #RequestParam exception

I have controller and method deleteFolder has #RequestParam:
#RestController
public class FolderController extends BaseController {
#DeleteMapping(path = Const.APIVersions.API_V1 + "/folders", params = "id")
public ResponseEntity<HttpStatus> deleteFolder(KeycloakAuthenticationToken authentication, #RequestParam Long id) throws EntityNotFoundException {
folderService.deleteFolder(id, authentication.getName());
return ResponseEntity.ok(HttpStatus.OK);
}
parent class:
public abstract class BaseController {
#ExceptionHandler({MissingServletRequestParameterException.class,
UnsatisfiedServletRequestParameterException.class, MethodArgumentTypeMismatchException.class,
IllegalArgumentException.class})
#ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<ErrorResponse> handleMissingServletRequestParameter(MissingServletRequestParameterException exception) {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), exception.getMessage()));
}
I want to handle exception, when required param is missing. But that exception handler don't want to catch that exception raised from deletFolder method.
Any others handlers works.
You have to create custom ConstraintValidator and catch ConstraintViolationException so your base controller becomes
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import javax.validation.*;
public abstract class BaseController {
#ExceptionHandler({ConstraintViolationException.class})
#ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<ErrorResponse> handlerFolderNotFoundException(ConstraintViolationException exception) {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), exception.getMessage()));
}
}
Validation Annotation
import javax.validation.*;
import java.lang.annotation.*;
#Constraint(validatedBy = FolderValidationConstraint.class)
#Target({ElementType.PARAMETER, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface ValidateFolder {
String message() default "Error validating folder name";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Validator class
import lombok.extern.slf4j.*;
import javax.validation.*;
import java.io.*;
#Slf4j
public class FolderValidationConstraint implements ConstraintValidator<ValidateFolder, String> {
#Override
public boolean isValid(String path, ConstraintValidatorContext constraintValidatorContext) {
return new File("/home/ashish/Documents/test-delete/" + path).exists();
}
}
Controller
import org.springframework.validation.annotation.*;
import org.springframework.web.bind.annotation.*;
import java.io.*;
import java.util.*;
#Validated
#RestController
#RequestMapping(path = "/folders")
public class FolderController extends BaseController {
#GetMapping
public Map<String, Boolean> delete(#ValidateFolder #RequestParam("name") String folderName) {
final File path = new File("/home/ashish/Documents/test-delete/" + folderName);
return Map.of("exists", path.exists());
}
}
Please make sure to add dependency in pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Controller are not working in Spring

I unable to understand why my controller are not redirecting to my html. Anyone can help me please?
WebConfig.java
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.udemy.controller" })
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix("");
return resolver;
}
}
HelloWorldController.java
#Controller
#RequestMapping("/example")
public class HelloWorldController {
public static final String EXAMPLE_VIEW = "example.html";
#GetMapping("/")
public String fileUploadForm(Model model) {
return "fileDownloadView";
}
#GetMapping("/helloworld")
public String helloWorld(){
return "helloworld";
}
// #RequestMapping(value="/exampleString", method=RequestMethod.GET)
#GetMapping("/exampleString")
public String exampleString(Model model){
model.addAttribute("name","John");
return EXAMPLE_VIEW;
}
// #RequestMapping(value="/exampleMAV", method=RequestMethod.GET)
#GetMapping("/exampleMAV")
public ModelAndView exampleMAV() {
ModelAndView mav= new ModelAndView(EXAMPLE_VIEW);
mav.addObject("name", "Mike");
return mav;
}
AppInitializer
public class MyWebAppInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
My project structure is well done. So my html and jsps, are inside of the root WEB-INF/views. Also, the anotation #ComponentScan, are detecting the controller. So, its not a problem of root. Anyone can tell me, why im am not redirecting to the .html , please..
Error says:
ADVERTENCIA: No mapping found for HTTP request with URI [/spring-mvc-download-example/WEB-INF/views/example.html] in DispatcherServlet with name 'dispatcher'
In your controller class, above the
#RequestMapping("/example")
Insert:
#Controller
Gonna be:
#Controller
#RequestMapping("/example")
you have to annotate class HelloWorldController with #Controller or #RestController, only then it will be picked by #Componentscan annotation.

Spring boot + redis

I am working demo Spring boot application with integration of Redis.
I have referred various site reference but lastly I preferred to follow this: http://www.baeldung.com/spring-data-redis-tutorial
My code is almost same as given in above link. Only change is that I have autowired StudentRepository in my RestController class.
Now when I try to do maven-install at that time it gives me error that
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'studentController': Unsatisfied dependency expressed through field 'studentRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'studentRepositoryImpl' defined in file [/home/klevu/work/Nimesh/Spring Boot Workspace/bootDemo/target/classes/com/example/demo/redis/repository/StudentRepositoryImpl.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.example.demo.redis.repository.StudentRepositoryImpl]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: No visible constructors in class com.example.demo.redis.repository.StudentRepositoryImpl
When I tried to keep constructor public, it creates build successfully. But I don't know I should do it or not here. I was thinking that rather than Autowiring constructor, I should be able to do setter injection. I also tried below:
#Autowired
private RedisTemplate<String, Student> redisTemplate;
But it is also not working.
package com.example.demo.redis.repository;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;
import com.example.demo.redis.bean.Student;
#Repository
public class StudentRepositoryImpl implements StudentRepository {
private static final String KEY = "Student";
//#Autowired
private RedisTemplate<String, Student> redisTemplate;
private HashOperations<String, String, Student> hashOps;
#Autowired
private StudentRepositoryImpl(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
#PostConstruct
private void init() {
hashOps = redisTemplate.opsForHash();
}
#Override
public void saveStudent(Student person) {
hashOps.put(KEY, person.getId(), person);
}
#Override
public void updateStudent(Student person) {
hashOps.put(KEY, person.getId(), person);
}
#Override
public Student findStudent(String id) {
return hashOps.get(KEY, id);
}
#Override
public Map<String, Student> findAllStudents() {
return hashOps.entries(KEY);
}
#Override
public void deleteStudent(String id) {
hashOps.delete(KEY, id);
}
}
RedisConfiguration are default and code as below:
package com.example.demo.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
#Configuration
public class RedisConfiguration {
#Bean
JedisConnectionFactory jedisConnectionFactory() {
return new JedisConnectionFactory();
}
#Bean
public RedisTemplate<String, Object> redisTemplate(){
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(jedisConnectionFactory());
return template;
}
}
Spring boot main entry point is declared as below:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
#SpringBootApplication
#EnableMongoRepositories(basePackages = {"com.example.demo.mongo.repository"} )
#EnableRedisRepositories(basePackages = {"com.example.demo.redis.repository"})
public class BootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(BootDemoApplication.class, args);
}
}
Demo controller to test redis is as below:
package com.example.demo.controller;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.redis.bean.Student;
import com.example.demo.redis.repository.StudentRepository;
#RestController
#RequestMapping("/student")
public class StudentController {
#Autowired
private StudentRepository studentRepository;
#GetMapping
public ResponseEntity<Map<String, Student>> index() {
Map<String, Student> students = studentRepository.findAllStudents();
return new ResponseEntity<Map<String, Student>>(students, HttpStatus.OK);
}
#RequestMapping(method = RequestMethod.GET, value = "/{id}")
public ResponseEntity<Student> getStudentById(#PathVariable("id") String id) {
Student student = studentRepository.findStudent(id);
return new ResponseEntity<Student>(student, HttpStatus.OK);
}
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<Student> saveStudent(#RequestBody Student student) {
studentRepository.saveStudent(student);
return new ResponseEntity<Student>(student, HttpStatus.CREATED);
}
#RequestMapping(method = RequestMethod.PUT, value = "/{id}")
public ResponseEntity<Student> updateStudent(#RequestBody Student student) {
studentRepository.updateStudent(student);
return new ResponseEntity<Student>(student, HttpStatus.OK);
}
#RequestMapping(method = RequestMethod.DELETE, value = "/{id}")
public ResponseEntity<Student> deleteMessage(#PathVariable("id") String id) {
studentRepository.deleteStudent(id);
return new ResponseEntity<Student>(HttpStatus.OK);
}
}
You set the constructor as private... change it to public
#Autowired
public StudentRepositoryImpl(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
Change the following redis configuration:
Your original:
#Bean
public RedisTemplate<String, Object> redisTemplate() {
...
}
Change it to:
#Bean
public RedisTemplate<String, ?> redisTemplate(){
...
}
It should work now for you.
You could use Spring Data Redis
Add dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Enable Caching
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
#SpringBootApplication
#EnableCaching
public class RedisDemoApplication {
public static void main(String[] args) {
SpringApplication.run(RedisDemoApplication.class, args);
}
}
Add Cacheable annotation at method to cache in redis
#Cacheable(value = "employee", key = "#id")
public Employee getEmployee(Integer id) {
log.info("Get Employee By Id: {}", id);
Optional<Employee> employeeOptional = employeeRepository.findById(id);
if (!employeeOptional.isPresent()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Id Not foud");
}
return employeeOptional.get();
}

Spring boot configure MessageInterpolator #Bean

I am using Spring boot v1.4 and hibernate v4.3.5.finall in my application
I have writen my own ResourceBundle and MessageInterpolator to save messages in database and have configured them as bean in my project. It seems ResourceBundle works fine and returns my custom message but parameters don't pass,for example for this validation :
#Size(min=5,max = 10)
private String lastName;
I expect : size must be between 5 and 10 bla bla.....
but the result is : size must be between {min} and {max} bla bla.....
any Idea? Thanks..
my ResourceBundle class:
package ir.pt.core.bundles;
import ir.pt.common.bean.ResourceEntity;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import java.io.IOException;
import java.util.*;
public class DatabaseResourceBundle extends ResourceBundle {
#PersistenceContext
protected EntityManager em;
private Map<String, String> cache = new HashMap<String, String>();
protected final static String BUNDLE_NAME = "ir.pt.core.bundles";
protected Control DB_CONTROL = new DBControl();
public DatabaseResourceBundle() {
setParent(ResourceBundle.getBundle(BUNDLE_NAME, DB_CONTROL));
}
public DatabaseResourceBundle(Locale locale) {
setParent(ResourceBundle.getBundle(BUNDLE_NAME, locale, DB_CONTROL));
}
#Override
protected Object handleGetObject(String key) {
return cache != null ? cache.get(key) : parent.getObject(key);
}
#Override
public Enumeration<String> getKeys() {
return parent.getKeys();
}
protected class DBControl extends Control {
#Override
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException {
return new CustomizedLocaleResources(locale);
}
protected class CustomizedLocaleResources extends ListResourceBundle {
private Locale locale;
public CustomizedLocaleResources(Locale locale) {
this.locale = locale;
}
#Override
protected Object[][] getContents() {
String sql = "FROM ResourceEntity re WHERE re.locale = '"+locale.getLanguage()+"'";
TypedQuery<ResourceEntity> query =
em.createQuery(sql, ResourceEntity.class);
List<ResourceEntity> resources = query.getResultList();
Object[][] all = new Object[resources.size()][2];
int i = 0;
for (Iterator<ResourceEntity> it = resources.iterator(); it.hasNext();) {
ResourceEntity resource = it.next();
all[i] = new Object[]{resource.getKey(), resource.getMessage()};
cache.put(resource.getKey(), resource.getMessage());
i++;
}
return all;
}
}
}
}
my MessageInterpolator class:
package ir.pt.core.bundles;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
import org.springframework.beans.factory.annotation.Autowired;
import javax.validation.MessageInterpolator;
import java.util.Locale;
import java.util.Map;
public class DatabaseMessageInterpolator extends ResourceBundleMessageInterpolator implements MessageInterpolator{
protected final String BRACE_OPEN = "\\{";
protected final String BRACE_CLOSE = "\\}";
#Autowired
DatabaseResourceBundle databaseResourceBundle;
#Override
public String interpolate(String message, Context context) {
return interpolate(message, context, databaseResourceBundle.getLocale());
}
#Override
public String interpolate(String message, Context context, Locale locale) {
String messageKey = context.getConstraintDescriptor().getAttributes().get("message").toString();
message = databaseResourceBundle.getString(messageKey.replaceAll(BRACE_OPEN, "").replaceAll(BRACE_CLOSE, ""));
Map<String, Object> attributes = context.getConstraintDescriptor().getAttributes();
for (String key : attributes.keySet()) {
String value = attributes.get(key).toString();
key = BRACE_OPEN + key + BRACE_CLOSE;
message = message.replaceAll(key, value);
}
return message;
}
}
my bean configuration:
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurationSupport {
#Override
public Validator getValidator() {
LocalValidatorFactoryBean factory = new LocalValidatorFactoryBean();
factory.setMessageInterpolator(messageInterpolator());
return factory;
}
#Bean
public MessageInterpolator messageInterpolator() {
return new DatabaseMessageInterpolator();
}
#Bean
ResourceBundle resourceBundle() {
return new DatabaseResourceBundle(new Locale("fa"));
}
}

HTTP Status 404 - Using Spring+Tomcat

I am beginner to Spring and I am working on my learning project. With below code, I can view the index.jsp but not test.jsp. I use Spring 4.0.1+ Tomcat 7.0.52 + STS 3.4.0.
Webapp.java
package springweb;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class Webapp extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[0];
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{ WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[]{ "/" };
}
}
IndexController.java
package springweb.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class IndexController {
private static final Logger logger = LoggerFactory.getLogger(IndexController.class);
#RequestMapping(value="/")
public String index() {
logger.info("Welcome Index!");
return "index";
}
}
TestController.java
package springweb.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
public class TestController {
private static final Logger logger = LoggerFactory.getLogger(TestController.class);
#RequestMapping(value="/test/", method = RequestMethod.GET)
public String test() {
logger.info("Welcome test!");
return "test";
}
}
WebConfig.java
package springweb;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages={"springweb.controller"})
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
Simple answer for 100% free xml:
Set property for the 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[] { "/" };
}
//that's important!!
#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";
}
}
that's all

Resources