Question

I'm using Struts 2 and the Display Tag table formatting tool to display query results from a database (a SELECT * query). I'm running into an odd error. After submitting a record to the database from Add.jsp, it takes me to View.jsp, where the table is correctly displayed. However, if I go to View.jsp directly, or via a hyperlink from the Add.jsp page WITHOUT submitting an entry to the database, it seemingly does not execute the methods necessary to retrieve the database entries into a variable to let the table display. In that case, I end up with a phrase, "nothing to display" where the table should be.

I was told this is most likely a problem with my method names, and the Struts 2 side of things, not any functionality on the Java side. I'm extremely new to Struts, and would appreciate some help at identifying and fixing the bugs. Some code excerpts are below, but I can post the whole thing if required. Also- no errors are shown when View.jsp is loaded, either after form submission or via direct link.

Add.jsp

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
    <head>
        <title>Add Development Environment</title>
    </head>
    <body>
    <div id="main">
        <h2>Add Development Environment</h2>

        <p><s:a href="View.jsp">View Entries</s:a></p>

        <s:actionerror />
        <s:form action="doEntries.action" method="post" validate="true">
            <s:textfield name="OS" key="label.OS" size="20" />
            <s:textfield name="OSVersion" key="label.OSVersion" size="20" />
            <s:textfield name="Note" key="label.note" size="20" />
            <s:submit method="doEntries" key="label.submit" />
        </s:form>
    </div>
    </body>
</html>

View.jsp

<%@ page contentType="text/html; charset=UTF-8" language="java" %>

<%@ taglib prefix="s" uri="/struts-tags"%>
<%@ taglib prefix="display" uri="http://displaytag.sf.net" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/"WebContent/View.jsp"DTD/xhtml1-transitional.dtd">
<html>
    <head>
        <title>View Development Environments</title>
    </head>
    <body>
    <div id="main">
    <h2>View Development Environments</h2>

    <p><s:a href="Add.jsp">Add Entry</s:a></p>

        <!--<s:set name="items" value="entries" scope="request"/>-->
            <display:table name="entries" class="DevEnvironment" requestURI="" id="itemsList" export="false" pagesize="15">
                <display:column property="did" title="id"/>
                <display:column property="OS" title="Operating System"/>
                <display:column property="OSVersion" title="Operating System Version" />
                <display:column property="note" title="Note"/>
            </display:table>
    </div>
    </body>
</html>

DatabaseAction.java

public class DatabaseAction extends ActionSupport{ 
    private static final Logger logger = Logger.getLogger(DatabaseAction.class);
    DBO myDBO;

    private String OS;
    private String OSVersion;
    private String note;

    private ArrayList<DevEnvironment> entries;

    private double offset;
    private double limit;

    public DatabaseAction(){
        super();
        //connect to DB
        myDBO = new DBO("com.mysql.jdbc.Driver", "jdbc:mysql://localhost:3306/devenvironments?user=root&password=mysqliscool");

    }

    public String doEntries(){
        logger.info("puting stuff in DB! =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-==-=-=");
        if(myDBO.connect() && myDBO.setEntry(OS, OSVersion, note)){
            return "success";
        } else {
            return "error";
        }
    }

    public ArrayList<DevEnvironment> getEntries() { 
        logger.info("-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=getEntries called");
        entries = myDBO.getEntry(0, -1);
        return entries;
    }

    public void setEntries(ArrayList<DevEnvironment> entries){
        this.entries = entries;
    }

    public String retrieveEntries(){
        logger.info("-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=retrieveEntries called");
        if(myDBO.connect()){
            logger.info("-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=EXECUTING SQL SELECT METHOD");
            //entries = myDBO.getEntry(0, -1);
            //offset, limit
            return "success";
        } else {
            return "input";
        }
    }

Struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <constant name="struts.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="false" />
    <constant name="struts.custom.i18n.resources" value="ApplicationResources" />
    <package name="default" extends="struts-default" namespace="/">
        <action name="doEntries" method="doEntries" class="net.josh.devenvironments.DatabaseAction" >
            <result name="success">View.jsp</result>
            <result name="input">Add.jsp</result>
        </action>
        <!-- 
        <action name="retrieveEntries" method="retrieveEntries" class="net.josh.devenvironments.DatabaseAction" >
            <result name="success">View.jsp</result>
            <result name="input">Add.jsp</result>
        </action>
        -->
    </package>
</struts>
Was it helpful?

Solution

You can get to the View.jsp because it is publicly accessible. As a rule put all JSP's under /WEB-INF the reason for this is that View.jsp will not make sense unless it is backed by an action. If you just go to View.jsp as you are now it does not go though an action it just hits the JSP directly and tries to parse it, the tags not finding any data probably gracefully fail (S2 tags typically do this, can't find the property just give up).

Now with the JSP under the /WEB-INF folder the only way to access it is with "doEntries" (you can leave off the dot action unless you're only filtering .action with s2 but if you don't have good reason you shouldn't be). Of course don't forget to update the action mapping to /WEB-INF/View.jsp

Now you could create another action called view to get there but if all it is going to do is the same thing as "doEntries" there really isn't any point, just use "doEntries".

When you get sick of writing XML (which is good practice but isn't really necessary) add the struts2-conventions-plugin to your class path. After it is added do the following:

Create a new package called struts2, create a class in it like this:

package struts2;

class HelloWorld extends ActionSupport{
  public String greetings = "Hello from HelloWorld Class!";
}

Then create a jsp called "hello-world.jsp" under /WEB-INF/content that has a

<s:property value="greeting"/>

tag now if you enter "hello-world" where index.html is probably located you'll see a little hello message... For most simple cases by following a simple Class to JSP naming convention you can avoid XML all together. If you don't like the convention you can easily override what you don't like, but if you add the conventions plugin to your class path both your xml and future conventions action will live in harmony.

PS: Yes I suppose the HelloWorld class should have getters and setters but it works just fine that way, and makes the example shorter.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top