Customizing JSPs with Dynamic Includes
The
liferay-util:dynamic-include
tag
is a placeholder into which you can inject content—JavaScript code, HTML,
and more. The example project demonstrates how to inject content with a dynamic include.
Deploy the Example Project
Start a new Liferay DXP instance by running
docker run -it -m 8g -p 8080:8080 liferay/dxp:2025.q1.6-lts
Sign in to Liferay at http://localhost:8080 using the email address test@liferay.com and the password test. When prompted, change the password to learn.
Then, follow these steps:
-
Download and unzip Customizing JSPs with Dynamic Includes.
curl https://resources.learn.liferay.com/examples/liferay-n3q9.zip -O
unzip liferay-n3q9.zip
-
From the module root, build and deploy.
./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
NoteThis command is the same as copying the deployed jars to /opt/liferay/osgi/modules on the Docker container.
-
Confirm the deployment in the Liferay Docker container console.
STARTED com.acme.n3q9.able.web_1.0.0 [1459] STARTED com.acme.n3q9.baker.web_1.0.0 [1460]
-
Verify that the example module works. Open your browser to
https://localhost:8080
. -
Navigate to a Site page and click the Edit icon (
). Add the N3Q9 Baker Portlet to the page. The widget can be found under Sample widgets.
Note how the first two lines come from the N3Q9 Baker Portlet, but the third line is injected from N3Q9 Able module’s dynamic include. This example is composed of two parts:
-
A JSP portlet that names and inserts a dynamic include into a specific line as a placeholder
-
An OSGi module that implements the dynamic include, replacing the placeholder line from the portlet with new JSP code
These modules are useful in different circumstances, and it is important to understand both to implement dynamic includes properly.
Implement the Dynamic Include
The most common use for dynamic includes is to add custom code to Liferay’s default pages and applications without overwriting them entirely. Liferay’s out-of-the-box code contains dynamic includes in places where you might want additional resources, HTML elements, editor modifications, and more. Once you know the dynamic include’s key, you can use it to create a module and inject your content.
-
Declare the class as an implementation of
DynamicInclude
with the@Component
annotation.@Component(service = DynamicInclude.class)
-
In the
include
method, add your custom content. The sample project uses a simplePrintWriter
example.
@Override
public void include(
HttpServletRequest request, HttpServletResponse response,
String key)
throws IOException {
PrintWriter printWriter = response.getWriter();
printWriter.println("<h3>Added by N3Q9 Able dynamic include.</h3>");
}
- In the
register
method, specify the dynamic include tag to use. In the sample, the register method targets the dynamic include of Baker module’sview.jsp
.
@Override
public void register(DynamicIncludeRegistry dynamicIncludeRegistry) {
dynamicIncludeRegistry.register("com.acme.n3q9.baker.web#view.jsp");
}
Insert A Dynamic Include
Traditionally, to make a change in the JSP of an out-of-the-box Liferay portlet, you must rewrite it entirely. This gives you full control over the entire portlet, but is difficult to manage. When you upgrade your Liferay instance, Liferay’s changes to the default portlet can conflict with your custom implementation.
If your customization contains several lines of code, it can be challenging to keep the native code separate and up-to-date. Instead, you can insert a dynamic include where you want your customizations to go and implement it in a separate module. This way, you update the portlet by adding a single line of custom code into the default JSP.
To do this, add the liferay-util:dynamic-include
tag where you want the dynamic include to be injected. In the sample, the tag is added to the bottom of N3Q9 Baker Portlet’s view.jsp
.
<%@ taglib uri="http://liferay.com/tld/util" prefix="liferay-util" %>
<h2>N3Q9 Baker Portlet</h2><br />
<h3>Hello N3Q9 Baker.</h3><br />
<liferay-util:dynamic-include key="com.acme.n3q9.baker.web#view.jsp" />
Make sure the dynamic include key
matches the target set in the register()
method above.