0

I've read most of the online resources for building a simple "Hello World" app using Java and Struts 2. I understand the simple stuff. My problem is that I'm trying to expand that learning and build a large scale app, and I just don't see how to connect the dots.

Scenario: I've got three views to begin with: Home.jsp, MyAccount.jsp, Contact.jsp. Each has the following HTML:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html>

<html>
    <head>
        <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
        <script type="text/javascript" src="js/common.js"></script>
        ...
    </head>
    <body>
        <!-- If logged in, says "hello <s:property name="username">"
             Else displays link to .show() #loginPane -->
        <div id="accountHeader">...</div>

        <!-- Displays <s:textfield> tags and <s:submit> tag to accept username and password -->
        <div id="loginPane" style="display: none">...</div>

        <header>...</header>

        <nav>...</nav>

        <!-- Displays view-specific content that includes Struts 2 tags -->
        <div id="content">...</div>

        <footer>...</footer>
    </body>
</html>

So, obviously there is a lot of code common to each view (anything not in #content div).

How do I architect these views for code reuse?

What I've tried:

  • Placing common code in common.js and using jQuery .html() calls to populate <div>s. [Doesn't work because jQuery cannot generate code with <s:> tags.]

  • Using only one .jsp view file and placing view-specific code in common.js to be generated with jQuery .html() calls. [Doesn't work for the same reason -- jQuery cannot generate code with <s:> tags.]

  • Placing all view components in .jspf files and loading each with jQuery .load() calls from common.js. [Doesn't work -- I'm guessing the .jspf files need the Struts 2 <%taglib ...%> included in each, but jQuery .load() treats the <%taglib ...%> as text to be displayed in the <div>... and also fails to properly generate the <s:> tags.]

What is the proper way to do this? How do I architect my view(s) for code reuse?

My apologies if this isn't the proper forum to ask for architecture help, but I'm really struggling here... Perhaps point me to a more appropriate forum or an online tutorial that addresses this type of architecture?

Thanks in advance!

user2507377
  • 67
  • 1
  • 7

2 Answers2

1

I've used several methods to accomplish this type of re-use of code including Tiles and tooling around with Sitemesh and other template frameworks. What I've found is that, much as Steven Benitez, in the end I preferred to use JSP taglibs, native Struts2 taglibs, and JSTL to essentially build out my own templating routines. The main reason I prefer this is that there tends to be less overhead and it's been a lot easier to maintain and extend in the long run.

Generally What I do is define my base template, index.jsp for example, and then in each independent Struts controller class I will define what page fragment is used. I try to split my controllers up in such a way that each page or function is handled by a single controller and I implement the Preparable interface. This way I can set a parameter for the page to reference. Sometimes I set it as a variable in the controller class, sometimes a sessions variable depending on what type of stating I need for the application.

Once I have a variable with the page to reference, I can just use a JSTL import or Struts include tag to load the page fragment.

The controller class would look something like this:

@Results({
    @Result(name = "success", location = "/WEB-INF/content/index.jsp")
})
public class IndexController extends RestActionSupport implements Preparable{
    private String page;
    private String pageTitle;

    @Override
    public void prepare() throws Exception {
        page = "home";
        pageTitle= "My Home Page";
    }
    ...
}

And then the JSP would look something like this:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="s" uri="/struts-tags"%> 
<html>
    <head>
        <title> ${pageTitle}</title>
    </head>

    <body>
        <c:import url="${page}.jsp" />
    </body>
</html>

EDIT: Fragment page example:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="s" uri="/struts-tags"%>

<div>
    <h1>Welcome Home!</h1>
</div>

<script type='text/javascript'>
    $(document).ready(function() {
        // page specific scripting if needed
    );
</script>
Russell Shingleton
  • 3,176
  • 1
  • 21
  • 29
  • Hi, thanks so much to both of you for responding! Russell, can you elaborate some more on what your .jsp files look like that you're importing? Do they look like normal HTML files (Struts <%taglib...%> at the top, ...,
    [view-specific code]
    , etc.) or do they only contain the view-specific code?
    – user2507377 Jul 17 '13 at 06:45
  • @user2507377 JSP pages that use the S2 tag libraries *must* include the taglib directives if they're dynamically included elsewhere, as each is its own servlet. – Dave Newton Jul 17 '13 at 10:41
  • Yes. As Dave Newton said, each fragment needs to have the taglibs included. Typically the fragments I use are not full HTML pages, rather I tend to use fragments with view specific code, content wrapped in a div for instance, instead of the full html-head-body since these elements are declared in my template page. – Russell Shingleton Jul 17 '13 at 12:27
  • Sorry for the delayed response... I needed to find some time to sit down and code this out. Thanks Russell, that was exactly the solution I was looking for! – user2507377 Jul 19 '13 at 21:54
0

You can encapsulate common template code in JSP tag files, as explained in this answer or you can also use decorator frameworks such as Tiles or SiteMesh to do this.

Personally, I prefer JSP tag files. Do not attempt to write out HTML with jQuery or to put all of your code into a single JSP.

Community
  • 1
  • 1
Steven Benitez
  • 10,936
  • 3
  • 39
  • 50
  • I have a REST-ful controller called via, for example, /Orders which calls a service that returns a list of orders. Within my controller, which can now be called multiple locations where a list of orders is needed - I have no idea whether this list will be the basis of a select-option control, or displayed as a
    • list or table - so that in turn forces me towards returning json or xml, which means writing HTML with jQuery. How do you deal with issues like this?
    – user497087 Jul 18 '13 at 07:59
  • If you're building an AJAX single-page app, you might want to use a specialized framework for that, such as Angular.js or Knockout. – Steven Benitez Jul 18 '13 at 15:01