2

I recently configured spring based maven project and I just want to replace all my XML (except POM) with java. I explore a lot of articles and docs regarding this, But, the reason I am here is, I have doubts which I think to be get resolved by you people.

As we know, every dynamic web project has single XML, which is called web.xml in absence of a framework.

Now If we integrate some framework say Struts, Spring, ORM etc. It is necessary to configure those also, so we write another XML config file.

I configured spring project so I have one deployment descriptor,application-context, and dispatcher servlet.

WEB.XML

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/app-ctx.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
     <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>redirect.jsp</welcome-file>
    </welcome-file-list>
</web-app>

app-ctx.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:flow="http://www.springframework.org/schema/webflow-config"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xmlns:jms="http://www.springframework.org/schema/jms"
       xmlns:lang="http://www.springframework.org/schema/lang"
       xmlns:osgi="http://www.springframework.org/schema/osgi"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:tx="http://www.springframework.org/schema/tx"

       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop 
                           http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/context  
                           http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/webflow-config 
                           http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd
                           http://www.springframework.org/schema/jee 
                           http://www.springframework.org/schema/jee/spring-jee.xsd
                           http://www.springframework.org/schema/jms 
                           http://www.springframework.org/schema/jms/spring-jms.xsd
                           http://www.springframework.org/schema/lang 
                           http://www.springframework.org/schema/lang/spring-lang.xsd
                           http://www.springframework.org/schema/osgi 
                           http://www.springframework.org/schema/osgi/spring-osgi.xsd
                           http://www.springframework.org/schema/tx 
                           http://www.springframework.org/schema/tx/spring-tx.xsd
                           http://www.springframework.org/schema/util 
                           http://www.springframework.org/schema/util/spring-util.xsd">

    <context:component-scan base-package="com.mzk.mavenproject1"/>

<!--    <bean id="propertyConfigurer"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
          p:location="/WEB-INF/config_local.properties" />-->


</beans>

dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:flow="http://www.springframework.org/schema/webflow-config"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xmlns:jms="http://www.springframework.org/schema/jms"
       xmlns:lang="http://www.springframework.org/schema/lang"
       xmlns:osgi="http://www.springframework.org/schema/osgi"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:util="http://www.springframework.org/schema/util"

       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop 
                           http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/context  
                           http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/mvc 
                           http://www.springframework.org/schema/mvc/spring-mvc.xsd
                           http://www.springframework.org/schema/webflow-config 
                           http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd
                           http://www.springframework.org/schema/jee 
                           http://www.springframework.org/schema/jee/spring-jee.xsd
                           http://www.springframework.org/schema/jms 
                           http://www.springframework.org/schema/jms/spring-jms.xsd
                           http://www.springframework.org/schema/lang 
                           http://www.springframework.org/schema/lang/spring-lang.xsd
                           http://www.springframework.org/schema/osgi 
                           http://www.springframework.org/schema/osgi/spring-osgi.xsd
                           http://www.springframework.org/schema/tx 
                           http://www.springframework.org/schema/tx/spring-tx.xsd
                           http://www.springframework.org/schema/util 
                           http://www.springframework.org/schema/util/spring-util.xsd">

    <mvc:resources mapping="/resources/**" location="/resources/"  cache-period="31556926" />
    <context:component-scan base-package="com.mzk.mavenproject1"/>

    <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>    

    <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
        <!--Turn off working out content type based on URL file extension, should fall back to looking at the Accept headers-->
        <property name="favorPathExtension" value="false" />
    </bean>   

    <!-- 2. HandlerMapping : Used default handler mapping internally -->

    <!-- 3. ViewResolver -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>   

</beans>

CONFUSION:

I am confused to know that, exactly how java many classes we need to replace the same. We need three java classes or the two classes are enough?

because, a lot of articles demonstrated the two java classes, which replace web.xml and dispatcher-servlet.xml, so what about app-ctx.xml?

EDITS:

 @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addRedirectViewController("/", "home");
    }

OR

@Override
        public void addViewControllers(ViewControllerRegistry registry) {
           registry.addViewController("/").setViewName("home");
        }

CONTROLLER CLASS

@Controller
public class HomeController {

    @RequestMapping(value="/")
    public ModelAndView showhomePage() {
        ModelAndView mav = new ModelAndView("home");
        mav.addObject("successMsg", "Congratulations! Your Cortana is Properly congigured");
        return mav;
    }
}

