Over a million developers have joined DZone.

Finally! A Web App (Part 2)

The second part of a series on turning a shape calculator into a web app for your team.

· Java Zone

What every Java engineer should know about microservices: Reactive Microservices Architecture.  Brought to you in partnership with Lightbend.

We began developing our application in the previous article....

Continue Developing the UI

And we are now almost ready to actually begin adding and working with the UI layout and pages.

I made two changes to our initial index.jsp to make sure the plumbing is working:

Image title

After our usual Build.Deploy.Start (BDS) (ha) cycle, our browser now shows:

Image title

Note that the title text is static, that is, it comes from the JSP.  Whereas the "Hi" is from the Controller class we created. It is the dynamic content.

More on this in a bit.

Convert to Pure Java Config

I realize this seems like a detour, but I want us to move from XML-config to Java config before we add anything else.

Then we'll get back to doing the UI.

We are going to replace web.xml, and mvc-dispatcher-servlet.xml, with Java classes.


And so I added a new class, "WebAppInitializer", in a new package, "com.eli.calc.shape.config".

You have seen that same "config" package in prior articles, when we were configuring our Shape Calculator Service.

Image title

You need to have that class implement WebApplicationInitializer.

Image title

I renamed the web.xml and mvc-dispatcher-servlet.xml by adding ".bak" at the end, to move them out of the way, and did a BDS again (see beginning of article if you forgot BDS). :D

The server log is just fine, but of course we get a 404 in the browser. Let's add to our new class.

So, we will need a root context, and we'll need a servlet context. Also, since we are doing our configuration with Java, we'll need to use annotations.

