Spring MVC - Dispatcher Servlet can't find any page - spring

I do really simple demo web app using Spring mvc, Java class annotations and .jsp instead of .html.
When I start Tomcat on localhost - I always get 404 error. Where do I do mistake?
Config.class
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.mylov.springsecurity.demo.config")
public class Config {
//Define bean for ViewResolver
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
Dispatcher Servlet Initialization
public class DispatcherServletInit extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{Config.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
Controller
#Controller
public class DemoController {
#GetMapping({"", "/"})
public String showHome() {
return "home";
}
}
Project Structure:

You need to scan packages under demo package. So Spring will find your Controllers and Config classes. But now you point to only config. So package 'controller' won't be scan.
Try to do this:
#ComponentScan(basePackages = "com.mylov.springsecurity.demo")

Try providing the mapping as below so that all url's are mapped with the servlet:
public class DispatcherServletInit extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{Config.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/*"};
}
}
Also change the base packages to as below so that the controller class is also picked up for component scanning :
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.mylov.springsecurity.demo")
public class Config {
..........
}

Related

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.

#Bean Controller not getting picked up by #EnableMVC

Most of my #Controllers are picked up through component scanning. However, a few, such as those I use with Spring Social are created as #Beans. I just migrated from mostly xml to JavaConfig only and upgraded to Spring 4.1.9.
However, the Controller endpoints that are created as #Beans are creating 404s.
Any ideas?
package nl.project.webapp.config;
#Order(1)
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{WebAppConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{ServletConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
[...]
}
package nl.project.webapp.config;
#Configuration
#ComponentScan(basePackages = {"nl.project.webapp"},excludeFilters={
#ComponentScan.Filter(type=FilterType.ANNOTATION,value=Controller.class),
#ComponentScan.Filter(type=FilterType.ANNOTATION,value=RestController.class)
})
#Import({AppConfig.class,JPAConfig.class})
#PropertySource("classpath:msa.properties")
public class WebAppConfig {
[...]
}
package nl.project.webapp.config;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"nl.project.webapp.controller"},includeFilters={
#ComponentScan.Filter(type=FilterType.ANNOTATION,value=Controller.class),
#ComponentScan.Filter(type=FilterType.ANNOTATION,value=RestController.class)
})
public class ServletConfig extends WebMvcConfigurerAdapter{
[...]
}
package nl.project.webapp.social.config;
#Configuration
public class SocialConfig{
#Bean
public MyConnectController connectController(MessageSource messages, UsorManager userMgr, PhotoManager photoMgr) {
MyConnectController connectController = new MyConnectController(connectionFactoryLocator, connectionRepository);
connectController.setConnectInterceptors(Arrays.asList(new ConnectInterceptor<?>[]{
new TwitterConnectInterceptor(userMgr, photoMgr, messages),
new FacebookConnectInterceptor(userMgr, photoMgr, messages),
new LinkedInConnectInterceptor(userMgr, photoMgr, messages),
new GoogleConnectInterceptor(userMgr, photoMgr, messages),
}));
return connectController;
}
#Bean
public MySignInController signinController(MessageSource messages, UsorManager userMgr, PhotoManager photoMgr){
MySignInController signinController = new MySignInController(connectionFactoryLocator, usersConnectionRepository, new SimpleSigninAdapter(userMgr));
signinController.setSignInInterceptors(Arrays.asList(new ProviderSignInInterceptor<?>[]{
new FacebookSigninInterceptor(userMgr, photoMgr, messages),
new LinkedInSigninInterceptor(userMgr, photoMgr),
new GoogleSigninInterceptor(userMgr, photoMgr)
}));
return signinController;
}
}
package nl.project.webapp.social.controller;
#Controller
#RequestMapping("/signin")
public class MySignInController extends ProviderSignInController {
public MySignInController(
ConnectionFactoryLocator connectionFactoryLocator,
UsersConnectionRepository usersConnectionRepository,
SignInAdapter signInAdapter) {
super(connectionFactoryLocator, usersConnectionRepository, signInAdapter);
this.connectionFactoryLocator = connectionFactoryLocator;
}
[...]
The problem was caused by SocialConfig being imported by the WebAppConfig in stead of the ServletConfig. Although the documentation suggests that any Controller bean available in the context will be picked up by using '#EnableWebMVC', it is not very clear that this does not apply to Controller beans loaded through the webapp context.

migrate configuration from dispatcher servlet xml to java class. Do i need both(java class and xml)?

Following is the code for my dispatcher-servlet.xml and configuration class :
Where do i put my db configuration and entity definitions?
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
super.addViewControllers(registry);
// Default view
registry.addViewController("/").setViewName("home");
registry.addViewController("/login").setViewName("login");
registry.addViewController("/home").setViewName("home");
}
#Bean
public Filter basicMetricFilter() {
return new PieRequestMetricsFilter();
}
}
You can put those configurations in MvcConfig but it's NOT a good idea. A better approach is to define one config for each architectural aspect of your application and then put related configs only in each one. Suppose you have a web application with traditional layered architecture. In this example you would have WebConfig just like your MvcConfig class, like this:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.example.web")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
super.addViewControllers(registry);
// Default view
registry.addViewController("/").setViewName("home");
registry.addViewController("/login").setViewName("login");
registry.addViewController("/home").setViewName("home");
}
#Bean
public Filter basicMetricFilter() {
return new PieRequestMetricsFilter();
}
}
Also, you could have a RepositoryConfig that contains your data access related configurations, like this:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackges = "com.example.repository")
public class RepositoryConfig() {
// put your datasource, entity manager, jdbc templates, tx managers here
}
For wiring these configurations together, there is no need for any xml file such as dispatcher servlet or web.xml. You can define a WepApplicationInitializer that defines parent and child configs in this scenario, like this:
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { RepositoryConfig.class, SecurityConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
WebApplicationInitializer is an interface provided by Spring MVC that ensures your implementation is detected and automatically used to initialize any Servlet 3 container. An abstract base class implementation of WebApplicationInitializer named AbstractDispatcherServletInitializer makes it even easier to register the DispatcherServlet by simply overriding methods to specify the servlet mapping and the location of the DispatcherServlet configuration.
For more details please consult the spring documentation.

How can i separate jsp in differents folders with Spring?

This is my AppInitializer:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.project.app")
public class AppInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer implements
WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
ctx.setServletContext(container);
ServletRegistration.Dynamic servlet = container.addServlet(
"dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
And this is my AppConfig:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.acfcm.app")
#Import({ SecurityConfig.class })
public class AppConfig extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver viewResolverForClasses() {
ResourceBundleViewResolver viewResolver = new ResourceBundleViewResolver();
viewResolver.setOrder(1);
viewResolver.setBasename("views");
return viewResolver;
}
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setOrder(2);
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations(
"/resources/");
}
}
What I want is how to change the AppConfig to put .jsp in differents foldes into the project because right now only can save it in /WEB-INF/views/ and there is a lot of .jsp!! I want to have two more folders to see my project like:
WEB-INF/views/moduleOne/
WEB-INF/views/moduleTwo/
...
Thanks!
I think your code is all fine; it will look for your JSPs starting in /WEB-INF/views/
Most people do like you say and break up JSP views under folders like /admin, /common, etc.
The way you do this is to specify the subfolder in the controller. For example, in your controller, you could return:
#RequestMapping(value = "/admin/index.htm", method = RequestMethod.GET)
public ModelAndView index(HttpServletRequest request,
HttpServletResponse response)
{
Map<String, Object> myModel = new HashMap<String, Object>();
myModel.put("someValues", new ArrayList());
ModelAndView mv = new ModelAndView("admin/index","model", myModel);
return mv;
}
Doing it like the above, you can put your JSP under
/WEB-INF/views/admin/index.jsp
Of course, your mappings (/admin) doesn't have to match the directory structure (/WEB-INF/views/admin) but we chose to make both match, to make it faster to find the code (if controller mapping matches the dir structure).
The important thing to remember is that whatever you put in that ModelAndView first param, Spring will prepend and append the values you defined in your code:
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
So, if you return ModelAndview("/pierre/was/here/something"), Spring will try to find the JSP at location: "/WEB-INF/views/pierre/was/here/something.jsp"
The common practice is to have the configuration as yours, and in the request handler controller methods, use the view names as moduleOne/view1, moduleTwo/view2 etc.

Change main endpoint in Spring Data Rest (usind Spring Boot)

Im building a small application using Spring (Boot, Data, Data Rest).
I have some JpaRepositories that aumotatically are exported as Rest endpoints.
What i want to do is to change the base path from / to /api.
Now to list all people for example i do a GET to http://localhost:8080/people and i want the url to be http://localhost:8080/api/people.
I tried adding this config class but nothing happened (it seems that Spring Boot overrides this config):
public class SpringWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
#Override
protected Class<?>[] getRootConfigClasses()
{
return new Class<?>[] { Application.class};
}
#Override
protected Class<?>[] getServletConfigClasses()
{
return new Class<?>[] { RestExporterRestConfig.class, RepositoryRestMvcConfiguration.class };
}
#Override
protected String[] getServletMappings()
{
return new String[] { "/api/*" };
}
}
My Application.java:
#Configuration
#ComponentScan
#Import(RestExporterRestConfig.class)
#EnableJpaRepositories
#EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
and RestExporterRestConfig:
#Configuration
public class RestExporterRestConfig extends RepositoryRestMvcConfiguration {
#Bean
public Validator validator() {
return new LocalValidatorFactoryBean();
}
#Override
protected void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener v) {
v.addValidator("beforeCreate", validator());
}
#Bean
#Qualifier
public DefaultFormattingConversionService defaultConversionService() {
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addConverter(StringToDate.INSTANCE);
return conversionService;
}
#Bean
public DomainClassConverter<?> domainClassConverter() {
return new DomainClassConverter<DefaultFormattingConversionService>(defaultConversionService());
}
}
Well i figured it out. SpringWebAppInitializer is not necesary in this case. I just added this code to Application.java:
#Bean
public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
ServletRegistrationBean reg = new ServletRegistrationBean(dispatcherServlet);
reg.addUrlMappings("/api/*");
return reg;
}
I think this is the correct way to modify (add, change mappings, etc) servlets using Spring Boot.

Resources