Archive

Posts Tagged ‘struts’

Dynamic Forms with Map-backed ActionForms in Struts 1

September 14, 2010 4 comments

A project that I work on uses Struts 1 and I came across a problem where I intended to create a page that could have any number of text fields (number of fields would be increased by a button click). The idea was to have a way to have name – value text input boxes whose content would be saved in a properties database table when the form was submitted. After some blind google searches I came across “Map-backed” and “List-backed” properties in struts. This write-up is a summary of using Map-backed properties to achieve that goal. This article does not show how to save the values in the database however… it just logs the values received on the server.

As a first step we will create a blank Struts application with maven. Look at this article to create a blank application.
The next step is to create a page that will have our dynamic form. Here is the page(dynamicTextEntry.jsp)..

<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>

<html:html>
<head>
<script type="text/javascript">
	function add(){
		var element1 = document.createElement("input");
		var element2 = document.createElement("input");
		var elementCount = parseInt(document.getElementById("count").value);

		element1.setAttribute("type","text");
		element1.setAttribute("value","Enter Name");
		element1.setAttribute("name","value(name"+ elementCount +")");

		element2.setAttribute("type","text");
		element2.setAttribute("value","Enter Value");
		element2.setAttribute("name","value(value"+ elementCount +")");

		var spanBody = document.getElementById("textBoxes");
		spanBody.appendChild(element1);
		spanBody.appendChild(element2);
		var breakElement = document.createElement('br');
		spanBody.appendChild(breakElement);
		
		document.getElementById("count").value = elementCount + parseInt(1);
	}
</script>
<title>Dynamic Entry Form</title>
<html:base/>
</head>
<body bgcolor="white">

<html:form action="setDynamicTextEntry.do" >
<html:hidden property="count" styleId="count" value="0"/>
<input type="button" value="Add Field (+)" onclick="add()"/>
</br>
<span id="textBoxes"></span>

<html:submit property="submit"> Submit</html:submit>

</html:form>
</body>
</html:html>

We will create two actions in struts-config.xml as follows… the action class is shown later…

	<action
            path="/dynamicInputs"
            forward="/pages/dynamicTextEntry.jsp"/>
		
	<action
            path="/setDynamicTextEntry"
            type="com.wordpress.codesilo.controller.SetDynamicTextEntryAction"
            name="dyamicTextEntryForm"
            scope="request"
            validate="true"
            input="/pages/dynamicTextEntry.jsp">
            <forward name="success" path="/pages/success.jsp"/>
        </action>

We will also add form bean to struts-config.xml

<form-bean name="dyamicTextEntryForm" type="com.wordpress.codesilo.model.DyamicTextEntryForm"></form-bean>

The action class is as follows…

public class SetDynamicTextEntryAction extends Action {

	
	@Override
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		
		DyamicTextEntryForm dynform = (DyamicTextEntryForm)form;
		Map dynformValues = dynform.getValues();
		int count = dynformValues.size()/2;
		
		System.out.println("Map Size: " + dynformValues.size());
		for(int i =0; i<count ; i++){
			String name = (String)dynformValues.get("name"+i);
			String value = (String)dynformValues.get("value"+i);
			System.out.println("Name:" + name + " Value:" + value);
		}
		return mapping.findForward("success");
	}
}

The form is as follows…

public class DyamicTextEntryForm extends ActionForm {

	private final Map values = new HashMap();
	private int count;
	
	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}

	public Map getValues(){
		return values;
	}
	
	public void setValue(String key, Object value){
		values.put(key, value);
	}
	
	public Object getValue(String key){
		return values.get(key);
	}
	
}

Add a success page that is forwarded to once the form is submitted and we are ready to try out the code.
The page looks as follows… (Every time to click the add button a new pair of text boxes are added)
When we add/change text in the boxes and click submit, the values entered in the text boxes are displayed in the console.


Explanation:
The javascript in the jsp adds text boxes to the existing dom in pairs. The elements added would look like the following when rendered in HTML

