Joshua Java

Creating custom component in Struts 2

Posted on: December 27, 2008

On my previous Tapestry 5 article I mentioned how difficult it is to create a custom component with Struts 2 compared to Tapestry 5. Since in our legacy apps we used Struts 2 and I got a task that made me to create a custom component I might as well just document it here since it is not documented in Struts 2 documentation nor the Struts 2 book.

I will show you a very simple example on how to create custom component which is the renown “Hello World”. This component would have one property: name.

First of all you would create a Component object which is extended from Component class. This is a reusable UI Component in Struts 2 which can be reused for JSTL, Freemarker and Velocity. For this article I will show you how to reuse it in JSTL, but it shouldn’t be hard to reuse it in Freemarker and Velocity once you get the gist of how custom components works in Struts 2.

package lab.struts2.components;

import com.opensymphony.xwork2.util.ValueStack;
import org.apache.struts2.components.Component;

import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;
import java.util.List;

public class Hello extends Component {
    protected String name;

    public Hello(ValueStack stack) {
        super(stack);
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean start(Writer writer) {
        try {
            writer.write("Hello " + name);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return true;
    }

    public boolean end(Writer writer) {
        return true;
    }

    @Override
    public boolean usesBody() {
        return false;
    }
}

As you can see from the code above, the Writer is located in this Component class. If you have written a JSTL tag before then you would know that the Writer is in the Taglib class. That is because this component will be reused by other view like Freemarker or Velocity. Since the Writer that is responsible to send buffer to the view is located in this class, you have to write the start and end method in this class. These two methods will be responsible to process anything on the tag opener and tag closer. The last method is the usesBody which is responsible to indicated whether body should be used or not. Besides those methods you must also create the property that can be accepted by this Component including its setters. The last thing you must write in this class is a constructor which receives ValueStack as its parameter.

Now onward to the next step. As I have told you that this article intend to show how to reuse Struts 2 component in JSTL. So the next step would be creating a JSTL tag. In this article we will extend the Tag class from ComponentTagSupport which is a Struts 2 base class for JSTL view that supports Struts 2 component. Two methods that must exists in this class is the populateParams and getBean method which is responsible to propagate the values that is set to the Component object. Now in this class you must also again write the property that can be accepted along with its setters.

package lab.struts2.taglib;

import org.apache.struts2.views.jsp.ComponentTagSupport;
import org.apache.struts2.components.Component;
import com.opensymphony.xwork2.util.ValueStack;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lab.struts2.components.Hello;

public class HelloTag extends ComponentTagSupport {
    protected String name;
    
    public Component getBean(ValueStack stack, 
             HttpServletRequest req, 
             HttpServletResponse res) {
        return new Hello(stack);
    }

    protected void populateParams() {
        super.populateParams();

        Hello hello = (Hello)component;
        hello.setName(name);
    }

    public void setName(String name) {
        this.name = name;
    }
}

Since we are reusing the component in JSTL, the last step would be registering this component in a .tld file which defines what properties that can be called from the JSP page. As for me I would save this .tld in META-INF/

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
        "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
    <tlib-version>2.2.3</tlib-version>
    <jsp-version>1.2</jsp-version>
    <short-name>lab</short-name>
    <uri>/lab</uri>
    <display-name>"Lab Tags"</display-name>
    <description><!&#91;CDATA&#91;"lab"&#93;&#93;></description>
    <tag>
        <name>hello</name>
        <tag-class>lab.struts2.taglib.HelloTag</tag-class>
        <body-content>JSP</body-content>
        <description><!&#91;CDATA&#91;Render a hello&#93;&#93;></description>
        <attribute>
            <name>id</name>
            <required>false</required>
            <rtexprvalue>false</rtexprvalue>
            <description>
                <!&#91;CDATA&#91;id for referencing element&#93;&#93;></description>
        </attribute>
        <attribute>
            <name>name</name>
            <required>true</required>
            <rtexprvalue>false</rtexprvalue>
            <description><!&#91;CDATA&#91; Name&#93;&#93;></description>
        </attribute>
    </tag>
</taglib>

Now that we have created our component, we would call it from a JSP page as such:

<!DOCTYPE html PUBLIC 
	"-//W3C//DTD XHTML 1.1 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
	
<%@taglib prefix="s" uri="/struts-tags" %>
<%@taglib prefix="lab" uri="/lab" %>

<html>
<head>
	<title>Hello World</title>
	<s:head />
</head>
<body>
    <lab:hello name="joshua"/>
</body>
</html>

If you open up your browser it would display: Hello joshua.

Well that shows you some effort you need to do for creating custom component in Struts 2. As you can see that this is only a very trivial example, but it shouldn’t be too difficult to get more advanced from here. Good luck.

19 Responses to "Creating custom component in Struts 2"

stop using struts and tapestry it is all dead. User more advanced ultra modern framework like Wicket.

Well, the Wicket is not such so great, the design idea is similar as ASP.NET, but it is hard for users.

Not everybody have the privilege to use whatever framework in their project 🙂

Hi Joshua,

Thank you very much for this post, I really appreciate it. I am in the process of doing a conversion from Struts 1 on IBM Portal to Struts 2 on Tomcat and I think that this article will prove to be very helpful.

Take Care,
Cory Wheeler

Thanks for article. Very useful!

@pen ma

what do you mean about :
stop using struts and tapestry it is all dead. User more advanced ultra modern framework like Wicket.

is it the struts2 & tapestry project have been discountinued?..
i see many people is still learn and use Struts2 and tapestry for their solution..

CMIIW..
thx..

@Aji Dont Listen to the lame pen ma is an idiot and he does not know what he is talking about.

Tapestry, Wicket and Struts are alive and well projects that continue to improve.

Nice article to get started with.

Nice post. Could you put an example on how to manage, instead of a String for the “name” variable, a List for exemple ?

I want to have a inside Writer.write . However, it is not being rendered in the webbrowser…

This was very useful thanks. In the old struts 1 world only one class was needed for a custom tag. Is there a way to do this with one class or do you always need to subclass ComponentTagSupport and Component in two classes for a JSTL tag in struts 2?

closing tag is not working. You need to use the following method
end(java.io.Writer writer, java.lang.String body)

Hi !

Thanks! for the post. Quite usefull.

I followed your custom tag tutorial and as long as I hard code the property values into the tag it works. If I try to inject a session or request object into it it will not read the actual value of the tag it reads it as a string value. Example:

name = “#request.name”
it will
read it as the string “#request.name”. I even tried to set the true and it still will not read it correctly. What do I need to do to fix this. Thank You

Also I know Struts 1 has an InitPlugin which operates on the servletContext layer to iitialize variables when the appl first starts up in the server. I use it to initialize a few variables. I can arc a spring service into it and load the results into the getAttribute. Does Struts have anything like this? If so it needs to do the same thing.

This is in reference to my query to create a struts2 custom tag that has access to request or session objects. I went ahead and researched this solution. By the time anyone would come up with a viable solution we might be moving on to Struts3. or be dead and buried. I felt this solution might help a few motivated soles:

Here is the TableTag java file that does all the work
(list is just a simple string value that is coming from a request object)
Pay particular attention to the
ValueStack stack = TagUtils.getStack((PageContext)getJspContext());
stack.findValue(list)
this is where all the processing is occuring

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

package pojo;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;

import org.apache.struts2.views.jsp.TagUtils;

import com.opensymphony.xwork2.util.ValueStack;

public class TableTag extends SimpleTagSupport{
private String list;

public void doTag() throws JspException
{
ValueStack stack = TagUtils.getStack((PageContext)getJspContext());

JspWriter out = getJspContext().getOut();

try {
StringBuffer st = new StringBuffer();
st.append(“This is from the custom tag via request object: ” + stack.findValue(list));

out.println(st.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

public void setList(String list)
{
this.list = list;
}

public String getList() {
return list;
}

}

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Here is the tbl.tld file (just place this file in your web-inf folder

2.2.3
1.2
lab
/lab
“Lab Tags”

tbl
pojo.TableTag
scriptless

list
true
true

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Here is the jsp that has an instance of my tbl.tld file
within the tbl tag I am injecting an instance of the request obj factor which has been set
at the string “yes” within my action class

Struts 2 Login Application!

asdasd

Test:

Test:

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
When a user clicks the submit button the factor request object will populate the tag and then via
ValueStack stack = TagUtils.getStack((PageContext)getJspContext());
the stack.findValue(list)); will evaluate and extract the value
for the jspwriter to display

Test:This is from the custom tag via request object: Yes

Hi,
I want to make reusable component in/for Struts 2 framework. For example, a login form having validations, authentication on form submission, error display, Forgot password link etc. I want to create this form in such a way so that it can be placed anywhere within the site (horizontal at one place and vertical at another place) and in any site without any changes.

Please suggest what should I use or better if you can provide and reference for the example of such type of components.

Thanks
Krishan Babbar

Leave a reply to Krishan Babbar Cancel reply