Reputation: 14963
I'm familiar with the Spring Boot JSP sample application
However that example uses the WAR
packaging. Is it possible to do the same with <packaging>JAR</packaging>
?
My goal is to put JSP
s under src/main/resources/jsp
to simplify the structure of my app.
Upvotes: 40
Views: 60312
Reputation: 1
Here is a solution to this problem for spring boot 3.3 https://github.com/MidasSLK/spring-boot-3-3-jsp-jar/tree/master/spring-boot-3-3-classic-loader-jsp-jar
I have used the "opt-out of the new nested Loader option" as provided by tesmo. And have combined it with the solution provided by code4kix.
Upvotes: 0
Reputation: 215
Starting with Spring Boot 3.2 the answer by code4kix stopped working because Spring changed JarLoader to use their new nested system.
You can opt-out as described in the Migration Guide for Spring Boot 3.1: here
For Maven this would be:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<loaderImplementation>CLASSIC</loaderImplementation>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
As the support for the classic Loader will be dropped some time in the future it is probably better to adjust it.
The following adjustments worked for me:
public class JSPStaticResourceConfigurer implements LifecycleListener {
private final Context context;
public JSPStaticResourceConfigurer(Context context) {
this.context = context;
}
private final String subPath = "/META-INF/resources";
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (!event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
return;
}
final URL finalLocation = getUrl();
this.context.getResources().createWebResourceSet(
ResourceSetType.RESOURCE_JAR,
"/",
finalLocation,
subPath
);
}
private URL getUrl() {
final URL location = this.getClass().getProtectionDomain().getCodeSource().getLocation();
if (ResourceUtils.isFileURL(location)) {
return location;
} else if (ResourceUtils.isJarURL(location)) {
try {
// when run as fat jar
//transform
//nested:/home/myfiles/Projects/myproj/myjar.jar/!BOOT-INF/classes/!/
//to
//jar:file:/home/myfiles/Projects/myproj/myjar.jar!/
String locationStr = location.getPath()
.replaceFirst("^nested:", "")
.replaceFirst("/!BOOT-INF/classes/!/$", "!/");
return new URI("jar:file", locationStr, null).toURL();
} catch (Exception e) {
throw new IllegalStateException("Unable to add new JSP source URI to tomcat resources", e);
}
} else {
throw new IllegalStateException("Can not add tomcat resources, unhandleable url: " + location);
}
}
}
And use this like
@Configuration
public class TomcatJSPConfiguration {
@Bean
public WebServerFactoryCustomizer<WebServerFactory> staticResourceCustomizer() {
return factory -> {
if (factory instanceof TomcatServletWebServerFactory tomcatFactory) {
tomcatFactory.addContextCustomizers(context -> context.addLifecycleListener(new JSPStaticResourceConfigurer(context)));
}
};
}
}
Upvotes: 0
Reputation: 1138
If for some reason anybody still needs this in SB2+ we had to slightly adjust lifecycleEvent method
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
URL location = this.getClass().getProtectionDomain().getCodeSource().getLocation();
if (new LocalDevelDetection().isDocker()){
try {
//This is necessary to make JSP work in docker --> not sure which of those mounts actually does the trick but I think /YOUR_SB_APP_NAME one works for docker-compose and the other one for "vanilla docker" (non-compose)
context.getResources().createWebResourceSet(WebResourceRoot.ResourceSetType.RESOURCE_JAR, "/<<YOUR_SB_APP_NAME>>", new URL("jar:file:/<<PATH_TO_YOUR_SB_APP>>.jar!/"), "/META-INF/resources");
context.getResources().createWebResourceSet(WebResourceRoot.ResourceSetType.RESOURCE_JAR, "/", new URL("jar:file:/<<PATH_TO_YOUR_SB_APP>>.jar!/"), "/META-INF/resources");
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
else {
if (ResourceUtils.isFileURL(location)) {
// when run as exploded directory
String rootFile = location.getFile();
if (rootFile.endsWith("/BOOT-INF/classes/")) {
rootFile = rootFile.substring(0, rootFile.length() - "/BOOT-INF/classes/".length() + 1);
}
if (!new File(rootFile, "META-INF" + File.separator + "resources").isDirectory()) {
return;
}
try {
location = new File(rootFile).toURI()
.toURL();
} catch (MalformedURLException e) {
throw new IllegalStateException("Can not add tomcat resources", e);
}
}
String locationStr = location.toString();
if (locationStr.endsWith("/BOOT-INF/classes!/")) {
// when run as fat jar
locationStr = locationStr.substring(0, locationStr.length() - "/BOOT-INF/classes!/".length() + 1);
try {
location = new URL(locationStr);
} catch (MalformedURLException e) {
throw new IllegalStateException("Can not add tomcat resources", e);
}
}
this.context.getResources()
.createWebResourceSet(WebResourceRoot.ResourceSetType.RESOURCE_JAR, "/", location, "/META-INF/resources");
}
}
}
Oh and our LocalDevelDetection.isDocker() method:
public boolean isDocker(){
try (Stream< String > stream =
Files.lines(Paths.get("/proc/1/cgroup"))) {
return stream.anyMatch(line -> line.contains("/docker"));
} catch (IOException e) {
return false;
}
}
Upvotes: 1
Reputation: 31587
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.
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
Upvotes: 43
Reputation: 21
here is my solution:
<build>
<resources>
<resource>
<directory>src/main/webapp</directory>
<targetPath>META-INF/resources</targetPath>
<includes>
<include>**/**</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/**</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!-- must use 1.4.2 version -->
<version>1.4.2.RELEASE</version>
</plugin>
</plugins>
</build>
Upvotes: 1
Reputation: 491
I tried out all possible solution finally this helped me out.
Add the following dependencies in pom.xml
<!-- Need this to compile JSP -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!-- Need this to compile JSP -->
<dependency>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
<version>4.6.1</version>
</dependency>
Add the view resolver to application.properties file.
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
Once, we are done with above code, we will build our project, using maven commands and then execute as standalone jar using standard java’s jar execution command.
cd <TO_YOUR_PROJECT_DIR>
mvn clean package spring-boot:repackage
java -jar target/<YOUR_PROJECT_CREATED_JAR>
Upvotes: 0
Reputation: 111
27.3.5 JSP limitations
When running a Spring Boot application that uses an embedded servlet container (and is packaged as an executable archive), there are some limitations in the JSP support.
With Tomcat it should work if you use war packaging, i.e. an executable war will work, and will also be deployable to a standard container (not limited to, but including Tomcat).
An executable jar will not work because of a hard coded file pattern in Tomcat.
With Jetty it should work if you use war packaging, i.e. an executable war will work, and will also be deployable to any standard container.
Undertow does not support JSPs.
Creating a custom error.jsp page won’t override the default view for error handling, custom error pages should be used instead.
Upvotes: 4
Reputation: 4187
If for whatever reason, you can't deal with a war packaging, there's a hack. Full credit to this guy for doing it for an older version of spring-boot.
One way to do this is to personalize tomcat and add BOOT-INF/classes
to tomcat's ResourceSet. In tomcat, all scanned resources are put into something called a ResourceSet. For example, the META-INF/resources of the application jar package in the servlet 3.0 specification is scanned and put into the ResourceSet.
Now we need to find a way to add the BOOT-INF/classes directory of the fat jar to the ResourceSet. We can do this through the tomcat LifecycleListener interface, in the Lifecycle.CONFIGURE_START_EVENT
event, get the BOOT-INF/classes URL, and then add this URL to the WebResourceSet. A complete example is here, but you can do this like so:
import org.apache.catalina.Context;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnProperty(name = "tomcat.staticResourceCustomizer.enabled", matchIfMissing = true)
public class TomcatConfiguration {
@Bean
public WebServerFactoryCustomizer<WebServerFactory> staticResourceCustomizer() {
return new WebServerFactoryCustomizer<WebServerFactory>() {
@Override
public void customize(WebServerFactory factory) {
if (factory instanceof TomcatServletWebServerFactory) {
((TomcatServletWebServerFactory) factory)
.addContextCustomizers(new org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer() {
@Override
public void customize(Context context) {
context.addLifecycleListener(new StaticResourceConfigurer(context));
}
});
}
}
};
}
}
And then use the LifecycleListener like so:
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.catalina.Context;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.WebResourceRoot.ResourceSetType;
import org.springframework.util.ResourceUtils;
public class StaticResourceConfigurer implements LifecycleListener {
private final Context context;
StaticResourceConfigurer(Context context) {
this.context = context;
}
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
URL location = this.getClass().getProtectionDomain().getCodeSource().getLocation();
if (ResourceUtils.isFileURL(location)) {
// when run as exploded directory
String rootFile = location.getFile();
if (rootFile.endsWith("/BOOT-INF/classes/")) {
rootFile = rootFile.substring(0, rootFile.length() - "/BOOT-INF/classes/".length() + 1);
}
if (!new File(rootFile, "META-INF" + File.separator + "resources").isDirectory()) {
return;
}
try {
location = new File(rootFile).toURI().toURL();
} catch (MalformedURLException e) {
throw new IllegalStateException("Can not add tomcat resources", e);
}
}
String locationStr = location.toString();
if (locationStr.endsWith("/BOOT-INF/classes!/")) {
// when run as fat jar
locationStr = locationStr.substring(0, locationStr.length() - "/BOOT-INF/classes!/".length() + 1);
try {
location = new URL(locationStr);
} catch (MalformedURLException e) {
throw new IllegalStateException("Can not add tomcat resources", e);
}
}
this.context.getResources().createWebResourceSet(ResourceSetType.RESOURCE_JAR, "/", location,
"/META-INF/resources");
}
}
}
Upvotes: 6
Reputation: 727
Spring Boot is pretty good with JSP and it's little easy also just you need below configuration
1 - tomcat-embad-jasper dependency
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
2 - Add below configuration is application.properties
spring.mvc.view.prefix: /
spring.mvc.view.suffix: .jsp
That's it still have some doubt then check it out below link
Spring Boot and JSP integration
Upvotes: 2
Reputation: 1322
If your springboot is building your project and running it in local server correctly then YES.
What you need to do is to build the project using
mvn -U clean package
.
Then in target folder you have your runnable xxxx.jar . Now what you have to do is put your xxxx.jar file in the server or where you want along with the src/main/webapp/WEB-INF/jsp/
*.jsp files in same hierarchy.
then try java -jar xxxx.jar
Your project will run with no issue.
`
.
├── src
│ └── main
│ └── webapp
│ └── WEB-INF
│ ├── jsp
│ │ ├── default.jsp
│ │ ├── help.jsp
│ │ ├── index.jsp
│ │ ├── insert.jsp
│ │ ├── login.jsp
│ │ ├── modify.jsp
│ │ ├── search.jsp
│ │ └── show.jsp
│ └── web.xml
├── xxx.jar
└── xxx.jar.original`
java -jar xxx.jar
<pre>
$java -jar xxx.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.4.RELEASE)
2017-09-05 19:31:05.009 INFO 10325 --- [ main] com.myapp.app.DemoApplication : Starting DemoApplication v0.0.1-SNAPSHOT on dipu-HP with PID 10325 (/home/dipu/Documents/workspace-sts/jspjartest/xxx.jar started by dipu in /home/dipu/Documents/workspace-sts/jspjartest)
2017-09-05 19:31:05.014 INFO 10325 --- [ main] com.myapp.app.DemoApplication : No active profile set, falling back to default profiles: default
2017-09-05 19:31:05.138 INFO 10325 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6e5e91e4: startup date [Tue Sep 05 19:31:05 IST 2017]; root of context hierarchy
2017-09-05 19:31:07.258 INFO 10325 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8090 (http)
2017-09-05 19:31:07.276 INFO 10325 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2017-09-05 19:31:07.278 INFO 10325 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.15
2017-09-05 19:31:08.094 INFO 10325 --- [ost-startStop-1] org.apache.jasper.servlet.TldScanner : At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
2017-09-05 19:31:08.396 INFO 10325 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2017-09-05 19:31:08.401 INFO 10325 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3267 ms
2017-09-05 19:31:08.615 INFO 10325 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2017-09-05 19:31:08.617 INFO 10325 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'loginServlet' to [/loginServlet/]
2017-09-05 19:31:08.618 INFO 10325 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'uploadController' to [/uploadController/]
2017-09-05 19:31:08.622 INFO 10325 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-09-05 19:31:08.622 INFO 10325 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-09-05 19:31:08.623 INFO 10325 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-09-05 19:31:08.623 INFO 10325 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2017-09-05 19:31:09.137 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6e5e91e4: startup date [Tue Sep 05 19:31:05 IST 2017]; root of context hierarchy
2017-09-05 19:31:09.286 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/user-management]}" onto java.lang.String com.myapp.app.DemoController.user()
2017-09-05 19:31:09.288 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto java.lang.String com.myapp.app.DemoController.reload()
2017-09-05 19:31:09.290 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/show]}" onto java.lang.String com.myapp.app.DemoController.show()
2017-09-05 19:31:09.292 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/modify]}" onto java.lang.String com.myapp.app.DemoController.modify()
2017-09-05 19:31:09.293 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/admin]}" onto java.lang.String com.myapp.app.DemoController.admin()
2017-09-05 19:31:09.294 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/login]}" onto java.lang.String com.myapp.app.DemoController.login()
2017-09-05 19:31:09.294 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/faq-management]}" onto java.lang.String com.myapp.app.DemoController.faq()
2017-09-05 19:31:09.294 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/subject-area]}" onto java.lang.String com.myapp.app.DemoController.subject()
2017-09-05 19:31:09.295 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/Chat]}" onto java.lang.String com.myapp.app.DemoController.index()
2017-09-05 19:31:09.295 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/delete]}" onto java.lang.String com.myapp.app.DemoController.delete()
2017-09-05 19:31:09.296 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/result]}" onto java.lang.String com.myapp.app.DemoController.result()
2017-09-05 19:31:09.296 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/insert]}" onto java.lang.String com.myapp.app.DemoController.insert()
2017-09-05 19:31:09.300 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/fileUpload]}" onto java.lang.String com.myapp.app.DemoController.file()
2017-09-05 19:31:09.301 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/search]}" onto java.lang.String com.myapp.app.DemoController.search()
2017-09-05 19:31:09.301 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/help]}" onto java.lang.String com.myapp.app.DemoController.help()
2017-09-05 19:31:09.312 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/LoginServlet]}" onto public void com.myapp.app.LoginServlet.LoginServlet.doPost(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws javax.servlet.ServletException,java.io.IOException
2017-09-05 19:31:09.313 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/image],methods=[GET],produces=[text/html;charset=UTF-8]}" onto public java.lang.String com.myapp.app.controller.ImageController.image()
2017-09-05 19:31:09.316 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/authenticate],methods=[POST]}" onto public java.lang.String com.myapp.app.controller.AjaxController.authenticate(java.lang.String,java.lang.String) throws java.io.IOException
2017-09-05 19:31:09.317 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/searchCompany],methods=[GET]}" onto public java.lang.String com.myapp.app.controller.AjaxController.getCompany(java.lang.String,java.lang.String) throws java.io.IOException
2017-09-05 19:31:09.318 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/executeQuery],methods=[GET]}" onto public java.lang.String com.myapp.app.controller.AjaxController.executeQuery(java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String) throws java.io.IOException
2017-09-05 19:31:09.318 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/insertData],methods=[POST]}" onto public int com.myapp.app.controller.AjaxController.insertResources(java.lang.String,java.lang.String,java.lang.String) throws java.io.IOException
2017-09-05 19:31:09.319 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/showData],methods=[GET]}" onto public java.lang.String com.myapp.app.controller.AjaxController.showResources(java.lang.String) throws java.io.IOException
2017-09-05 19:31:09.319 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/searchData],methods=[POST]}" onto public java.lang.String com.myapp.app.controller.AjaxController.getSearchData(java.lang.String,java.lang.String) throws java.io.IOException
2017-09-05 19:31:09.319 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/deleteData],methods=[POST]}" onto public java.lang.String com.myapp.app.controller.AjaxController.deleteData(java.lang.String,java.lang.String) throws java.io.IOException
2017-09-05 19:31:09.320 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/modifyData],methods=[POST]}" onto public int com.myapp.app.controller.AjaxController.modifyData(java.lang.String,java.lang.String,java.lang.String) throws java.io.IOException
2017-09-05 19:31:09.322 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/suggestWords],methods=[POST]}" onto public java.lang.String com.myapp.app.controller.AjaxController.suggestWords(java.lang.String,java.lang.String) throws java.io.IOException
2017-09-05 19:31:09.322 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/authenticateUser],methods=[POST]}" onto public java.lang.String com.myapp.app.controller.AjaxController.authenticateUser(java.lang.String) throws java.io.IOException
2017-09-05 19:31:09.323 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/insertJson],methods=[POST]}" onto public int com.myapp.app.controller.AjaxController.insertJsonResources(java.lang.String,java.lang.String) throws java.io.IOException
2017-09-05 19:31:09.323 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/getvalue],methods=[GET]}" onto public java.lang.String com.myapp.app.controller.AjaxController.getResource(java.lang.String,java.lang.String) throws java.io.IOException
2017-09-05 19:31:09.324 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/searchQuery],methods=[GET]}" onto public java.lang.String com.myapp.app.controller.AjaxController.getResources(java.lang.String,java.lang.String) throws java.io.IOException
2017-09-05 19:31:09.330 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/upload],methods=[POST]}" onto public void com.myapp.app.controller.UploadController.doPost(org.springframework.web.multipart.MultipartFile,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws javax.servlet.ServletException,java.io.IOException
2017-09-05 19:31:09.333 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-09-05 19:31:09.334 INFO 10325 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-09-05 19:31:09.388 INFO 10325 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-09-05 19:31:09.388 INFO 10325 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-09-05 19:31:09.461 INFO 10325 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-09-05 19:31:09.752 INFO 10325 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2017-09-05 19:31:09.861 INFO 10325 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8090 (http)
2017-09-05 19:31:09.867 INFO 10325 --- [ main] com.myapp.DemoApplication : Started DemoApplication in 5.349 seconds (JVM running for 5.866)
</pre>
here the server is running
$ curl 127.0.0.1:8090/login
Welcome to Login page
My POM.xml
<code>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.myapp</groupId>
<artifactId>app</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Jsp Springboot</name>
<description>Jsp Springboot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- Need this to compile JSP,
tomcat-embed-jasper version is not working, no idea why -->
<dependency>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
<version>4.6.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.3.7</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>rest</artifactId>
<version>5.5.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.16</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.16</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.16</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>
</plugins>
</build>
</project>
</code>
my application.properties
<code>
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
server.port=8090
</code>
My Project Structure
<code>
.
├── src
│ └── main
│ ├── java
│ │ └── com
│ │ └── myapp
│ │ └── app
│ │ ├── mynewapp
│ │ ├── controller
│ ├── resources
│ │ └── static
│ │ ├── assets
│ │ │ ├── css
│ │ │ │ ├── fonts
│ │ │ │ └── lib
│ │ │ ├── img
│ │ │ └── js
│ │ │ └── lib
│ │ ├── css
│ │ │ └── img
│ │ ├── fonts
│ │ ├── images
│ │ └── js
│ │ └── img
│ └── webapp
│ └── WEB-INF
│ ├── jsp
│ └── lib
</code>
Thank You.
Upvotes: 7
Reputation: 33
Hi I figer out how to copy jsp's from jar to embedded tomcat folder
package com.demosoft.stlb.loadbalancer;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.context.ServletContextAware;
import javax.annotation.PostConstruct;
import javax.servlet.ServletContext;
import java.io.*;
import java.net.MalformedURLException;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@Component
public class JarFileResourcesExtractor implements ServletContextAware {
private String resourcePathPattern = "WEB-INF/**";
private String resourcePathPrefix = "WEB-INF/";
private String destination = "/WEB-INF/";
private ServletContext servletContext;
private AntPathMatcher pathMatcher = new AntPathMatcher();
/**
* Extracts the resource files found in the specified jar file into the destination path
*
* @throws IOException If an IO error occurs when reading the jar file
* @throws FileNotFoundException If the jar file cannot be found
*/
@PostConstruct
public void extractFiles() throws IOException {
try {
JarFile jarFile = (JarFile) getClass().getProtectionDomain().getCodeSource().getLocation().getContent();
Enumeration<JarEntry> entries = jarFile.entries();
System.out.println("Tomcat destination : " + servletContext.getRealPath(destination));
while (entries.hasMoreElements()) {
processJarEntry(jarFile, entries);
}
} catch (MalformedURLException e) {
throw new FileNotFoundException("Cannot find jar file in libs: ");
} catch (IOException e) {
throw new IOException("IOException while moving resources.", e);
}
}
private void processJarEntry(JarFile jarFile, Enumeration<JarEntry> entries) throws IOException {
JarEntry entry = entries.nextElement();
if (pathMatcher.match(resourcePathPattern, entry.getName())) {
String fileName = getFileName(entry);
if (checkFileName(fileName)) return;
String sourcePath = getSourcePath(entry, fileName);
if (checkSourcePath(sourcePath)) return;
copyAndClose(jarFile.getInputStream(entry), getOutputStream(fileName, sourcePath));
}
}
private FileOutputStream getOutputStream(String fileName, String sourcePath) throws IOException {
File destinationFolder = new File(servletContext.getRealPath(destination)+sourcePath);
destinationFolder.mkdirs();
File materializedFile = new File(destinationFolder, fileName);
materializedFile.createNewFile();
return new FileOutputStream(materializedFile);
}
private boolean checkSourcePath(String sourcePath) {
return sourcePath.startsWith(".idea");
}
private String getSourcePath(JarEntry entry, String fileName) {
String sourcePath = entry.getName().replaceFirst(fileName, "");
sourcePath = sourcePath.replaceFirst(resourcePathPrefix, "").trim();
return sourcePath;
}
private boolean checkFileName(String fileName) {
return fileName.trim().equals("");
}
private String getFileName(JarEntry entry) {
return entry.getName().replaceFirst(".*\\/", "");
}
@Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
public static int IO_BUFFER_SIZE = 8192;
private static void copyAndClose(InputStream in, OutputStream out) throws IOException {
try {
byte[] b = new byte[IO_BUFFER_SIZE];
int read;
while ((read = in.read(b)) != -1) {
out.write(b, 0, read);
}
} finally {
in.close();
out.close();
}
}
}
Upvotes: 0
Reputation: 1059
I'm using JSP successfully on Spring Boot Application with jar packaging, putting my JSP files on src/main/webapp/WEB-INF/JSP directory and configuring my Application as bellow
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/JSP/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
My Controller is:
@Controller
public class HelloController {
@RequestMapping(value = { "/", "/hello**" }, method = RequestMethod.GET)
public ModelAndView welcomePage() {
ModelAndView model = new ModelAndView();
model.addObject("title", "Spring Security Example");
model.addObject("message", "This is Hello World!");
model.setViewName("hello");
System.out.println("° ° ° ° welcomePage running. model = " + model);
return model;
}
. . .
And my hello.jsp is
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@page session="true"%>
<html>
<body>
<h1>Title : ${title}</h1>
<h1>${message}</h1>
<h2>Options:
<a href="<c:url value="/hello" />" >Home</a> |
<a href="<c:url value="/admin" />" >Administration</a> |
<a href="<c:url value="/super" />" >Super user</a>
<c:if test="${pageContext.request.userPrincipal.name != null}"> |
<a href="<c:url value="/logout" />" >Logout</a>
</c:if>
</h2>
</body>
</html>
My pom.xml file is
<groupId>br.com.joao-parana</groupId>
<artifactId>my-spring-boot-app</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>my-spring-boot-app Maven Webapp</name>
<url>http://maven.apache.org</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.4.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
. . .
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<build>
<finalName>my-spring-boot-app</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
I hope this help someone !
Upvotes: 1
Reputation: 221
Your best bet is to change the packaging type into war, and it should work without further changes.
As mentioned in on of the comments above, there are some limitations:
Upvotes: 7