<input type="text" value="Enter Name" name="value(name0)">
<input type="text" value="Enter Value" name="value(value0)">

Every time the button is clicked the count increments and new text boxes are added. So, on the second click the following elements are added…

<input type="text" value="Enter Name" name="value(name1)">
<input type="text" value="Enter Value" name="value(value1)">

Once the form is submitted, the setValue(String key, Object value) on the form is called for each of these text boxes. The key will be the names we provide (name0, value0, name1, value1 etc) and the value is the value from the text boxes.

Rest is self explanatory. 🙂

References:
http://struts.apache.org/1.x/userGuide/building_controller.html
http://www.manning-sandbox.com/message.jspa?messageID=26953

Struts 1.3.5 Tiles – Basics

May 24, 2010 Leave a comment

Struts tiles provides us a templating system. The introduction below shows the basic reusability of the modules of a web page.
To start, we will build a basic struts project using a maven archetype. Read more of it here.
Add a new dependency to the pom file

 <dependency>
 <groupId>org.apache.struts</groupId>
 <artifactId>struts-tiles</artifactId>
 <version>1.3.5</version>
 </dependency>

In struts-config.xml of the project , add the following plugin

 <plug-in className="org.apache.struts.tiles.TilesPlugin" >
 <set-property property="definitions-config" value="/WEB-INF/tiles-defs.xml" />
 <set-property property="definitions-parser-validate" value="true" />
 <set-property property="moduleAware" value="true" />
 </plug-in>

What we will now do is remove the default welcome.jsp page that was created by maven and reroute the request to a page (layout.jsp) that we create using tiles.
The components of the page will be the following : header.jsp, footer.jsp,menu.jsp , body.jsp and need to be located in the pages folder.
These will look as follows:

header.jsp

<div id="header">
 This is header
</div>

footer.jsp

<div id="footer">
 This is footer
</div>

body.jsp

<div id="body">
 This is body
</div>

menu.jsp

<div id="menu">
 This is menu
</div>

layout.jsp

<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
<%@ taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles"%>

<html:html>
<head>

</head>

<body>
<table>
<tr valign='top'><td style="background-color:LightSlateGray "><tiles:insert attribute="menu"/></td>
<td><table>
<tr><td style="background-color:LightSkyBlue"><tiles:insert attribute="header"/></td></tr>
<tr><td style="background-color:LightSteelBlue "><tiles:insert attribute="body"/></td></tr>
<tr><td style="background-color:LightSkyBlue"><tiles:insert attribute="footer"/></td></tr>
</table>
</td>
</tr>
</table>
</body>
</html:html>

Uncomment the following from web.xml

<init-param>
<param-name>chainConfig</param-name>
<param-value>org/apache/struts/tiles/chain-config.xml</param-value>
</init-param>

Create a file tiles-defs.xml in the webapp folder of the project with the following content

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/tiles-config_1_3.dtd">
<tiles-definitions>
<definition name="Tiles.welcome" path="/pages/layout.jsp">
<put name="header" value="/pages/header.jsp" />
<put name="menu" value="/pages/menu.jsp" />
<put name="body" value="/pages/body.jsp" />
<put name="footer" value="/pages/footer.jsp" />
</definition>
</tiles-definitions>

So, now we have a tile definition by the name Tiles.welcome and the path /pages/layout.jsp. The layout.jsp has tiles header, menu, body and footer whose content will be in the files defined in the tiles-defs.xml file.

The last thing is to go to struts-config.xml file and change the forward path of the Welcome action…
Change ..

<action
path="/Welcome"
forward="/pages/Welcome.jsp"/>

to..

<action
path="/Welcome"
forward="Tiles.welcome"/>

Build and deploy the project. Go to the following url http://localhost:8080/test-struts-tiles (Note : The project I created was test-struts-tiles)
You should see the following

