How to Serve Jsps from Inside a Jar in Lib, or Is There a Workaround

Can I serve JSPs from inside a JAR in lib, or is there a workaround?

Servlet 3.0 which Tomcat 7 supports includes the ability to package jsps into a jar.

You need to:

  • place your jsps in META-INF/resources directory of your jar
  • optionally include a web-fragment.xml in the META-INF directory of your jar
  • place the jar in WEB-INF/lib directory of your war

You should then be able to reference your jsps in your context. For example if you have a jsp META-INF/resources/test.jsp you should be able reference this at the root of your context as test.jsp

How to include JSP from jar lib

I know of only one way.

  1. Keep the JSP in /META-INF/resources folder.
  2. Create a 'lib' folder inside the WEB-INF folder in your WAR.
  3. Place the JAR (containing the JSP in the /META-INF/resources folder) in the lib folder of the WAR.
  4. In the main JSP where you want to include this external JSP residing in the JAR, use the following statement: <jsp:include page="/myJSP.jsp" ></jsp:include>. Note that the '/' is required in front of the jsp file name to make the container look for the JSP in an absolute path (and hence in the jar in the lib folder) rather than in the current path where the main JSP is lying.

This will surely work.

Spring boot: resolve JSPs from jar dependencies

I don't think it is worth to publish the whole pom.xml, but here is the maven-dependency-plugin section that works in my case:

            <!-- ... -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>

<!-- this skip property is set by maven profile in same pom.xml - no magic here -->
<skip>${exclude.some_submodule}</skip>

<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>some_submodule</artifactId>
<version>${project.version}</version>
<type>jar</type>
<overWrite>true</overWrite>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>

<!-- there are webapp/view/*.jsp files in some_module's structure -->
<includes>view/**</includes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<!-- ... -->

The only problem here is that it works only when you launch the executable .war. Launching this application from IDE (IntelliJ IDEA) need some additional steps to be made. And that's another one disadvantage of this solution, to my mind. The first one is a dirty pom.xml.

TL;DR

Solution:

BUT!. I have found another solution that is more suitable, I think.
Actually I have moved from Tomcat to Jetty, and solution above works fine even there. There's no need in hacking the build anymore.

Now I put my .jsp files into src/main/webapp/META-INF/resources/view/some_module folder in some_module dependency and resolve it by path 'some_module/someJsp' via standard Spring's @Controllers.

I apologize that I haven't found this topic earlier. Now this is a duplicate. But who knows, maybe someone will apply solution with maven dependency plugin.

Is it possible with Spring Boot to serve up JSPs with a JAR packaging?

As @Andy Wilkinson said, there are limitations related to JSP. Please package your application as war and execute as jar. This is documented at spring site.

With Tomcat it should work if you use war packaging, i.e. an executable war will work (...). An executable jar will not work because of a hard coded file pattern in Tomcat.

  • 27.3.5 JSP limitations
  • jsp sample

Deprecated, old answer

Yes, this is possible with Spring Boot.

Take look at this example: https://github.com/mariuszs/spring-boot-web-jsp-example.

For doing this use spring-boot-maven-plugin or gradle equivalent.

With this plugin jar is executable and can serve JSP files.

$ mvn package
$ java -jar target/mymodule-0.0.1-SNAPSHOT.war

(Note the extension of the artifact in the above command .war)
or just

$ mvn spring-boot:run

Tomcat hot reload of JSP file that is inside a JAR of an exploded webapp

I noticed that Tomcat DOES recompile jsp and tag files inside JAR files.

However, "Package File" action of IntelliJ, which updates the file in the JAR, is not enough for this.

To recompile jsp and tag files in a JAR from a dependency, I have to

  • compile the dependency project
    • In the example, go to core project and run mvn install
  • package the webapp project
    • In the example, go to webapp-demo project and run mvn package

Tomcat then notices the changed JAR and recompiles the jsp and tag files.

Note that it does not work, when running mvn package in core project. It seems like Tomcat is missing something, when the dependency project is packaged but not build.

Note further that Tomcat seems to recompile all jsp and tag files in the JAR in this case. Maybe even further files from later projects that depend on these. Thus, in my case recompilation of the jsp and tag files of the changed JAR takes nearly as long as deploying the webapp from scratch.

Tested with Tomcat 9.0.50 and Maven 3.6.0

Web application in other web application

Of course you can do that:

1) Create Servlet classes / JSP files. Package them all in a jar file. Don't include web.xml or any other files.

2) Import the jar in your web application classpath.

3) Configure Servlet classes and JSP files in your web.xml as below:

For JSP:

<servlet>
<servlet-name>MyJSPFile</servlet-name>
<jsp-file>/path/to/jsp/MyJSP.jsp</jsp-file>
</servlet>

<servlet-mapping>
<servlet-name>MyJSPFile</servlet-name>
<url-pattern>/MyJSP.jsp</url-pattern>
</servlet-mapping>

For Servlet:

<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>my.servlet.classpath.MyServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet.do</url-pattern>
</servlet-mapping>


Related Topics



Leave a reply



Submit