Lesson 4.2: Using Velocity with WebWork

There are two ways of using Velocity as the view.

  • Using the velocity result-type to render velocity templates;
  • Registering WebWorkVelocityServlet in your web.xml file to render Velocity templates accessed directly through browser requests.

To use the second approach, we have to modify web.xml and add a servlet and a servlet mapping for WebWorkVelocityServlet, as demonstrated below:

<servlet> 
	<servlet-name>velocity</servlet-name> 
	<servlet-class>com.opensymphony.webwork.views.velocity.WebWorkVelocityServlet</servlet-class> 
	<load-on-startup>1</load-on-startup> 
</servlet> 

<servlet-mapping> 
	<servlet-name>velocity</servlet-name> 
	<url-pattern>*.vm</url-pattern> 
</servlet-mapping>

Read more: xwork.xml

Using velocity result-type means that Velocity templates can only be rendered through an action, i.e., request to .vm pages will not render the file and it will be returned as plain text. If you choose this approach, it's recommended that you place your Velocity files under WEB-INF so they become unaccessible.

Using WebWorkVelocityServlet means that Velocity templates can be rendered through requests to .vm pages. That also means that you should implement security checks in your templates so an user doesn't access it directly witout going through an action first (if that is required).

No matter which approach you choose (and you can choose to use both at the same time), not only all the features from Velocity are available to you when you're writing templates, but also some other functionalities, specific of WebWork, are available. It is supposed that you are already familiar with Velocity, so we will focus only in the WebWork-specific features. If that's not the case, please get started with Velocity before continuing.

The main feature of it is to provide easy access to objects that are on the Value Stack, which contains some things that WebWork provides to you automatically, because you may find them useful at some point. These are some of the things that are available in the value stack:

  • The current HttpServletRequest;
  • The current HttpServletResponse;
  • The current OgnlValueStack;
  • An instance of OgnlTool;
  • All the properties of the current action class.

To access the objects in the value stack, all you have to do is use appropriate Velocity references:

  • $req = HttpServletRequest;
  • $res = HttpServletResponse;
  • $stack = OgnlValueStack;
  • $ognl = OgnlTool;
  • $name-of-property = property of the current action class.

The example below does the same thing as the Hello example from lesson 3, but now, using a Velocity template as the result. Notice that the <property value="person" /> tag was replaced by the $person reference, which returns the same thing: a property from the action class. In this example we chose to use the velocity result-type approach.

xwork.xml:

<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" 
"http://www.opensymphony.com/xwork/xwork-1.0.dtd">

<xwork>
	<!-- Include webwork defaults (from WebWork JAR). -->
	<include file="webwork-default.xml" />
	
	<!-- Configuration for the default package. -->
	<package name="default" extends="webwork-default">
		<!-- Default interceptor stack. --> 
		<default-interceptor-ref name="defaultStack" /> 
		
		<!-- Action: Lesson 4.2: HelloAction using Velocity as result. -->
		<action name="helloVelocity" class="lesson03.HelloAction">
			<result name="error" type="dispatcher">ex01-index.jsp</result>
			<result name="success" type="velocity">ex01-success.vm</result>
		</action>
	</package>
</xwork>

HelloAction.java (same as lesson 3):

package lesson03;

import com.opensymphony.xwork.ActionSupport;

public class HelloAction extends ActionSupport {
	String person;
	public String getPerson() {
		return person;
	}
	public void setPerson(String person) {
		this.person = person;
	}
	public String execute() throws Exception {
		if ((person == null) || (person.length() == 0)) return ERROR;
		else return SUCCESS;
	}
}

ex01-index.jsp (same as lesson 3):

<html>
<head>
<title>WebWork Tutorial - Lesson 3 - Example 2</title>
</head>

<body>

<p>What's your name?</p>

<form action="helloVelocity.action" method="post">
<p><input type="text" name="person" /><input type="submit" /></p>
</form>

</body>
</html>

ex01-success.vm:

<html> 
<head> 
<title>WebWork Tutorial - Lesson 4.2 - Example 1</title> 
</head> 
<body> 

Hello, $person 

</body> 
</html>

Try the example!

Using WebWork Tags from Velocity:

As you already know, when you switch from JSP to Velocity you lose the ability of using JSP Tags. But WebWork's Velocity Servlet provides a way of doing this through the use of #tag, #bodytag and #param velocimacros. The general syntax is:

#tag (name-of-tag list-of-attributes)

– or –

#bodytag (name-of-tag list-of-attributes)
	#param (key value)
	#param (key value)
...
#end

Let's revisit lesson 4.1.1's form example to demonstrate the usage of the UI tags from velocity:

xwork.xml:

<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" 
"http://www.opensymphony.com/xwork/xwork-1.0.dtd">

<xwork>
	<!-- Include webwork defaults (from WebWork JAR). -->
	<include file="webwork-default.xml" />
	
	<!-- Configuration for the default package. -->
	<package name="default" extends="webwork-default">
		<!-- Default interceptor stack. --> 
		<default-interceptor-ref name="defaultStack" /> 
		
		<!-- Actions: Lesson 4.2: FormProcessingAction using Velocity. --> 
		<action name="formProcessingVelocityIndex" class="lesson04_02.FormProcessingIndexAction">
			<result name="success" type="velocity">ex02-index.vm</result>
		</action>
		<action name="formProcessingVelocity" class="lesson04_01_01.FormProcessingAction"> 
			<result name="input" type="velocity">ex02-index.vm</result> 
			<result name="success" type="velocity">ex02-success.vm</result> 
			<interceptor-ref name="validationWorkflowStack" /> 
		</action> 
	</package>
