如何在多个Liferay Portlet项目间共享自定义JSTL标签库?
Absolutely, you can centralize your shared taglibs (both standard JSTL and your custom one) into a single dependency project to avoid duplicate TLD copies and simplify updates. However, a basic empty project with just src/main/resources/WEB-INF/tld won’t cut it—here’s how to set it up properly:
Step 1: Create a Shared JAR Project
Instead of a WAR, create a Java JAR project (since this is a library dependency, not a web application). Structure it like this:
shared-taglibs/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/yourcompany/taglib/ <!-- Put your custom tag handler classes here --> │ │ └── resources/ │ │ └── META-INF/ │ │ └── tld/ │ │ ├── c.tld │ │ ├── fmt.tld │ │ ├── fn.tld │ │ └── custom.tld └── pom.xml <!-- or build.gradle for Gradle -->
Key notes:
- Place TLDs in
src/main/resources/META-INF/tld/, notWEB-INF/tld—JAR dependencies useMETA-INFfor resources that need to be accessible to the web container. - Don’t forget to include your custom tag’s Java implementation (tag handlers, tag files, etc.) in the
javadirectory—without these, your custom taglib won’t function.
Step 2: Configure the Build File
For Maven:
Ensure your pom.xml is set to package as a JAR, and that resources are correctly included:
<project> <groupId>com.yourcompany</groupId> <artifactId>shared-taglibs</artifactId> <version>1.0.0</version> <packaging>jar</packaging> <dependencies> <!-- Add dependencies for JSTL if needed (Liferay may provide these) --> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl-api</artifactId> <version>1.2</version> <scope>provided</scope> </dependency> </dependencies> </project>
For Gradle:
Set up your build.gradle as a Java library:
plugins { id 'java-library' } group = 'com.yourcompany' version = '1.0.0' repositories { mavenCentral() } dependencies { compileOnly 'javax.servlet.jsp.jstl:jstl-api:1.2' }
Step 3: Update Your Portlet WAR Projects
Add the Shared Dependency
In each Portlet project’s build file, add a dependency on your shared taglib JAR:
Maven:
<dependency> <groupId>com.yourcompany</groupId> <artifactId>shared-taglibs</artifactId> <version>1.0.0</version> <!-- Use 'provided' for JSTL if Liferay already includes it; use 'compile' for your custom taglib --> <scope>compile</scope> </dependency>
Gradle:
dependencies { implementation project(':shared-taglibs') // Or use compileOnly if applicable }
Update web.xml Taglib References
In each Portlet’s WEB-INF/web.xml, update the taglib locations to point to the JAR’s META-INF/tld path instead of the local WEB-INF/tld:
<taglib> <taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri> <taglib-location>/META-INF/tld/c.tld</taglib-location> </taglib> <taglib> <taglib-uri>http://yourcompany.com/custom-taglib</taglib-uri> <taglib-location>/META-INF/tld/custom.tld</taglib-location> </taglib>
Note: For standard JSTL taglibs, some containers auto-detect the TLDs from the JAR, so you might be able to skip these web.xml entries—but including them ensures consistency across environments.
Step 4: Clean Up Duplicate Files
Delete the WEB-INF/tld directories and their contents from all your Portlet projects—they’re no longer needed!
Why Your Initial Idea Won’t Work
A project with just src/main/resources/WEB-INF/tld fails for two critical reasons:
- Resource Path: Web containers don’t look for TLDs in
WEB-INFinside JAR dependencies—they expectMETA-INFfor library resources. - Missing Implementation: Your custom taglib relies on Java classes (tag handlers) that need to be packaged with the TLDs. Without these, the taglib will throw runtime errors.
Bonus: Optimize for Liferay
- If Liferay already includes JSTL libraries in its container, you can exclude the standard JSTL TLDs from your shared project and set their dependency scope to
provided—this reduces the size of your shared JAR. - Test deploy one Portlet first to verify that all tags (standard and custom) work as expected before rolling out to all projects.
内容的提问来源于stack exchange,提问作者Jamie