I also do one trick, I created a global index.jsp, and specify only one scriptlet which will redirect the request to the Controller by using `sendRedirect().

LIKE

@Override
            public void addViewControllers(ViewControllerRegistry registry) {
               registry.addViewController("/").setViewName("forward:/index.jsp");
            }

No snippet work for me, every time I am facing 404, something I am missing i think?

cgrim
  • 4,890
  • 1
  • 23
  • 42
user9634982
  • 565
  • 5
  • 24
  • You can also replace _app-ctx.xml_ by Java class - look here: https://stackoverflow.com/questions/45002435/how-to-define-componentscan-without-xml-and-annotation – cgrim Oct 15 '18 at 07:17
  • Hi @cgrim, I am expecting you, thanks for your coming, can you demonstrate the replacement, so it will be helpful for me, actually I am confused, because for three XML, how can we configured all three only in two classes. – user9634982 Oct 15 '18 at 07:20
  • the above article didn't help me much – user9634982 Oct 15 '18 at 09:16
  • As per above article, I still need to have dispatcher-servlet.xml, but my requrement is pure java based configuration – user9634982 Oct 15 '18 at 09:20

1 Answers1

5

If I understand it well you want to get rid of all XML configurations.

Then at first you have to implement WebApplicationInitializer which replaces web.xml config file. You can do it like this:

public class CustomWebAppInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(RootConfig.class);

        ContextLoaderListener contextLoaderListener = new ContextLoaderListener(rootContext);
        servletContext.addListener(contextLoaderListener);

        AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
        webContext.register(MvcConfig.class);

        DispatcherServlet dispatcherServlet = new DispatcherServlet(webContext);
        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", dispatcherServlet);
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
    }
}

Another step is to implement Spring configuration for root context which replaces app-ctx.xml:

@Configuration
@EnableWebMvc
@ComponentScan({"com.mzk.mavenproject1.service", "com.mzk.mavenproject1.model"})
public class RootConfig {
// ... provide another custom beans when needed
}

And the last step is to implement configuration for MVC which replaces dispatcher-servlet.xml:

@Configuration
@EnableWebMvc
@ComponentScan("com.mzk.mavenproject1.controller")
public class MvcConfig extends WebMvcConfigurerAdapter {
    @Bean
    ViewResolver internalViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }

// ... provide another custom beans when needed
}

Regarding of your question about classes count - yes, you can do it only by two classes: CustomWebAppInitializer and MvcConfig and have only one context for everything.

CustomWebAppInitializer.onStartup() method body will then look like:

    AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
    webContext.register(MvcConfig.class);

    ContextLoaderListener contextLoaderListener = new ContextLoaderListener(webContext);
    servletContext.addListener(contextLoaderListener);

    DispatcherServlet dispatcherServlet = new DispatcherServlet(webContext);
    ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", dispatcherServlet);
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/");
cgrim
  • 4,890
  • 1
  • 23
  • 42
  • Tons of thanks @cgrim, you just nailed it, now finally I got a clear clarity – user9634982 Oct 15 '18 at 14:04
  • But now i am concerning about the attributes inside @ComponentScan, because, the number of packages will increase in future in that case i need to hardcode the same, I wish, there should be way to declare packages in properties file and refer that property file inside componentscan, so we do not need to modify the MvcConfig.java again and again isn't? – user9634982 Oct 15 '18 at 14:07
  • 2
    You can partly return to XML approach and have `DispatcherServlet` configuration in XML - then no need to recompile ;-) Another option is to have package `mvc` for `MvcConfig` and `core` for `RootConfig` and ten separate it by your need on sub-packages for example. Or you can go from the opposite side and scan everything and prepare filters for packages you dont want to scan - see https://stackoverflow.com/questions/16238089/filter-specific-packages-in-componentscan – cgrim Oct 15 '18 at 14:19
  • one more thing, is it mandatory to specify the full path in @ComponentScan, what If I provided only @ComponentScan("com.mzk.mavenproject1"),may be it stuck or may be not? – user9634982 Oct 15 '18 at 17:04
  • I'm not sure what do you mean by _full path_. But you can have `@ComponentScan("com.mzk.mavenproject1")` whether there are other sub-packages or not. – cgrim Oct 15 '18 at 17:57
  • hey I am just trying to configure , and I encountered 404, please see my edits – user9634982 Oct 15 '18 at 18:03
  • Add `registry.addViewController("/").setViewName("forward:/home");` in `MvcConfig.addViewControllers()` and annotation for `HomeController.showHomePage()` should be `@RequestMapping(value = "/home", method = RequestMethod.GET)` For more details you can look here https://stackoverflow.com/questions/30972676/how-to-specify-welcome-file-list-in-webapplicationinitializer-onstartup – cgrim Oct 15 '18 at 18:21
  • I took reference from the same link, but still I am stuck – user9634982 Oct 15 '18 at 18:27
  • I think there is somewhare another reason for that, because I comment the addviewcontroller snippet, but still I am getting 404, the default "Hello world" is also not displayed, it displayed before 15 minutes. – user9634982 Oct 15 '18 at 18:31