</xwork>

ex02-index.vm:

<html> 
<head> 
<title>WebWork Tutorial - Lesson 4.2 - Example 2</title> 
<style type="text/css"> 
  .errorMessage { color: red; } 
</style>   
</head> 

<body> 

<p>UI Form Tags Example using Velocity:</p> 

#bodytag (Form "action='formProcessingVelocity.action'" "method='post'") 
	#tag (Checkbox "name='checkbox'" "label='A checkbox'" "fieldValue='checkbox_value'") 
	#tag (File "name='file'" "label='A file field'") 
	#tag (Hidden "name='hidden'" "value='hidden_value'") 
	#tag (Label "label='A label'") 
	#tag (Password "name='password'" "label='A password field'") 
	#tag (Radio "name='radio'" "label='Radio buttons'" "list={'One', 'Two', 'Three'}") 
	#tag (Select "name='select'" "label='A select list'" "list={'One', 'Two', 'Three'}" 
		"emptyOption=true") 
	#tag (Textarea "name='textarea'" "label='A text area'" "rows='3'" "cols='40'") 
	#tag (TextField "name='textfield'" "label='A text field'") 
	#tag (Submit "value='Send Form'") 
#end 

</body> 
</html>

ex02-success.vm:

<html> 
<head> 
<title>WebWork Tutorial Lesson 4.2 - Example 2</title> 
</head> 

<body> 

<p>UI Form Tags Example result using Velocity:</p> 

<ul> 
	<li>checkbox: $!checkbox</li> 
	<li>file: $!file</li> 
	<li>hidden: $!hidden</li> 
	<li>password: $!password</li> 
	<li>radio: $!radio</li> 
	<li>select: $!select</li> 
	<li>textarea: $!textarea</li> 
	<li>textfield: $!textfield</li> 
</ul> 

</body> 
</html>

FormProcessingAction.java (same as lesson 4.1.1):

package lesson04_01_01;

import com.opensymphony.xwork.ActionSupport;

public class FormProcessingAction extends ActionSupport {
	private String checkbox;
	private String file;
	private String hidden;
	private String password;
	private String radio;
	private String select;
	private String textarea;
	private String textfield;
	
	public String getCheckbox() { return checkbox; }
	public String getFile() { return file; }
	public String getHidden() { return hidden; }
	public String getPassword() { return password; }
	public String getRadio() { return radio; }
	public String getSelect() { return select; }
	public String getTextarea() { return textarea; }
	public String getTextfield() { return textfield; }
	
	public void setCheckbox(String checkbox) { this.checkbox = checkbox; }
	public void setFile(String file) { this.file = file; }
	public void setHidden(String hidden) { this.hidden = hidden; }
	public void setPassword(String password) { this.password = password; }
	public void setRadio(String radio) { this.radio = radio; }
	public void setSelect(String select) { this.select = select; }
	public void setTextarea(String textarea) { this.textarea = textarea; }
	public void setTextfield(String textfield) { this.textfield = textfield; }
	
	public String execute() throws Exception {
		return SUCCESS;
	}
}

FormProcessingAction-validation.xml (same as lesson 4.1.1):

<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 
1.0//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.dtd">

<validators>
  <field name="checkbox">
    <field-validator type="requiredstring">
      <message>Please, check the checkbox.</message>
    </field-validator>
  </field>

  <field name="file">
    <field-validator type="requiredstring">
      <message>Please select a file.</message>
    </field-validator>
  </field>

  <field name="password">
    <field-validator type="requiredstring">
      <message>Please type something in the password field.</message>
    </field-validator>
  </field>

  <field name="radio">
    <field-validator type="requiredstring">
      <message>Please select a radio button.</message>
    </field-validator>
  </field>

  <field name="select">
    <field-validator type="requiredstring">
      <message>Please select an option from the list.</message>
    </field-validator>
  </field>

  <field name="textarea">
    <field-validator type="requiredstring">
      <message>Please type something in the text area.</message>
    </field-validator>
  </field>

  <field name="textfield">
    <field-validator type="requiredstring">
      <message>Please type something in the text field.</message>
    </field-validator>
  </field>
</validators>

Try the example!

The example above does not use the #param tag. So, let's revisit another example from lesson 4.1.1 - custom components:

ex03.vm:

<html> 
<head> 
<title>WebWork Tutorial - Lesson 4.2 - Example 3</title> 
</head> 

<body> 

<p>Custom Component Example:</p> 

<p> 
#bodytag (Component "template=datefield.vm") 
	#param ("label" "Date") 
	#param ("name" "mydatefield") 
	#param ("size" "3") 
#end 
</p> 

</body> 
</html>

/template/xhtml/datefield.vm (same as lesson 4.1.1):

#set ($name = $parameters.get('name')) 
#set ($size = $parameters.get('size')) 
#set ($yearSize = $size * 2) 

$parameters.get('label'): 
<input type="text" name="${name}.day" size="$size" /> / 
<input type="text" name="${name}.month" size="$size" /> / 
<input type="text" name="${name}.year" size="$yearSize" /> (dd/mm/yyyy)

Notice that, this time, we did not enclose Date and mydatefield with single quotes, as we had to do when we used the JSP tag.

Try the example!


Previous Lesson | Next Lesson