Apache Velocity is an open-source java-based templating engine that can play as an alternative to JSP (Jakarta server pages). It is helpful to generate XML files, SQL, etc., In this article, let us see the creation of dynamic web pages.
Working way of Velocity:
- Velocity engine initialization
- Reading the template
- Putting the data model in the context object
- Finally merging the template with context data and rendering the view
Essentially we need to see what are dependencies needed to use apache velocity
<dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.7</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-tools</artifactId> <version>2.0</version> </dependency>
Velocity Template Language (VTL) reference starts with $ for getting a value and for setting the value # is used. Let us see how to use variables, properties, and methods
variables
#set ($<your message>="Welcome to GeeksForGeeks") // To set a message
properties
$product.productName //(To get a product name)
methods
$product.getProductName()
Finally, the result is rendered as a string. Let us see the whole concept by using a sample maven project.
Example Maven Project
Project Structure:
Let us start with pom.xml as all dependencies need to be given there
pom.xml
XML
<? xml version = "1.0" encoding = "UTF-8" ?> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 < modelVersion >4.0.0</ modelVersion > < artifactId >apache-velocity</ artifactId > < version >0.1-SNAPSHOT</ version > < name >apache-velocity</ name > < packaging >war</ packaging > < parent > < groupId >com.gfg</ groupId > < artifactId >parent-modules</ artifactId > < version >1.0.0-SNAPSHOT</ version > </ parent > < dependencies > < dependency > < groupId >org.apache.velocity</ groupId > < artifactId >velocity</ artifactId > < version >${velocity-version}</ version > </ dependency > < dependency > < groupId >org.apache.velocity</ groupId > < artifactId >velocity-tools</ artifactId > < version >${velocity-tools-version}</ version > </ dependency > < dependency > < groupId >org.apache.httpcomponents</ groupId > < artifactId >httpclient</ artifactId > < version >${org.apache.httpcomponents.version}</ version > < scope >test</ scope > < exclusions > < exclusion > < artifactId >commons-logging</ artifactId > < groupId >commons-logging</ groupId > </ exclusion > </ exclusions > </ dependency > </ dependencies > < build > < finalName >apache-velocity</ finalName > < resources > < resource > < directory >src/main/resources</ directory > < filtering >true</ filtering > </ resource > </ resources > < plugins > < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-war-plugin</ artifactId > < version >3.3.2</ version > < configuration > < failOnMissingWebXml >false</ failOnMissingWebXml > </ configuration > </ plugin > </ plugins > </ build > < properties > < org.apache.httpcomponents.version >4.5.2</ org.apache.httpcomponents.version > < velocity-version >1.7</ velocity-version > < velocity-tools-version >2.0</ velocity-tools-version > </ properties > </ project > |
Let us write the java code involving model, service, and servlet classes first
OnlineProductSale.java
Java
public class OnlineProductSale { private String productName; private double productPrice; public OnlineProductSale(String productName, double productPrice) { this .productName = productName; this .productPrice = productPrice; } public String getProductName() { return productName; } public void setProductName(String productName) { this .productName = productName; } public double getProductPrice() { return productPrice; } public void setProductPrice( double productPrice) { this .productPrice = productPrice; } @Override public String toString() { return "OnlineProductSale{" + "productName='" + productName + '\ '' + ", productPrice=" + productPrice + '}' ; } } |
OnlineProductService.java
Java
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.gfg.model.OnlineProductSale; import java.util.Arrays; import java.util.List; public class OnlineProductService { Logger logger = LoggerFactory.getLogger(OnlineProductService. class ); public List<OnlineProductSale> getOnlineProductsForSale() { logger.debug( "Product service returning list of products" ); return Arrays.asList( new OnlineProductSale( "Dell Laptop" , 31000.00 ), new OnlineProductSale( "Samsung Mobile" , 16000.00 ), new OnlineProductSale( "Samsung Tablet" , 15000.00 ), new OnlineProductSale( "Sony Camera" , 23000.00 )); } } |
OnlineProductServlet.java
Java
package com.gfg.servlet; import com.gfg.model.OnlineProductSale; import com.gfg.service.OnlineProductService; import org.apache.velocity.Template; import org.apache.velocity.context.Context; import org.apache.velocity.tools.view.VelocityViewServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.List; public class OnlineProductServlet extends VelocityViewServlet { OnlineProductService service = new OnlineProductService(); @Override public Template handleRequest(HttpServletRequest request, HttpServletResponse response, Context context) { Logger logger= LoggerFactory.getLogger(OnlineProductServlet. class ); List<OnlineProductSale> onlineProductsForSale = service.getOnlineProductsForSale(); context.put( "products" , onlineProductsForSale); Template template = null ; try { // Referring the index.vm present // under templates directory template = getTemplate( "templates/index.vm" ); response.setHeader( "Template Returned" , "Success" ); } catch (Exception e) { logger.error( "Error while reading the template " , e); } return template; } } |
SampleLayoutServlet.java
Java
import com.gfg.model.OnlineProductSale; import com.gfg.service.OnlineProductService; import org.apache.velocity.Template; import org.apache.velocity.context.Context; import org.apache.velocity.tools.view.VelocityLayoutServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.List; public class SampleLayoutServlet extends VelocityLayoutServlet { OnlineProductService service = new OnlineProductService(); @Override public Template handleRequest(HttpServletRequest request, HttpServletResponse response, Context context) { Logger logger= LoggerFactory.getLogger(SampleLayoutServlet. class ); List<OnlineProductSale> onlineProductsForSale = service.getOnlineProductsForSale(); context.put( "products" , onlineProductsForSale); Template template = null ; try { // Referring layoutdemo.vm from templates folder template = getTemplate( "templates/layoutdemo.vm" ); response.setHeader( "Template Returned" , "Success" ); } catch (Exception e) { logger.error( "Error while reading the template " ,e); } return template; } } |
index.vm
HTML
< HTML > < HEAD > < TITLE >Online Electronic Store</ TITLE > < style > body {background-color: Aqua;} h1 {color: green;} p {color: red;} table.gridtable { font-family: verdana,arial,sans-serif; font-size:11px; color:#333333; border-width: 1px; border-color: #666666; border-collapse: collapse; } table.gridtable th { border-width: 1px; padding: 8px; border-style: solid; border-color: #666666; background-color: #dedede; } table.gridtable td { border-width: 1px; padding: 8px; border-style: solid; border-color: #666666; background-color: #ffffff; } </ style > </ HEAD > < BODY > < CENTER > < h1 >Today's Offers</ h1 > < BR /> < BR /> < h2 >$products.size() Products are available for Sale today!</ h2 > < BR /> Welcome to our store for exiting prices < BR /> < BR /> #set( $count = 1 ) < TABLE class = "gridtable" > < TR > < TH >Serial #</ TH >< TH >Product Name</ TH >< TH >Price</ TH > </ TR > #foreach( $product in $products ) < TR > < TD >$count)</ TD > < TD >$product.getProductName()</ TD > < TD >$product.getProductPrice()</ TD > </ TR > #set( $count = $count + 1 ) #end </ TABLE > < BR /> </ CENTER > </ BODY > </ HTML > |
If we look at the vm file, we are seeing the ways of setting the value by using
#set( $count = 1 ) -- Here count is a variable assigned with value 1
Similarly to display the retrieved value (i.e. get values, by using
$product.getProductName() // To get the product name $product.getProductPrice() // To get the product price
In order to run the loop, we have to do the following
// almost it is similar like java code only #foreach( $product in $products ) <TR> <TD>$count)</TD> <TD>$product.getProductName()</TD> <TD>$product.getProductPrice()</TD> </TR> #set( $count = $count + 1 ) #end
Let us see the important web.xml (configuration file) and then run the program. VelocityViewServlet configuration in web.xml has to be done
web.xml
XML
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" < web-app > < display-name >apache-velocity</ display-name > < servlet > < servlet-name >OnlineProductServlet</ servlet-name > < servlet-class >com.gfg.servlet.OnlineProductServlet</ servlet-class > </ servlet > < servlet > < servlet-name >SampleLayoutServlet</ servlet-name > < servlet-class >com.gfg.servlet.SampleLayoutServlet</ servlet-class > </ servlet > <!-- This is much required to use VelocityViewServlet in the web.xml.--> < servlet > < servlet-name >velocityLayout</ servlet-name > < servlet-class >org.apache.velocity.tools.view.VelocityLayoutServlet</ servlet-class > < init-param > < param-name >org.apache.velocity.properties</ param-name > < param-value >/WEB-INF/velocity.properties</ param-value > </ init-param > </ servlet > <!-- This is much required to use VelocityViewServlet in the web.xml.--> < servlet-mapping > < servlet-name >OnlineProductServlet</ servlet-name > < url-pattern >/</ url-pattern > </ servlet-mapping > < servlet-mapping > < servlet-name >SampleLayoutServlet</ servlet-name > < url-pattern >/layout</ url-pattern > </ servlet-mapping > <!-- This is much required to use VelocityViewServlet in the web.xml.--> < servlet-mapping > < servlet-name >velocityLayout</ servlet-name > <!-- we need to see .vm file to be referred --> < url-pattern >*.vm</ url-pattern > </ servlet-mapping > <!-- This is much required to use VelocityViewServlet in the web.xml.--> <!-- session timeout --> < session-config > < session-timeout > 30 </ session-timeout > </ session-config > <!-- welcome file --> < welcome-file-list > < welcome-file >index.html</ welcome-file > </ welcome-file-list > </ web-app > |
WEB-INF/layout.properties
resource.loader=webapp webapp.resource.loader.class=org.apache.velocity.tools.view.WebappResourceLoader webapp.resource.loader.path = webapp.resource.loader.cache = true
On running the program on tomcat, we can see the below output
XML
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" < web-app > < display-name >apache-velocity</ display-name > < servlet > < servlet-name >OnlineProductServlet</ servlet-name > < servlet-class >com.gfg.servlet.OnlineProductServlet</ servlet-class > </ servlet > < servlet > < servlet-name >SampleLayoutServlet</ servlet-name > < servlet-class >com.gfg.servlet.SampleLayoutServlet</ servlet-class > </ servlet > <!-- This is much required to use VelocityViewServlet in the web.xml.--> < servlet > < servlet-name >velocityLayout</ servlet-name > < servlet-class >org.apache.velocity.tools.view.VelocityLayoutServlet</ servlet-class > < init-param > < param-name >org.apache.velocity.properties</ param-name > < param-value >/WEB-INF/velocity.properties</ param-value > </ init-param > </ servlet > <!-- This is much required to use VelocityViewServlet in the web.xml.--> < servlet-mapping > < servlet-name >OnlineProductServlet</ servlet-name > < url-pattern >/</ url-pattern > </ servlet-mapping > < servlet-mapping > < servlet-name >SampleLayoutServlet</ servlet-name > < url-pattern >/layout</ url-pattern > </ servlet-mapping > <!-- This is much required to use VelocityViewServlet in the web.xml.--> < servlet-mapping > < servlet-name >velocityLayout</ servlet-name > <!-- we need to see .vm file to be referred --> < url-pattern >*.vm</ url-pattern > </ servlet-mapping > <!-- This is much required to use VelocityViewServlet in the web.xml.--> <!-- session timeout --> < session-config > < session-timeout > 30 </ session-timeout > </ session-config > <!-- welcome file --> < welcome-file-list > < welcome-file >index.html</ welcome-file > </ welcome-file-list > </ web-app > |
As a good practice let us test the same via our testcases as well
OnlineProductServletLiveTest.java
Java
import static org.junit.Assert.assertEquals; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.junit.Test; public class OnlineProductServletLiveTest { @Test public void whenRequestUsingHttpClient_thenCorrectResponse() throws Exception { HttpClient httpClient = new DefaultHttpClient(); HttpResponse httpResponse = httpClient.execute(method); assertEquals( "Success" , httpResponse.getHeaders( "Template Returned" )[ 0 ].getValue()); } } |
Output of JUnit:
Conclusion
Rendering of dynamic web pages is easier via Apache Velocity and in the software industry, it is widely used.