Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Finally! A Web App (Part 3)

DZone's Guide to

Finally! A Web App (Part 3)

In the next part of this series, see how the first steps of getting your Java app up and running on the web.

· Java Zone
Free Resource

Just released, a free O’Reilly book on Reactive Microsystems: The Evolution of Microservices at Scale. Brought to you in partnership with Lightbend.

We have been on a long software development journey (here is the first article) in our make-believe scenario — where you work within a team of developers and your team is part of a larger IT organization, and you have been enhancing some code for quite some time. It started as something just for yourself. It probably had just one or two classes and a "main()" method, but it was useful.

Then, over time, it progressed from that to a reusable component in its own project (ShapeCalculatorService), having persistence (Spring Data JPA with Hibernate), and it is currently used within a command-line application.

But for the past two articles (here and here), and continuing with this one, you have been requested to enable that service for the web. In other words, expose all of the very same command-line (menu-driven) features, but in a web page.

Back to UI (Pages)

Ok, we are finally ready to tackle our UI.

I think we need several pages, to handle:

  • Viewing pending requests.

  • Viewing calculated results.

  • Maybe also a combo run/view results.

  • Obviously, we need a page to create a request.

  • All of that in addition to our index page.

Let's add some pages. I copied from index.jsp and created pending.jsp, newreq.jsp, and results.jsp.

Here is what the project looks like at the moment:

Image title

You can view all of the code here.

Index.jsp

We want our index.jsp to be the jumping off place of all the other pages.

Let's recall what we want this to look like:

Image title

Image title

That look-and-feel, and those tabs were created with the help of  Bootstrap.

I downloaded their zip file, and copied the CSS and JS folders into a new "resources" folder under the WebContent folder of the project.

Image title

For our desired style, and for the tabs, here is something we can start with, taken from w3schools.com.  Look for "Toggleable/Dynamic Tabs".

<ul class="nav nav-tabs">
  <li class="active"><a data-toggle="tab" href="#home">Home</a></li>
  <li><a data-toggle="tab" href="#menu1">Menu 1</a></li>
  <li><a data-toggle="tab" href="#menu2">Menu 2</a></li>
</ul>

<div class="tab-content">
  <div id="home" class="tab-pane fade in active">
    <h3>HOME</h3>
    <p>Some content.</p>
  </div>
  <div id="menu1" class="tab-pane fade">
    <h3>Menu 1</h3>
    <p>Some content in menu 1.</p>
  </div>
  <div id="menu2" class="tab-pane fade">
    <h3>Menu 2</h3>
    <p>Some content in menu 2.</p>
  </div>
</div>

Let's add the above to our index.jsp.

After trying this, our index.jsp looks like so:

Image title

Not good.   Looks like we are missing style sheet (CSS) information.

Add the following in the <head></head> section of index.jsp:

<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/bootstrap.min.css" />

Our next try is no better.  Taking a look at the console output, we see why:

WARNING: No mapping found for HTTP request with URI [/webapp-p2/resources/css/bootstrap.min.css] in DispatcherServlet with name 'dispatcherServlet'

WebConfig

We need to add the following:

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

After a Build.Deploy.Start (BDS)...  

Image title

Ah... Yes... Much better.

Notice the text jutted all the way to the edge — not good. We need to fix that.

Index.jsp

To do so, wrap everything that we now have inside the <body></body>, with this:

<body>

<div class="container">
....   div block ....

</div>

</body>


Integrate Pages

We want index.jsp to be the hub or focal point of everything. So we need somehow to get the individual <div> sections of the Bootstrap template to reference the other pages, or to allow us to embed them.

I left the original template code in and added what we will need for our purposes.

        <ul class="nav nav-tabs">
            <li class="active"><a data-toggle="tab" href="#home">Home</a></li>
            <li><a data-toggle="tab" href="#menu1">Menu 1</a></li>
            <li><a data-toggle="tab" href="#menu2">Menu 2</a></li>
            <li><a data-toggle="tab" href="#newreq" >Request Calculation</a></li>
            <li><a data-toggle="tab" href="#pening"  >Pending Requests</a></li>
            <li><a data-toggle="tab" href="#results" >Calculated Results</a></li>
        </ul>

        <div class="tab-content">
            <div id="home" class="tab-pane fade in active">
                <h3>HOME</h3>
                <p>Some content.</p>
            </div>
            <div id="menu1" class="tab-pane fade">
                <h3>Menu 1</h3>
                <p>Some content in menu 1.</p>
            </div>
            <div id="menu2" class="tab-pane fade">
                <h3>Menu 2</h3>
                <p>Some content in menu 2.</p>
            </div>

