views:

3802

answers:

3

Hi,

I'm currently evalutating Struts 2. The official documentation contains a HelloWorld example with the following Java and JSP code:

Java

import com.opensymphony.xwork2.ActionSupport;

public class HelloWorld extends ActionSupport {

    public static final String MESSAGE = "Struts is up and running ...";

    public String execute() throws Exception {
        setMessage(MESSAGE);
        return SUCCESS;
    }

    private String message;

    public void setMessage(String message){
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

JSP

<%@ taglib prefix="s" uri="/struts-tags" %>

<html>
    <head>
        <title>Hello World!</title>
    </head>
    <body>
        <h2><s:property value="message" /></h2>
    </body>
</html>

The example uses the following XML file to specify a URL for this action, and to tie the action and view together

<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd"&gt;
<struts>
    <package name="tutorial" extends="struts-default">
        <action name="HelloWorld" class="tutorial.HelloWorld">
            <result>/HelloWorld.jsp</result>
        </action>
    </package>
</struts>

My question (finally) is: is this really the state-of-the-art for Struts2? I'd been lead to believe that the necessity for XML config and subclassing a particular base class (ActionSupport) has been deprecated. I thought that annotations could be used for configuration instead.

A couple of more specific questions:

  • Is it necessary to have one Action class for each request type, or is it possible to define multiple methods in an eaction, each of which can handle a different request?
  • Is it necessary to define a public getter and setter for the data members that you want to make available to the view ('message' in the example above)?

If this is the state-of-the-art in Struts2, then it doesn't seem like much of an improvement over Struts1, but I suspect this is just a bad example.

Thanks, Don

+1  A: 

Some answers (not all):

  • You can add several methods to the same Action class. Each of those need to return a String.
  • I think the public getter and setter are needed.
  • The base class provided only defines certain useful values, such as the constant SUCCESS.

You can use annotations by means of the "Zero Configuration" feature (zero conf doc)

pgb
+1  A: 

The example is old-style struts2. You can use annotations for just about everything, as @pgb says.

There are also 2 distinct styles of configuration available; one is called "convention" and the other is "annotation". Convention is influenced by rails, and creates default bindings between actions and results by path/naming. Using annotations you declare everything, like you did with xml, but only inside the controller class. I find both to be great simplifications and am currently running with only a tiny xml file for a large site.

krosenvold
Here is a link to the convention plugin: https://cwiki.apache.org/WW/convention-plugin.htmlI highly recommend it.
Ruggs
+1  A: 

Sorry for the missing resources, but I can not copy and paste those here.

But this should give you an idea about the 2.1.x features.

struts.xml:

<!DOCTYPE struts PUBLIC 
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd"&gt;
<struts>
    <!-- Include webwork default (from the Struts JAR). -->
    <include file="struts-default.xml"/>
    <!-- Configuration for the default package. -->
    <package name="default" extends="struts-default">
     <interceptors>
      <interceptor name="appLogin" class="us.pdinc.client.com.usgoldnetwork.support.struts.LoginInterceptor" /> 
      <interceptor-stack name="loginStack">
                <interceptor-ref name="appLogin"/>
                <interceptor-ref name="paramsPrepareParamsStack"/>
            </interceptor-stack>
     </interceptors>  
     <!-- Default interceptor stack. -->
     <default-interceptor-ref name="loginStack"/>  
     <global-results>
            <result name="login">/WEB-INF/jsp/login-input.jsp</result>
        </global-results>
    </package>
</struts>
<!--  http://struts.apache.org/2.1.6/docs/convention-plugin.html  -->

struts.properties:

struts.custom.i18n.resources=guest
struts.convention.result.path=/WEB-INF/jsp
struts.ognl.allowStaticMethodAccess=true

AddrAction.java

    package us.pdinc.client.com.usgoldnetwork.action;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.hibernate.Session;
import org.hibernate.Transaction;

import us.pdinc.client.com.usgoldnetwork.beans.model.hibernate.Addr;
import us.pdinc.client.com.usgoldnetwork.beans.model.hibernate.AddrType;
import us.pdinc.client.com.usgoldnetwork.beans.model.hibernate.Tx;
import us.pdinc.client.com.usgoldnetwork.servlet.support.RequestScopeHibernateSession;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;

@Results({
      @Result(name="list", type="redirect", location="/addr", params={"transaction.id","${transaction.id}"})
    })
public class AddrAction extends ActionSupport implements Preparable , ServletRequestAware 
{
    private static final long serialVersionUID = 1L;

    private List<Addr> addrs;
    private List<AddrType> addrTypes;
    private List<Tx> txs;
    private Addr addr;
    private AddrType addrtype;
    private HttpServletRequest httpServletRequest;
    private Tx transaction;
    long txId = 0;

    @Override
    public void prepare() throws Exception
    {
     if (addr!=null && addr.getId()!=null) 
      {
       Session session = RequestScopeHibernateSession.getSession(httpServletRequest);
       addr=(Addr) session.get(Addr.class, addr.getId());
      }
    }

    public String index()
    {
     return list();
    }

    public String list()
    {
     System.out.println("LIST");
     if (transaction==null)throw new RuntimeException();
     if (transaction.getId()==null) throw new RuntimeException();
     if (transaction.getId()<=0) throw new RuntimeException();
     Session session = RequestScopeHibernateSession.getSession(httpServletRequest);
     transaction=(Tx)session.get(Tx.class, transaction.getId());
     addrs=transaction.getAddrs();

     return SUCCESS;
    }

    public String input() 
    {
     Session session = RequestScopeHibernateSession.getSession(httpServletRequest);
     addrTypes=session.createCriteria(AddrType.class).list();
     //txs = session.createCriteria(Tx.class).list();
     return INPUT;
    }

    public String save() 
    {
     System.out.println("SAVE");

     if(transaction != null && transaction.getId() != null){
      txId = transaction.getId();
     }
     if(addr != null && addr.getTx() != null && addr.getTx().getId() != null){
      txId = addr.getTx().getId();
     }
     /*if (transaction==null || addr == null)throw new RuntimeException();
     System.out.println("******************************************************************");
     System.out.println("Transaction value ==" + transaction);
     System.out.println("Addr value ==" + addr);
     if (addr.getTx() == null) throw new RuntimeException();
     System.out.println("Transaction ID value ==" + transaction.getId());
     System.out.println("Addr Transaction value ==" + addr.getTx());
     if ( addr.getTx().getId() == null ) throw new RuntimeException();
     System.out.println("********************************************************************");
     System.out.println("Addr Transaction ID value ==" + addr.getTx().getId());*/

     Session session = RequestScopeHibernateSession.getSession(httpServletRequest);
     transaction=(Tx)session.get(Tx.class, txId);
     //String addrTypeId = httpServletRequest.getParameter("addr.addrType.id");
     //Long Id = Long.valueOf(addrTypeId);
     addrtype=(AddrType) session.get(AddrType.class, addr.getAddrType().getId());
     if (addr.getId()==null)
     { 
      System.out.println("Addr is null");
      addr.setTx(transaction);
      addr.setAddrType(addrtype);
      Transaction tx = session.getTransaction();
      tx.begin();
      session.save(transaction);
      session.persist(addr);
      tx.commit();
     }
     else
     {
      System.out.println("Addr is not null");
      Transaction tx = session.getTransaction();
      tx.begin();
      session.update(addr);
      tx.commit();  
     }
     return "list";
    }



    public String delete() 
    {
     Session session = RequestScopeHibernateSession.getSession(httpServletRequest);
     Transaction tx = session.getTransaction();
     tx.begin();
     session.delete(session.get(Addr.class, addr.getId()));
     tx.commit();  
     return "list";
    }


    @Override
    public void setServletRequest(HttpServletRequest arg0)
    {
     httpServletRequest=arg0; 
    }

    public Addr getAddr()
    {
     return addr;
    }

    public void setAddr(Addr addr)
    {
     this.addr = addr;
    }

    public List<Addr> getAddrs()
    {
     return addrs;
    }

    public List<AddrType> getAddrTypes()
    {
     return addrTypes;
    }

    public List<Tx> getTxs()
    {
     return txs;
    }

    public Tx getTransaction() {
     return transaction;
    }

    public void setTransaction(Tx transaction) {
     this.transaction = transaction;
    }

}

addr.jsp:

<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <link href="<s:url value='/css/main.css'/>" rel="stylesheet" type="text/css"/>
    <title>Addresses Screen</title>
       <jsp:include page = "barcodeextractor.jsp" />
</head>
<body>
<div class="titleDiv">USGN Core Process</div>
<h1>Addresses</h1>
<s:url id="url" action="addr!input" >
<s:param name="transaction.id" value="transaction.id" />
</s:url>
<a href="<s:property value="#url"/>">Add New Address</a>
<br/><br/>
<table class="borderAll">
    <tr>
        <th>Customer</th>
        <th>Name</th>
        <th>Type</th>
        <th>Street 1</th>
        <th>Street 2</th>
        <th>Street 3</th>
        <th>Street 4</th>
        <th>Street 5</th>
        <th>Street 6</th>
        <th>City</th>
        <th>State</th>
        <th>Postal</th>
        <th>Country</th>
        <th>&nbsp;</th>
    </tr>
    <s:iterator value="addrs" status="status">
        <tr class="<s:if test="#status.even">even</s:if><s:else>odd</s:else>">
            <td class="nowrap"><s:property value="tx.id"/></td>
            <td class="nowrap"><s:property value="name"/></td>
            <td class="nowrap"><s:property value="addrType.addrType"/></td>
            <td class="nowrap"><s:property value="street1"/></td>
            <td class="nowrap"><s:property value="street2"/></td>
            <td class="nowrap"><s:property value="street3"/></td>
            <td class="nowrap"><s:property value="street4"/></td>
            <td class="nowrap"><s:property value="street5"/></td>
            <td class="nowrap"><s:property value="street6"/></td>
            <td class="nowrap"><s:property value="city"/></td>
            <td class="nowrap"><s:property value="state"/></td>
            <td class="nowrap"><s:property value="postal"/></td>
            <td class="nowrap"><s:property value="country"/></td>
            <td class="nowrap">
                <s:url action="addr!input" id="url">
                    <s:param name="addr.id" value="id"/>
                </s:url>
                <a href="<s:property value="#url"/>">Edit</a>
                &nbsp;&nbsp;&nbsp;
                <s:url action="addr!delete" id="url" >
                    <s:param name="addr.id" value="id"/>
                </s:url>
                <a href="<s:property value="#url"/>">Delete</a>
            </td>
        </tr>
    </s:iterator>
    </table>
</body>
</html>

addr-input.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<s:if test="addr==null || addr.id == null">
    <s:set name="title" value="%{'Add new contact type'}"/>
</s:if>
<s:else>
    <s:set name="title" value="%{'Update contact type'}"/>
</s:else>

<html>
<head>
    <link href="<s:url value='/css/main.css'/>" rel="stylesheet" type="text/css"/>
    <style>td { white-space:nowrap; }</style>
    <title><s:property value="#title"/></title>
     <jsp:include page = "barcodeextractor.jsp" />
</head>
<body>
<div class="titleDiv">USGN Core Process</div>
<h1><s:property value="#title"/></h1>
<s:actionerror />
<s:actionmessage />
<s:form action="addr!save" method="post">
    <s:select name="addr.addrType.id" label="Address Type" list="addrTypes" listKey="id" listValue="addrType" value="%{addr.addrType.id}"/>
    <s:textfield name="addr.name" value="%{addr.name}" label="Name" size="40"/>
    <s:textfield name="addr.street1" value="%{addr.street1}" label="Street 1" size="40"/>
    <s:textfield name="addr.street2" value="%{addr.street2}" label="Street 2" size="40"/>
    <s:textfield name="addr.street3" value="%{addr.street3}" label="Street 3" size="40"/>
    <s:textfield name="addr.street4" value="%{addr.street4}" label="Street 4" size="40"/>
    <s:textfield name="addr.street5" value="%{addr.street5}" label="Street 5" size="40"/>
    <s:textfield name="addr.street6" value="%{addr.street6}" label="Street 6" size="40"/>
    <s:textfield name="addr.city" value="%{addr.city}" label="City" size="40"/>
    <s:textfield name="addr.state" value="%{addr.state}" label="State" size="40"/>
    <s:textfield name="addr.postal" value="%{addr.postal}" label="Postal" size="40"/>
    <s:textfield name="addr.country" value="%{addr.country}" label="Country" size="40"/>
    <s:hidden name="addr.id" value="%{addr.id}"/>
    <s:hidden name="transaction.id" value="%{transaction.id}"/>
    <s:submit value="Submit"/>
    <s:submit value="Cancel" name="redirectAction:addr!list"/>
</s:form>
</body>
</html>
Jason Pyeron