Note:
If you do not uncomment the lines in web.xml for chainConfig, you will get the following exception…
javax.servlet.ServletException: java.lang.IllegalArgumentException: Path Tiles.welcome does not start with a “/” character
org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:283)
org.apache.struts.action.ActionServlet.process(ActionServlet.java:1858)

<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
<%@ taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles"%>

<html:html>
<head>

</head>

<body>
<table>
<tr valign='top'><td style="background-color:LightSlateGray "><tiles:insert attribute="menu"/></td>
<td><table>
<tr><td style="background-color:LightSkyBlue"><tiles:insert attribute="header"/></td></tr>
<tr><td style="background-color:LightSteelBlue "><tiles:insert attribute="body"/></td></tr>
<tr><td style="background-color:LightSkyBlue"><tiles:insert attribute="footer"/></td></tr>
</table>
</td>
</tr>
</table>
</body>
</html:html>

Maven and Struts 1

February 10, 2010 7 comments

Maven archetype can be used to generate blank projects. However, the mvn archetype:generate command does not give an option to generate an empty struts project with Struts 1. To generate a Struts 1.x project we need to install the struts blank archetype. Use the following commands to download and install struts blank archetype in the local repository.

svn co http://svn.apache.org/repos/asf/struts/maven/trunk/struts-archetype-blank
cd struts-archetype-blank
mvn install

Now to generate a project use the following command

mvn archetype:generate -DarchetypeGroupId=org.apache.struts -DarchetypeArtifactId=struts-archetype-blank -DarchetypeVersion=1.3.5-SNAPSHOT -DgroupId=com.wordpress.codesilo -DpackageName=com.wordpress.codesilo -DartifactId=test-struts

Now we will test this on JBoss AS. Set a variable JBOSS_HOME in bash_profile and change the plugins section generated in the pom.xml file above to the following.

 <plugins>
 <plugin>
 <groupId>org.codehaus.mojo</groupId>
 <artifactId>jboss-maven-plugin</artifactId>
 <version>1.4</version>
 <configuration>
 <jbossHome>/${JBOSS_HOME}</jbossHome>
 <serverName>web</serverName>
 <fileName>target/test-struts.war</fileName>
 </configuration>
 </plugin>
 <plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-compiler-plugin</artifactId>
 <configuration>
 <source>1.5</source>
 <target>1.5</target>
 </configuration>
 </plugin>
 <plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-war-plugin</artifactId>
 <configuration>
 <webResources>
 <webResource>
 <directory>
 ${basedir}/src/main/webapp/WEB-INF</directory>
 <includes>
 <include>web.xml</include>
 </includes>
 <targetPath>WEB-INF</targetPath>
 <filtering>true</filtering>
 </webResource>
 </webResources>
 </configuration>
 </plugin>
 </plugins>

Now we will use the maven JBoss plugin to deploy the war generated above. Use the following command to deploy the war file.

mvn jboss:hard-deploy

(To undeploy use the command mvn jboss:hard-undeploy)

The war will be deployed to the following dir ($JBOSS_HOME/server/web/deploy) (in JBoss 5). If Jboss 4 is used, change the serverName above to “default”.

On starting Jboss we will see an exception ….
java.lang.ClassCastException: org.apache.xerces.jaxp.SAXParserFactoryImpl cannot be cast to javax.xml.parsers.SAXParserFactory
This can be corrected by removing the jar that is included by the struts-archetype-blank plugin.
Change the following in the pom.xml

 <dependency>
 <groupId>org.apache.struts</groupId>
 <artifactId>struts-core</artifactId>
 <version>1.3.5</version>
 </dependency>

to

 <dependency>
 <groupId>org.apache.struts</groupId>
 <artifactId>struts-core</artifactId>
 <version>1.3.5</version>
 <exclusions>
 <exclusion>
 <groupId>xml-apis</groupId>
 <artifactId>xml-apis</artifactId>
 </exclusion>
 </exclusions>
 </dependency>

The server will now start without any exceptions.