Velocity is a Project of Apache Software Foundation, it’s released under Apache Velocity Engine where it’s considered as a Template Engine that provides a Template language to reference objects defined in the Java code.
The major aim of Velocity is to ensure clean separation between the presentation tier and business tier in the web application, similar for numerous presentation technologies that we had used before.
However, you’re developed a Portlet using a JSP & Servlet for registering employees and that you were used a JSP as a presentation tier, Standard Portlet as a controller and a Servlet for handling registration business.
The same example would be used this time, with one difference, in that a Velocity Templates and Velocity Portlet would replace your used JSPs and Standard Portlet, respectively.
This tutorial is going to provide you a full-fledged scenario for how you can use Velocity Templates for getting full functional Portlet that can be used for saving your employees against your database.
Project Structure
Here, you’ll get a full depiction for the whole created project:
Employee Table
Before getting started looking into the way in which you can integrate a Velocity templates inside your application, take a glance for the Employee Table that would be used for retaining the employees and the SQL statement that’s used for creating the Table into your database.
Employee.SQL
1 2 3 4 5 6 7 8 9 |
CREATE TABLE `employee` ( `EMP_ID` int(11) NOT NULL AUTO_INCREMENT, `EMP_NAME` varchar(45) DEFAULT NULL, `EMP_JOB` varchar(45) DEFAULT NULL, `EMP_SALARY` int(11) DEFAULT NULL, PRIMARY KEY (`EMP_ID`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; |
Employee Model
According for MVC (Model-View-Controller) design pattern, the data must be retained inside a model, since it will be sent back and forth between the different components in the application (i.e. View & Controller). Since, we have single Employee Table, an Employee model will look like below:
Employee.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
package com.journaldev.data; public class Employee { private int id; private String name; private String job; private int salary; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } } |
RegisterEmployeePortlet Velocity Portlet
Creating of Velocity Portlet isn’t much complicated mission, as you may be familiar with many types of Portlets were introduced here. Like any normal Portlet, your Velocity one should look like below:
RegisterEmployeePortlet.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
package com.journaldev.portlet; import java.io.IOException; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; import javax.portlet.PortletException; import javax.portlet.PortletRequestDispatcher; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; public class RegisterEmployeePortlet extends org.apache.portals.bridges.velocity.GenericVelocityPortlet { public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException { // Check the status parameter if(request.getParameter("status") == null){ // In case it's null, return into default view that's already defined in the portlet.xml viewPage super.doView(request, response); } else { // In case, the status value is success if(request.getParameter("status").equals("success")){ PortletRequestDispatcher dispatcher = this.getPortletContext().getRequestDispatcher("/register/success.vm"); // delegate the view into success.vm dispatcher.include(request, response); } else { // In case, the status value is failure PortletRequestDispatcher dispatcher = this.getPortletContext().getRequestDispatcher("/register/failure.vm"); // delegate the view into failure.vm dispatcher.include(request, response); } } } public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException{ // Create request dispatcher PortletRequestDispatcher dispatcher = this.getPortletContext().getNamedDispatcher("RegisterEmployeeServlet"); try { // Include dispatcher.include(request, response); // Set render parameter response.setRenderParameter("status", "success"); } catch(Exception ex){ // Set render parameter response.setRenderParameter("status", "failed"); response.setRenderParameter("exception", ex.getMessage()); } } } |
Here’s detailed explanation for the code mentioned above:
- Your Portlet should extend org.apache.portals.bridges.velocity.GenericVelocityPortlet.
- Like any standard Portlet, you have a chance of overriding required methods.
- Typically, you have an access for different types of requests/responses.
- As you may delegate the request into your JSP view as it happened in JSP & Servlet Tutorial, you have the ability to do the same thing with the Velocity markup Templates.
- Since we have a default ViewPage value as init param, the calling of super.doView will give the registerEmployee.vm a chance to handle the request.
- According for status parameter, you may get accessed success.vm or failure.vm.
- You can reference your Velocity templates by using their defined path within your project, since they’re considered like any presentation technology you have dealt with. The path that we’ve suggested is /register/registerEmployee.vm, /register/success.vm and /register/faliure.vm.
RegisterEmployeePortlet Velocity Portlet Descriptor
Fortunately, there is not much details that you must be aware of when it comes to define your Portlet inside your Portlet deployment descriptor (Portlet.xml). However, like any Standard Portlet, your Portlet.xml should look like:
portlet.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<?xml version="1.0" encoding="UTF-8"?> <portlet-app xmlns="https://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"> <portlet> <display-name>Register Employee</display-name> <portlet-name>RegisterEmployee</portlet-name> <portlet-class>com.journaldev.portlet.RegisterEmployeePortlet </portlet-class> <description>Employee Registration</description> <init-param> <name>ViewPage</name> <value>/register/registerEmployee.vm</value> </init-param> <supports> <mime-type>text/html</mime-type> <portlet-mode>VIEW</portlet-mode> </supports> <portlet-info> <title>Employee Registration</title> <keywords>employee, registration</keywords> <short-title>Employee Registration</short-title> </portlet-info> </portlet> </portlet-app> |
Here’s detailed explanation for the code typed above:
- You should define ViewPage init param for getting registerEmployee.vm displayed once the Portlet accessed through its contained page.
- Similar for ViewPage, you can add EditPage and HelpPage.
- Supporting different views require you to tune your supports element.
Application Deployment Descriptor & Maven Build File
You may be asking about how the defined Velocity Templates got executed since no explicit declaration for the way in which that is done. In fact and indeed, a defined Servlet will handle the Velocity Templates interpretation process, so once your Portlet had delegated the request into any Velocity resources that ends with the *.vm, the Velocity Servlet get executed and the HTML output has returned. Look below at the deployment descriptor (web.xml):
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "https://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Employee Registration</display-name> <servlet> <servlet-class>com.journaldev.servlet.RegisterEmployeeServlet</servlet-class> <servlet-name>RegisterEmployeeServlet</servlet-name> </servlet> <servlet-mapping> <servlet-name>RegisterEmployeeServlet</servlet-name> <url-pattern>/registerEmployeeServlet</url-pattern> </servlet-mapping> <!-- Define Velocity Servlet --> <servlet> <servlet-name>velocity</servlet-name> <servlet-class>org.apache.portals.bridges.velocity.BridgesVelocityViewServlet</servlet-class> </servlet> <!-- Map *.vm files to Velocity --> <servlet-mapping> <servlet-name>velocity</servlet-name> <url-pattern>*.vm</url-pattern> </servlet-mapping> </web-app> |
As you can notice, BridgesVelocityServlet has used in conjunction with the mapping element. Let’s glance the used Maven build file:
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.journaldev</groupId> <artifactId>VelocityBridge</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>VelocityBridge</name> <url>https://maven.apache.org</url> <properties> <deployFolder>D:/Apache Pluto/pluto-2.0.3/webapps</deployFolder> </properties> <dependencies> <!-- Java Portlet Specification V2.0 --> <dependency> <groupId>org.apache.portals</groupId> <artifactId>portlet-api_2.0_spec</artifactId> <version>1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.7.0</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.1</version> </dependency> <dependency> <groupId>commons-digester</groupId> <artifactId>commons-digester</artifactId> <version>1.7</version> </dependency> <dependency> <groupId>commons-digester</groupId> <artifactId>commons-digester</artifactId> <version>1.7</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.5</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-tools</artifactId> <version>2.0</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.apache.pluto</groupId> <artifactId>pluto-taglib</artifactId> <version>1.1.7</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.32</version> </dependency> <dependency> <groupId>org.apache.portals.bridges</groupId> <artifactId>portals-bridges-velocity</artifactId> <version>2.0</version> </dependency> <dependency> <groupId>org.apache.portals.bridges</groupId> <artifactId>portals-bridges-common</artifactId> <version>2.0</version> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> <plugins> <!-- bind 'pluto2:assemble' goal to 'process-resources' lifecycle --> <!-- This plugin will read your portlet.xml and web.xml and injects required lines --> <plugin> <groupId>org.apache.portals.pluto</groupId> <artifactId>maven-pluto-plugin</artifactId> <version>2.1.0-M3</version> <executions> <execution> <phase>generate-resources</phase> <goals> <goal>assemble</goal> </goals> </execution> </executions> </plugin> <!-- configure maven-war-plugin to use updated web.xml --> <!-- This plugin will make sure your WAR will contain the updated web.xml --> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.1.1</version> <configuration> <webXml>${project.build.directory}/pluto-resources/web.xml</webXml> </configuration> </plugin> <plugin> <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> <id>copy</id> <phase>integration-test</phase> <configuration> <tasks> <copy file="target/${project.artifactId}.war" tofile="${deployFolder}/${project.artifactId}.war" /> </tasks> </configuration> <goals> <goal>run</goal> </goals> </execution> <execution> <id>delete</id> <phase>clean</phase> <configuration> <tasks> <delete file="${deployFolder}/${project.artifactId}.war" /> <delete dir="${deployFolder}/${project.artifactId}" /> </tasks> <detail>true</detail> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> </project> |
Velocity Templates (Views)
As we’ve stated earlier, you can use a Velocity Templates instead of using default JSP for rendering your requested view. Similar for JSP, an implicit objects have been defined inside your Velocity Templates for getting used while you’re developing your views. Let’s look at the created views and see the major things that must be noticed.
registeremployee.vm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Register Employee</title> </head> <body> <form action="$renderResponse.createActionURL()" method="POST"> <table width="100%"> <tr width="60%"> <td>Enter Employee ID:</td> <td><input name="employeeID" /></td> </tr> <tr width="60%"> <td>Enter Employee Name:</td> <td><input name="employeeName" /></td> </tr> <tr width="60%"> <td>Enter Employee Job:</td> <td><input name="employeeJob" /></td> </tr> <tr width="60%"> <td>Enter Employee Salary:</td> <td><input name="employeeSalary" /></td> </tr> <tr width="60%" align="center"> <td colspan="2"><input type="submit" value="Register" /></td> </tr> </table> </form> </body> </html> |
Here’s detailed explanation for the code listed above:
- Implicit objects that you may need are, RenderRequest, RenderResponse & PortletConfig.
- You should use $renderRequest, $renderResponse & $portletConfig for getting referenced these objects, respectively.
- Since these objects are Java Objects, so you have them with all accompanies relevant functions, just like you’re invoked them from within your Standard Portlet.
- We created an actionUrl by calling $renderResponse.createActionURL().
success.vm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Register Employee</title> </head> <portlet:renderURL var="registerAnother"> <portlet:param name="status" value="initiate"/> </portlet:renderURL> <img src="https://www.journaldev.com/5099/$renderRequest.getContextPath()/images/success.jpg" name="$renderResponse.getNamespace()Success"/> <body> <span>Congratulations ! you've just add a new employee</span><br/><a href="$renderResponse.createRenderURL()">Register Another</a> </body> </html> |
failure.vm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Register Employee</title> </head> <body> <span>Unfortunately ! you may not be able of registering a new employee cause the reason below</span> <br/> <br/> <img src="https://www.journaldev.com/5099/$renderRequest.getContextPath()/images/failed.jpg" name="$renderResponse.getNamespace()Failed"/> <span style="font-size:small ;font-style: italic;color: red;font-weight: bold;"> $renderRequest.getParameter("exception") </span> <br/> <br/> <a href="$renderResponse.createRenderURL()">Try Again</a> </body> </html> |
Here’s detailed explanation for both of success and failure velocity templates:
- We used $renderRequest.getContextPath() for specifying the context of the running application.
- For getting safe code, since the Velocity Templates may contain the same JavaScript variable/code, you have the opportunity of making a unique identifier using $renderReponse.getNamespace().
- You have the ability to get accessed specific request attributes by calling of $renderRequest.getParamater().
- $renderResponse().createRenderURL() is used for rendering a render request against your Portlet.
Register Employee Business Handler
Handling of employee registration business isn’t a Portlet mission, as it’s considered like controller when it comes to map your components into MVC design. Regardless, of the type of Portlet you were used, we have a separate Servlet that’s responsible of handling the registration process; extract the request’s parameters and calling the database utilities for got employee saved.
RegisterEmployeeServlet.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package com.journaldev.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import com.journaldev.dao.EmployeeDAO; import com.journaldev.data.Employee; public class RegisterEmployeeServlet extends HttpServlet { private static final long serialVersionUID = 1L; Logger logger = Logger.getLogger(RegisterEmployeeServlet.class); public RegisterEmployeeServlet() { super(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Create employee Employee employee = new Employee(); // Fill in required data from the request sent employee.setId(Integer.parseInt(request.getParameter("employeeID"))); employee.setName(request.getParameter("employeeName")); employee.setJob(request.getParameter("employeeJob")); employee.setSalary(Integer.parseInt(request.getParameter("employeeSalary"))); try { // Asking employeeDAO creating the employee against registered database Employee createdEmployee = EmployeeDAO.getInstance().createEmployee(employee); // Print out the created employee information logger.info("Employee Created"+createdEmployee); } catch (Exception e) { // Log the exception logger.error("Employee Creation Failed", e); // Throw another exception for notifying the Portlet throw new ServletException(e); } } } |
Database Utility
Since our application has accessed the database for getting employee instance persisted, it’s important to handle the database code with the best practice we have own, EmployeeDAO & ConnectionUtility are both classes used for accessing the database, safely and asynchronously.
EmployeeDAO.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
package com.journaldev.dao; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import com.journaldev.dao.utility.ConnectionUtility; import com.journaldev.data.Employee; public class EmployeeDAO { public static EmployeeDAO employeeDAO = null; private EmployeeDAO(){ } public static EmployeeDAO getInstance(){ synchronized(EmployeeDAO.class){ if(employeeDAO == null){ employeeDAO = new EmployeeDAO(); } } return employeeDAO; } public Employee createEmployee(Employee employee) throws SQLException, IllegalAccessException, IOException, ClassNotFoundException{ // Get connection instance Connection connection = ConnectionUtility.getInstance().getConnection(); // Create Prepared Statement PreparedStatement query = connection.prepareStatement("INSERT INTO EMPLOYEE VALUES (?,?,?,?)"); // Set variables query.setInt(1, employee.getId()); query.setString(2, employee.getName()); query.setString(3, employee.getJob()); query.setInt(4, employee.getSalary()); try { // Execute query.execute(); // Return employee instance return employee; } catch(Exception e){ // Close statement query.close(); // Close connection connection.close(); // Throw another exception for notifying the Servlet throw new SQLException(e); } } public boolean deleteEmployee(Employee employee){ return false; } public boolean updateEmployee(Employee employee, int employeeId){ return false; } } |
ConnectionUtility.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
package com.journaldev.dao.utility; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; public class ConnectionUtility { private static ConnectionUtility connectionUtiliy = null; private Connection connection = null; private ConnectionUtility() { } public static ConnectionUtility getInstance() throws IOException, IllegalAccessException, SQLException, ClassNotFoundException{ // Synchronized against connectionUtility instance synchronized(ConnectionUtility.class){ // Check whether the connectionUtility is null or not if(connectionUtiliy == null){ // Create a properties instance Properties properties = new Properties(); // Load properties from classpath properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("connection.properties")); // Set connection with connectionUtility connectionUtiliy = new ConnectionUtility(); // Load driver class Class.forName("com.mysql.jdbc.Driver"); // Create connection connectionUtiliy.setConnection(DriverManager.getConnection("jdbc:mysql://localhost:3306/journaldev", properties)); } return connectionUtiliy; } } public Connection getConnection() throws ClassNotFoundException, SQLException, IOException { if(connection.isClosed()){ // Create a properties instance Properties properties = new Properties(); // Load properties from classpath properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("connection.properties")); // Load driver class Class.forName("com.mysql.jdbc.Driver"); // Create connection connectionUtiliy.setConnection(DriverManager.getConnection("jdbc:mysql://localhost:3306/journaldev", properties)); } return connection; } public void setConnection(Connection connection) { this.connection = connection; } } |
Employee Registration Demo
We assumed that you have a running instance of Apache Pluto as you are also created a Portal page named JournalDev and you’re also familiar with the way which can be used for deploying your Portlet into your Portal page. In case, you’ve heard this for the first time, it’s worth for you to return back into our Apache Pluto Introduction for get everything relevant done.
Once the user has activated the register action, the Portlet’s processAction method has been executed and the Register Servlet would be invoked. The user will be informed instantly with the result of registration operation and whether it’s got finished successfully or not.
Now, what’s happened just in case you’ve tried to register another employee with the same identifier:
Summary
It’s fantastic, as you can create whatever you want of Portlets using the standard Portlet container specification. You’ve already faced a JSP & Servlet, PHP, JSF, Struts & now a Velocity Templates one. Your comments or notes are highly appreciated as you can find the downloaded source listed below for your practice.