Docker + Spring Boot/MVC WAR = Tomcat 404 - spring-boot

so I am trying to dockerize my Spring Boot web app. Under IntelliJ it works fine, but as soon as I deploy it - the http status 404 appears instead of my homepage.
project structure
-src
-main
-java
...my packages
-resources
...application.properties and others
-webapp
-WEB-INF
-views
...jsp pages
-resources
...js, css, images
-test
The pom.xml includes spring-boot-starter dependencies, Tomcat and spring-boot-maven plugin.
Dockerfile
FROM tomcat:8.0.51-jre8-alpine
RUN rm -rf /usr/local/tomcat/webapps/*
COPY ./target/charity-0.0.1-SNAPSHOT.war /usr/local/tomcat/webapps/ROOT.war
I think somehow the Docker doesn't see the WEB-INF folder. I'm in trouble with this for over 2 days... Any ideas?
CMD ["catalina.sh", "run"]

Just for the record - this Dockerfile finally worked:
FROM java:8
ADD /target/charity-0.0.1-SNAPSHOT.war charity.war
ENTRYPOINT ["java", "-jar", "/charity.war"]

Just to confirm, you are doing
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
and mark the packaging as a war in pom.xml
Also, you need to modify the main class of your application
Please take reference from below link
https://www.baeldung.com/spring-boot-war-tomcat-deploy

Related

Docker for local development with spring boot

I want to use docker with a spring boot application in my development environment.
For production I first generate the war file using mvn package then I build an image using this dockerfile :
FROM tomcat:9.0-jre8-alpine
COPY target/backend-0.0.1-SNAPSHOT.war $CATALINA_HOME/webapps/api.war
But for dev purpose I want to be able to check my changes when I edit my code and not have to redo mvn package then build the image then run the container. Changes made to the code can be watched using spring boot devtools so that my app is recompiled every time I make changes to the source code.
But then I thought to use an image, still with tomcat, and setup a volume. But I don't know which files I have to watch. Is it the folder target or some specific files inside it ? And to which folder inside my image do I link the volume to ? Something like $CATALINA_HOME/webapps I presume.
If anyone can help me to point me in the right direction it would be greatly appreciated ? Thanks.
I managed to do it using a Maven Docker image. mapping the source code using volumes, and setting the working directory so Maven can find the pom.xml. In your docker-compose.yml:
version: '3.1'
services:
backend:
image: maven:3.6.3-jdk-8
command: mvn spring-boot:run
ports:
- 8080:8080
- 8085:8085
volumes:
- .:/usr/src/mymaven:rw
working_dir: /usr/src/mymaven
Make sure you have the boot tools enabled in your pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
And if you need, enable the remote debugger:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.0.3.RELEASE</version>
<configuration>
<jvmArguments>
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8085
</jvmArguments>
</configuration>
</plugin>
Then you can attach your code editor to the Docker container:
https://code.visualstudio.com/Docs/editor/debugging#_launch-versus-attach-configurations

With a mysql-connector-java as "provided" dependency, my Maven build cannot connect to the data store

Because Tomcat tells us to have the mysql-connector-java in its lib/ directory, so that it can handle multiple projects, I had my dependency as provided:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.36</version>
<scope>provided</scope>
</dependency>
And I extracted the jar archive mysql-connector-java-x.x.x-bin.jar from the downloaded dependency and copied it into the lib folder of the Tomcat server:
cp ~/.m2/repository/mysql/mysql-connector-java/5.1.36/mysql-connector-java-5.1.36.jar lib/
But when I now run a build the tests phase fails since it cannot connect to the data store.
The build would succeed if commenting out the provided scope.
There must be a simple way around this...
UPDATE: I could run the Maven Tomcat 7 command: mvn clean install tomcat7:run -Denv="preprod" after adding the mysql-connector-java dependency in the tomcat7-maven-plugin plugin. But I still cannot run the tests, I have a connection failed when running the maven-surefire-plugin tests.
I used both provided and test scopes as in:
<scope>provided test</scope>
and it now also make the connector in the tests phase.

How is a war file created for spring boot with maven?

I'm trying to follow the guide for converting a spring project to a war.
http://spring.io/guides/gs/convert-jar-to-war/
It starts out using maven and gradle and then right after the jar portion it completely forgets about maven and only has gradle updates.
There are two main changes that you need to make in the pom. The first is to change the project's packaging type to war:
<groupId>org.springframework</groupId>
<artifactId>gs-convert-jar-to-war</artifactId>
<version>0.1.0</version>
<packaging>war</packaging>
The second is to add a dependency on spring-boot-starter-tomcat and mark it as provided:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
mvn package will now produce a war file that can be run using java -jar or deployed to a separate servlet container.
There is an official guide at spring:
http://spring.io/guides/gs/convert-jar-to-war-maven/
Pay attention to "Initialize the servlet" section.
It explains an important point of adding a class that substitutes web.xml. Without it (or without proper web.xml) you will get a war file but when deployed nothing will be accessible in browser as nothing will be registered as your request dispatcher.
Also note that it is best to run this example on Tomcat 8 as it supports latest servlet specs. I have spent number of hours trying to figure out why it does not work on my Tomcat 7.

One Spring Boot project, deploy to both JAR or WAR

Is there a way to have a single Spring Boot project be packagable into both JAR and WAR without changing the pom.xml or the application source?
I've read Converting a Spring Boot JAR Application to a WAR, but it converts the project to WAR and it loses the ability to be packaged as JAR.
I don't expect mvn package to do both. What I want is something like mvn i-want-a-jar and it would package the project as JAR. Or I could run mvn i-want-a-war and it would package the project as WAR.
Is this possible?
I managed to do it by adding
<packaging>${packaging.type}</packaging>
to the POM file and then setting different profiles for JAR and WAR:
<profiles>
<profile>
<id>jar</id>
<properties>
<packaging.type>jar</packaging.type>
</properties>
</profile>
<profile>
<id>war</id>
<properties>
<packaging.type>war</packaging.type>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
</profiles>
Now mvn package -P war produces a WAR and mvn package -P jar produces a JAR.
Another option is to create separate modules for JAR and WAR, but I didn't go that route.
What's wrong with a WAR file that's executable? Isn't that what you really need?
P.S. like
java -jar name.war
We've recently had a similar requirement, where an existing Spring Boot based project that was originally packaged as an executable Jar needed to support Tomcat and WildFly deployments.
Due to some dependencies used in this project (for example WebJars), a simple switch to WAR package wasn't an option since some of those dependencies were required for WildFly (VFS support) but not for other deployment.
The solution was to restructure the project modules in a way that core module contained the actual project but without having Spring Boot’s plugin applied, while several package modules would depend on core module and configure deployment artifact specifics (Boot and other plugins, deployment specific dependencies etc.).
That way project build was able to generate multiple deployment artifacts (Boot's executable JAR, traditional WAR and WildFly specific WAR) in a single build run.
In case anyone finds this useful, the sample project to demonstrate the approach is available on Github. The project can be built by either Gradle or Maven.

Spring Boot + Jetty & hot deployment

I've read the Hot swapping in Spring Boot but didn't find something that will help my case.
I have a spring-boot app on embedded jetty servers using thymeleaf. My app will serve html,css,js(AngularJS) and REST services.
Folder structure is like this:
/java
----
/resources
/static
/js
/css
/templates (html)
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
But css/html/js is not hot deployed when I change them. I have to restart server every time.
+bonus = when page loads it locks resources (js) and even Ant script cannot replace them.
Can I set scanIntervalSeconds anywhere?
--EDIT--
Main.java
#Configuration
#ComponentScan
#EnableJpaRepositories
#EnableAutoConfiguration
#Import({RepositoryRestMvcConfiguration.class, PersistenceConfig.class, ThymeleafConfig.class})
public class Main {
public static void main(String[] args) throws Exception {
SpringApplication.run(Main.class, args);
}
}
I've run it by right click on class and Debug in IDEA.
How are you launching the app? If you use an IDE with debug mode it should work (except for the locking problem which I believe is Windows OS), or if you launch it with "mvn spring-boot:run", or "gradle bootRun".
I develop using NetBeans 8.0.1.
I fixed the issue of not reloaded static resources in src/main/resources like css (in src/main/resources/resources/css (yes, really twice "resources"!), html-thymeleaf-templates (in src/main/resources/templates) the following way:
My Spring Boot webapp is a JAR project (pom.xml)
Add src/main/resources/application.properties:
spring.template.cache=false
spring.thymeleaf.cache=false
Added custom maven build: Project - Properties - Custom... - Goals...
Execute Goals: spring-boot:run
Set Properties:
jpda.listen=maven (to run it in debug mode)
Env.spring.profiles.active=DEV (optional, but I need it for different SpringConfig-....properties in development, production,...)
Just run the custom maven build for starting the webapp in debug mode. Changes in Thymeleaf-Templates (that are in src/main/resources/templates, eg. index.html (not .xhtml!)) are visible immediately on browser reload.
if you move the css and java script to a folder under
src/main/java/webapp it should work.
for some reason resources under src/main/java/resources didnt seem to get hot deployed when changed.
to fix this as the above post suggested I added
spring.template.cache=false
spring.thymeleaf.cache=false
to Application.properties inside the resources folder.
Note:
I also added this
-javaagent:springloaded-1.2.0.RELEASE.jar -noverify
as a vm runtime argument.

Resources