<!-------------------------------------------------------------------------------->
<!-------------------------------------------------------------------------------->
            <div id="newreq" class="tab-pane fade">
                <h3>Request Calculation</h3>
<!--  -->
                <div id="requestFrameDiv" 
                     class="embed-responsive embed-responsive-16by9">
                </div>
<!--  -->
            </div>

<!-------------------------------------------------------------------------------->
<!-------------------------------------------------------------------------------->
            <div id="pending" class="tab-pane fade">
                <h3>Show Current Requests</h3>
<!--  -->
                <div id="pendingFrameDiv" 
                     class="embed-responsive embed-responsive-16by9">
                </div>
<!--  -->
            </div>

<!-------------------------------------------------------------------------------->
<!-------------------------------------------------------------------------------->
            <div id="results" class="tab-pane fade">
                <h3>Run/List Calculations</h3>
<!--  -->
                <div id="resultsFrameDiv" 
                     class="embed-responsive embed-responsive-16by9">
                </div>
<!--  -->
            </div>


        </div>


And it looks like this:

Image title

Let's move onto another change. Let's remove the template code ("Home," "Menu 1," etc.) that we won't use, and add our own "Home," "About." 

Here are the tab changes (Home, About)...

            <li class="active"><a data-toggle="tab" href="#home">Home</a></li>
            <li><a data-toggle="tab" href="#menu1">Menu 1</a></li>

 .... more code here....


<!------------------------------------------------------------------------------------>
<!------------------------------------------------------------------------------------>
            <div id="home" class="tab-pane fade in active">
                <h3>HOME</h3>
                <p>Wecome to The Shape Calculator</p>
                <p/>
                <p>
                This is a project that began as a result of a programming exercise.<br>
                It is probably non-sensical, but it was a good way to review/study<br>
                some technologies such as:
                </p>
                <p>HTML 5, CSS, JS, Bootstrap</p>
                <p>Spring MVC</p>
                <p>JPA / Hibernate / MySQL</p>
                <p>This is a complete web app, front to back</p>
                <p>(there is another that is a webapp client consuming a web service)</p>
            </div>

<!------------------------------------------------------------------------------------>
<!------------------------------------------------------------------------------------>
            <div id="about" class="tab-pane fade ">
                <h3>About/Usage</h3>
                <p>Wecome to The Shape Calculator</p>
                <p/>
                <p>
                If you first click on either <b>Current Requests</b> or <b>Run/List Results</b>,<br>
                you should not see much.  Once you do a <b>Request Calculation</b>, then <br>
                the requested calculation moves to a pending list. Once you do a <br>
                <b>Run/List..</b> then the pending calculation will disappear.<br>
                You can request multiple calculations, and they will create a list of<br>
                pending requests, and then you can run them all at the same time.<br>
                I purposely put in some random time for each calculation, to simulate<br>
                a long-running process.  I did not have time to add a 'busy' icon<br>
                in the Run/List page.. so you may just see a delay before anything<br>
                appears.
                </p>
                <p>Tested on Chrome 51.0.., IE 11.0.., and Firefox 37.0..
            </div>



Also, if you try clicking the tabs, they don't work. We need to add the Bootstrap JS code, and Bootstrap depends on JQuery. So we need both.

Make sure to have the npm.js, bootstrap.min.js (or bootstrap.js), and jquery-x.x.x.min.js (or jquery-x.x.x.js) in the WebContent/resources/js folder.

Then you need to refer to them in the <head></head> section.

<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/bootstrap.min.css" />
<script src="${pageContext.request.contextPath}/resources/js/jquery-2.2.4.min.js"></script>
<script src="${pageContext.request.contextPath}/resources/js/bootstrap.min.js"></script>