(Just a reminder: there are plenty of good articles on the web.. that's why I am not doing much of an explanation of the "why" as we proceed... but, rather, I am showing by how we get errors when something is missing — hopefully you will find this helpful someday if you come across an error)

I added the following to our new class's single method:

    System.err.println("\n\n\n\nWeb AppInitializer onStartup() \n\n\n\n");

    AnnotationConfigWebApplicationContext rootCtx =
                        new AnnotationConfigWebApplicationContext();



We'll now need a "WebConfig" class. I placed it in the same package as the Initializer. The WebConfig class could implement the "WebMvcConfigurer" interface, however, we would then have quite a few methods, most of we may not use.  So let's intead extend from "WebMvcConfigurerAdapter", and override what we need.

(Eclipse may complain of a possible error with "WebConfig.class" statement in the above code block, until you do a build.)

Continue With WebAppInitializer

Starting the server again, we'll see the console message that we placed in the WebAppInitializer.

We will need a context loader listener as well... so in our WebAppInitializer, I added:

    System.err.println("\n\n\n\nWeb AppInitializer root context loader listener.. \n\n\n\n");
    ContextLoaderListener loaderListener = new ContextLoaderListener(rootCtx);

(Yeah, I could add logging, but I'm lazy. Sue me)

Another BDS cycle, and nada.  No errors. Let's keep going.

Soo... by the time we are inside the "onStartup()" method, we have a servlet context.  It is passed in to this method.

We are going to inform it of our root context:

        "\n\n\n\nELI: "
        +"Web AppInitializer add root context loader listener to"
        +"servletcontext..... \n\n\n\n");

(Side note: I have a habit of putting my name "ELI:" so that I can later go back and do an exhaustive search, to remove all those print statements - since they're not worth the official capacity of a logging statement)

Note: when Eclipse implemented our onStartup(), it named the parameter as "arg0".  We need to change to match "servletContext".

Another BDS, and console output is still clean.

In case you are wondering how is it that we are replacing the contents of web.xml, here is an obvious one:

          "\n\n\n\nELI: "
          +"Web AppInitializer created dispatcher servlet passing root ctx....."
    DispatcherServlet dispatcherServlet = 
          new DispatcherServlet(rootCtx);

          +"Web AppInitializer register dispatcher servlet with servlet context....."
    ServletRegistration.Dynamic registration = 


    System.err.println("\n\n\n\nELI: Web AppInitializer onStartup() done\n\n\n\n");

Another BDS.  No issues.  However, if we were to try to view the root URL, we get:

Sep 07, 2016 2:35:57 PM org.springframework.web.servlet.PageNotFound noHandlerFound

WARNING: No mapping found for HTTP request with URI [/webapp-p1/] in DispatcherServlet with name 'dispatcherServlet'

Back to WebConfig

Ok, now it is time to add to WebConfig.

We need the WebConfig class to be involved during the Tomcat startup, since it is a web configuration class, after all.

Also, we may need to implement one or two methods:

// we may need this one...
    public void addViewControllers(ViewControllerRegistry registry) {

        System.err.println("\n\n\n\nELI: Web Config addViewControllers\n\n\n\n");


At the class level, let's add: @EnableWebMvc.  If you neglect to add this annotation, the class will not take part in the startup. Test this out — by putting it in and taking it out, and you should see the above print statement come and go.

So, first and foremost, we need @EnableWebMvc.

Let's BDS.  Console output looks clean. Let's try our URL: "http://webapp-dep-on-shape-calc-jpa-hibernate/"

We get a 404 at the browser, and we get this at the console:

WARNING: No mapping found for HTTP request with URI [/webapp-p1/index] in DispatcherServlet with name 'dispatcherServlet'

And it doesn't matter if we added the "/index" at the end or nor. Same error.

Remember that our mvc-dispatcher-servlet.xml file contained an InternalResourceViewResolver.   So we will add that inside our WebConfig.

    public InternalResourceViewResolver viewResolver() {

        System.err.println("\n\n\n\nELI: Web Config @Bean ViewResolvr\n\n\n\n");

        UrlBasedViewResolver viewResolver = new InternalResourceViewResolver();
        return viewResolver;

Time to BDS.

I saw the print statement in the console upon startup.

We still have the same mapping error as before.

Let's add one line to the first method in WebConfig:


So the complete WebConfig looks as so now:

package com.eli.calc.shape.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

public class WebConfig extends WebMvcConfigurerAdapter {

    public void addViewControllers(ViewControllerRegistry registry) {

        System.err.println("\n\n\n\nELI: Web Config addViewControllers\n\n\n\n");


    public InternalResourceViewResolver viewResolver() {

        System.err.println("\n\n\n\nELI: Web Config @Bean ViewResolvr\n\n\n\n");

        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        return viewResolver;


And let's make some changes to our index.jsp:

<title>Welcome To The Shape Calculator</title>
    <H1>Welcome : Static Index Page Text</H1>
    There should be a dynamic message here: [ ${message } ] but is there?

And let's also make changes to our RequestResponseController:

public class RequestResponseController {

    public ModelAndView welcomeTheSlash() {

        System.err.println("\n\n\nWelcome: The / (slash) ; Index page\n\n\n");

        return new ModelAndView(
          "Slash Index Page: dynamic message from Controller");

    public ModelAndView welcomeTheIndex() {

        System.err.println("\n\n\nWelcome2: The /index Index page\n\n\n");

        return new ModelAndView(
          "Index Index Page: dynamic message from Controller");

My goal here is to see what happens with static and dynamic content, and for us to be able to clearly see it.

Time to BDS.

We again have a clean startup.  Uninteresting.  What IS interesting is if you try these two different URLs:  (here are my versions)

  • http://localhost:8080/webapp-dep-....hibernate/

  • http://localhost:8080/webapp-dep-....hibernate/

The first one is nice... 

Image title

...and yet... we see only static content.  Checking the console output confirms the Controller method for the "/" was not involved.

The second URL fared worse.....

Image title

So I think we have already determined that the WebConfig, addViewControllers(), is somehow involved with static, but not dynamic, content.

Let's try to get the Controller involved.  We need to add an annotation to the WebConfig.


Spring will use this to search for suitable Controllers.

Do a BDS.

Try the two URLs again.  Een-teh-rress-teeng.  Hmm..

Here's what I got:

Image title


Image title

In both cases, we see both static and dynamic content, even though we only are handling the slash in the WebConfig, addViewControllers(), and NOT handling the "/index".

We can conclude that addViewControllers() method is only required when we only care about static content, but the the RequestResponseController will handle the mapping for both if there is a match.

So I am going to comment out the WebConfig addViewControllers() method for now.

Latest Code


Next Step: Continue With UI (Pages)

To be continued in the next article!

Microservices for Java, explained. Revitalize your legacy systems (and your career) with Reactive Microservices Architecture, a free O'Reilly book. Brought to you in partnership with Lightbend.

java 8,j2ee,jsp,bootstrap,javascript,spring mvc,controller

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}