Liferay Core JSP Override

Liferay Core JSP Override

Core JSP Override Using Custom JSP Bag


Overview


We often need to customize the portal appearance. For styling customization we can use custom themes or style books, for business-logic adjustments - service wrappers or portlet filters. But when we need to change what is displayed on the page (make changes to the markup itself) - we need to override the portal JSP files. Fortunately, there are extension points for this. For core JSPs we can use a Custom JSP Bag. 


What is a Core JSP?


Liferay 7 has a modular architecture. 

Previously (Liferay 6.2 and below versions) had a monolith one: Liferay was a single web application deployed to webapps/ROOT. All the JSP files were stored in webapps/ROOT/html folder. For these JSPs customization there was a “JSP hook” approach. 

In Liferay 7 most of these JSPs were moved to separate modules. Remaining JSPs, which are still inside webapps/ROOT/html folder are considered as “Core JSPs”:


For these JSPs we can use the “Core JSP Override” approach. While for other JSPs, moved to individual modules - we need a Module JSP Override way.


What is a Custom JSP Bag?


Liferay provides a CustomJspBag interface, which is an extension point to define custom JSP files to overwrite the Liferay core ones. It defines special methods for this:


public String getCustomJspDir();

public List<String> getCustomJsps();

There is also a BaseCustomJspBag class, which implements CustomJspBag and can be used by developers to define their own Custom JSP Bag.



How to implement a Custom JSP Bag?


To implement a Custom JSP Bag we need to create a module in the Liferay Workspace, sample:



Bundle bnd.bnd descriptor is quite simple: 


Bundle-Name: LifeDev Core JSP Override

Bundle-SymbolicName: com.lifedev.core.jsp.override

Bundle-Version: 1.0.0


As well as Gradle dependencies file  build.gradle:


dependencies {

  compileOnly group: "com.liferay.portal", name: "release.portal.api"

}


Then we need to create a Custom JSP Bag - an OSGi component, which implements (directly or indirectly) the com.liferay.portal.deploy.hot.CustomJspBag interface. In this sample we created a LifeDevCustomJspBag class, which extends the BaseCustomJspBag:


@Component(

       immediate = true,

       property = {

               "context.id=com.lifedev.core.jsp.override.LifeDevCustomJspBag",

               "context.name=LifeDev Custom JSP Bag",

               "service.ranking:Integer=100"

       },

       service = CustomJspBag.class

)

public class LifeDevCustomJspBag extends BaseCustomJspBag {


}


Here we specified immediate = true to make the service available on module activation, and the following properties:

  • context.id - class name of Custom JSP Bag component 

  • context.name - human readable name

  • service.ranking - a priority of implementation (the highest one will be chosen by container).

 

Finally, we need to override the JSP file. In this sample we override the webapps/ROOT/html/common/themes/body_bottom.jsp file to add a copyright string at the bottom of the page.

The path for JSP files should be: {custom_jsp_dir}/{jsp_path}

As we see in BaseCustomJspBag - custom JSP directory is set to "META-INF/resources/custom_jsps" and target file is located on “/html/common/themes” path, which means the target location is “META-INF/resources/custom_jsps/html/common/themes” (in the resources folder). 


Now we need to copy the original file onto this location and extend it:


<%@ include file="/html/common/themes/init.jsp" %>


<%

com.liferay.petra.string.StringBundler bodyBottomSB = OutputTag.getDataSB(request, WebKeys.PAGE_BODY_BOTTOM);


if (bodyBottomSB != null) {

  bodyBottomSB.writeTo(out);

}

%>


<liferay-util:include page="/html/common/themes/body_bottom-ext.jsp" />


<p>&copy; LifeDev 2010 - 2023 | All rights reserved</p>



Once we deploy such module - we’ll see our updates on the portal page:



Enjoy 😏


Comments

Popular posts from this blog

Liferay Search Container Example

Liferay DXP - max upload file size

Liferay Keycloak integration