<title>Welcome To The Shape Calculator</title>

</head>


Now, when we try it, we see just the tabs we need — and they work.

Note: I am using Bootstrap 3.3.6. When I tried JQuery 3.1.0, it didn't seem to work. When I tried  JQuery 2.2.4, it worked. Your mileage may vary.

Image title


OK, so, we know the tabs work. But we have yet to load and display our new pages (pending.jsp,  newreq.jsp, and result.jsp).

I'm sure there are other ways to do this, but I chose to go the route of dynamically including the child pages into iframes with some scripts.

    <script>
    function loadNewReqFrame() {
        $("#requestFrameDiv").html("<iframe src=\'${pageContext.request.contextPath}/newreq\'></iframe>");
    }
    </script>

    <script>
    function loadCurReqFrame() {
        $("#pendingFrameDiv").html("<iframe src=\'${pageContext.request.contextPath}/pending\'></iframe>");
    }
    </script>

    <script>
    function loadResultsFrame() {
        $("#resultsFrameDiv").html("<iframe src=\'${pageContext.request.contextPath}/results\'></iframe>");
    }
    </script>


I also had to change the tab-headings section, from this:

<li><a data-toggle="tab" href="#newreq" >Request Calculation</a></li>
<li><a data-toggle="tab" href="#pending"  >Pending Requests</a></li>
<li><a data-toggle="tab" href="#results" >Calculated Results</a></li>


To this:

<li><a data-toggle="tab" href="#newreq" onClick="loadNewReqFrame()">Request Calculation</a></li>
<li><a data-toggle="tab" href="#pening" onClick="loadCurReqFrame()" >Current Requests</a></li>
<li><a data-toggle="tab" href="#results" onClick="loadResultsFrame()">Run/List Results</a></li>

Here is the complete index.jsp, up till our latest changes:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/bootstrap.min.css" />
<script src="${pageContext.request.contextPath}/resources/js/jquery-2.2.4.min.js"></script>
<!--
<script src="${pageContext.request.contextPath}/resources/js/jquery-3.1.0.min.js"></script>
-->
<script src="${pageContext.request.contextPath}/resources/js/bootstrap.min.js"></script>

<title>Welcome To The Shape Calculator</title>

    <script>
    function loadNewReqFrame() {
        $("#requestFrameDiv").html("<iframe src=\'${pageContext.request.contextPath}/newreq\'></iframe>");
    }
    </script>

    <script>
    function loadCurReqFrame() {
        $("#pendingFrameDiv").html("<iframe src=\'${pageContext.request.contextPath}/pending\'></iframe>");
    }
    </script>

    <script>
    function loadResultsFrame() {
        $("#resultsFrameDiv").html("<iframe src=\'${pageContext.request.contextPath}/results\'></iframe>");
    }
    </script>

</head>
<body>
    <div class="container">

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

        <ul class="nav nav-tabs">
            <li class="active"><a data-toggle="tab" href="#home">Home</a></li>
            <li><a data-toggle="tab" href="#about" >Usage</a></li>
            <li><a data-toggle="tab" href="#newreq" onClick="loadNewReqFrame()">Request Calculation</a></li>
            <li><a data-toggle="tab" href="#pending" onClick="loadCurReqFrame()" >Pending Requests</a></li>
            <li><a data-toggle="tab" href="#results" onClick="loadResultsFrame()">Calculated Results</a></li>
        </ul>

        <div class="tab-content">

<!------------------------------------------------------------------------------------>
<!------------------------------------------------------------------------------------>
            <div id="home" class="tab-pane fade in active">
                <h3>HOME</h3>
                <p>Wecome to The Shape Calculator</p>
                <p/>
                <p>
                This is a project that began as a result of a programming exercise.<br>
                It is probably non-sensical, but it was a good way to review/study<br>
                some technologies such as:
                </p>
                <p>HTML 5, CSS, JS, Bootstrap</p>
                <p>Spring MVC</p>
                <p>JPA / Hibernate / MySQL</p>
                <p>This is a complete web app, front to back</p>
                <p>(there is another that is a webapp client consuming a web service)</p>
            </div>

<!------------------------------------------------------------------------------------>
<!------------------------------------------------------------------------------------>
            <div id="about" class="tab-pane fade ">
                <h3>About/Usage</h3>
                <p>Wecome to The Shape Calculator</p>
                <p/>
                <p>
                If you first click on either <b>Current Requests</b> or <b>Run/List Results</b>,<br>
                you should not see much.  Once you do a <b>Request Calculation</b>, then <br>
                the requested calculation moves to a pending list. Once you do a <br>
                <b>Run/List..</b> then the pending calculation will disappear.<br>
                You can request multiple calculations, and they will create a list of<br>
                pending requests, and then you can run them all at the same time.<br>
                I purposely put in some random time for each calculation, to simulate<br>
                a long-running process.  I did not have time to add a 'busy' icon<br>
                in the Run/List page.. so you may just see a delay before anything<br>
                appears.
                </p>
                <p>Tested on Chrome 51.0.., IE 11.0.., and Firefox 37.0..
            </div>


<!------------------------------------------------------------------------------------>
<!------------------------------------------------------------------------------------>
            <div id="newreq" class="tab-pane fade">
                <h3>Request Calculation</h3>
<!--  -->
                <div id="requestFrameDiv" class="embed-responsive embed-responsive-16by9">
                </div>
<!--  -->
            </div>

<!------------------------------------------------------------------------------------>
<!------------------------------------------------------------------------------------>
            <div id="pending" class="tab-pane fade">
                <h3>Pending Requests</h3>
<!--  -->
                <div id="pendingFrameDiv" class="embed-responsive embed-responsive-16by9">
                </div>
<!--  -->
            </div>

<!------------------------------------------------------------------------------------>
<!------------------------------------------------------------------------------------>
            <div id="results" class="tab-pane fade">
                <h3>Calculated Results</h3>
<!--  -->
                <div id="resultsFrameDiv" class="embed-responsive embed-responsive-16by9">
                </div>
<!--  -->
            </div>


        </div>

    </div>

</body>
</html>


If you try it now, you will notice that "Home" and "Usage" work, but the other three have differing results: 

Image title

Notice we see some 404 not found errors, but we also see some valid HTML. The 404s occur inside the iframes.

Why does one tab work, but not the others?

Here is the console output:

Sep 09, 2016 1:16:27 AM org.springframework.web.servlet.PageNotFound noHandlerFound

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

Sep 09, 2016 1:17:21 AM org.springframework.web.servlet.PageNotFound noHandlerFound

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

Where did we map the "Pending Requests?" Open the RequestResponseController class.

You will see a method there, and you will see this:

@RequestMapping(value="/pending",method=RequestMethod.GET)

The "/pending" matches what you see in the Javascript inside index.jsp:

<script>
function loadCurReqFrame() {
    $("#pendingFrameDiv").html("<iframe src=\'${pageContext.request.contextPath}/pending\'></iframe>");
}
</script>

Let's add to the RequestResponseController:

    @RequestMapping(value="/newreq",method=RequestMethod.GET)
    public ModelAndView newreq() {

        System.err.println("\n\n\nNew Request\n\n\n");

        return new ModelAndView("/newreq","message","New Request Page: message from Controller");

    }

    @RequestMapping(value="/results",method=RequestMethod.GET)
    public ModelAndView results() {

        System.err.println("\n\n\nCalculated Results\n\n\n");

        return new ModelAndView("/results","message","Calculated ResultsPage: message from Controller");

    }


When you try now, all the tabs should work and look the same.

Get the Latest Code

You can go here to get the latest version of the code.

Next Steps

We have come a long way. We are close to completing this round of the web application for the Shape Calculator. Inside the Controller, we will add in the required code to use the Calculator, and that's about it. Except...

We need to be able to return lists of pending requests and calculated results back to the JSPs, and we also have the matter of creating a new request. We will need a FORM for that.

So, stay tuned for the next article!

Strategies and techniques for building scalable and resilient microservices to refactor a monolithic application step-by-step, a free O'Reilly book. Brought to you in partnership with Lightbend.

Topics:
java 8 ,j2ee ,spring mvc ,jsp ,bootstrap ,javascript ,iframes ,controllers ,model ,view

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}