[JAVA] Deploy the Spring Boot project to Tomcat on XAMPP

Introduction

SpringBoot has a built-in tomcat, and you can start the app just by executing jar. I didn't know how to deploy to tomcat built separately, so I looked it up.

Verification environment

Create an app with Spring Boot

Create a template project for verification with "Spring Initializr" with gradle. https://start.spring.io/

Make something like WebAPI in the text.

Create an ordinary controller.

AppController.java


package warapp.app.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AppController {
    @GetMapping("/")
    public String index() {
        return "Hello World!";
    }
    @GetMapping("/hoge")
    public String hoge() {
        return "hogehoge";
    }
}

Execute the Application class and start Spring Boot. I was able to get the expected results by connecting to "localhost: 8080" and "localhost: 8080 / hoge".

Ready to deploy to tomcat

Two conditions must be met in order to place it on Tomcat.

  1. Create a war file
  2. Set not to use built-in Tomcat

In the state created by Initializr, there is a task to create a jar, but there is no task to create a war. The method was officially written.

Spring Boot Reference Documentation

All you have to do is follow this procedure.

Inherit SpringBootServletInitializer

【Change before】

AppApplication.java


package warapp.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AppApplication {
	public static void main(String[] args) {
		SpringApplication.run(AppApplication.class, args);
	}
}

** [After change] **

AppApplication.java


package warapp.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class AppApplication extends SpringBootServletInitializer {
	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
		return builder.sources(AppApplication.class);
	}

	public static void main(String[] args) {
		SpringApplication.run(AppApplication.class, args);
	}
}

Add war plugin

Add the war plugin to build.gradle.

build.gradle


plugins {
	id 'org.springframework.boot' version '2.2.4.RELEASE'
	id 'io.spring.dependency-management' version '1.0.9.RELEASE'
	id 'java'
}

group = 'war-app'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

configurations {
	developmentOnly
	runtimeClasspath {
		extendsFrom developmentOnly
	}
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

//Add one line below
apply plugin: 'war'

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

test {
	useJUnitPlatform()
}

Prevent embedded tomcat from interfering

Add the following settings to dependencies.

build.gradle


plugins {
	id 'org.springframework.boot' version '2.2.4.RELEASE'
	id 'io.spring.dependency-management' version '1.0.9.RELEASE'
	id 'java'
}

group = 'war-app'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

configurations {
	developmentOnly
	runtimeClasspath {
		extendsFrom developmentOnly
	}
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

apply plugin: 'war'

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
	//Add the following
	providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
}

test {
	useJUnitPlatform()
}

Now you can build the war file.

build war file

  1. Open the gradle task list.
  2. Execute "Tasks"-> "build"-> "boot War"

【Execution result】

22:31:35: Executing task 'bootWar'...

> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE
> Task :bootWar

BUILD SUCCESSFUL in 1s
3 actionable tasks: 1 executed, 2 up-to-date
22:31:37: Task execution finished 'bootWar'.

A file called "~ -0.0.1-SNAPSHOT.war" is created under <project root> / build / libs.

Reflected in Tomcat

Change the war file name because it is troublesome later.

「~-0.0.1-SNAPSHOT.war」→「~.war」 ex. 「app-0.0.1-SNAPSHOT.war」→「app.war」

File placement

Place "~ .war" in Tomcat's webapps directory. Since I am using xampp this time, I placed it in "xampp \ tomcat \ webapps".

Start tomcat

Start tomcat from the xampp control panel. When started, the war file is expanded.

Check the log

You should see the following error in "xampp \ tomcat \ logs \ catalina.yyyy-mm-dd.log".

console:catalina.2020-02-24.log


information:Web application archive C:\xampp\tomcat\webapps\app.Deploy war
2 24, 2020 10:43:45 pm org.apache.catalina.startup.TldConfig execute
information: 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.
2 24, 2020 10:43:49 pm org.apache.catalina.core.ContainerBase addChildInternal
Serious: ContainerBase.addChild: start: 
org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/app]]
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:162)
	at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:1018)
	at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:994)
	at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:662)
	at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1127)
	at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:2020)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'defaultValidator' defined in class path resource [org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.validation.beanvalidation.LocalValidatorFactoryBean]: Factory method 'defaultValidator' threw exception; nested exception is java.lang.NoClassDefFoundError: javax/el/ELManager
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:656)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:484)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
	at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:152)
	at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:132)
	at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:92)
	at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:172)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5709)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
	... 10 more
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.validation.beanvalidation.LocalValidatorFactoryBean]: Factory method 'defaultValidator' threw exception; nested exception is java.lang.NoClassDefFoundError: javax/el/ELManager
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651)
	... 32 more
Caused by: java.lang.NoClassDefFoundError: javax/el/ELManager
	at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.buildExpressionFactory(ResourceBundleMessageInterpolator.java:88)
	at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:47)
	at org.hibernate.validator.internal.engine.ConfigurationImpl.getDefaultMessageInterpolator(ConfigurationImpl.java:474)
	at org.springframework.boot.validation.MessageInterpolatorFactory.getObject(MessageInterpolatorFactory.java:53)
	at org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration.defaultValidator(ValidationAutoConfiguration.java:57)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
	... 33 more

2 24, 2020 10:43:49 pm org.apache.catalina.startup.HostConfig deployWAR
Serious:Web application archive C:\xampp\tomcat\webapps\app.Error deploying war
java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/app]]
	at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:1022)
	at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:994)
	at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:662)
	at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1127)
	at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:2020)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

It seems that the error is caused by the old javax / el / library on the tomcat side. The version is 2.2, but it needs to be raised to 3.0 or higher.

Download the 3.0 jar from the link below and place it under "xampp \ tomcat \ libs". At this time, the old version of the jar may be deleted.

After placing the jar, restart Tomcat (STOP → START).

After starting up, check the log, and if there is no stack trace, there is no problem.

Deployment confirmation

Make sure it is deployed in your browser.

Connect to "localhost: 8080 / app" with a browser → Check "Hello World!" Connect to "localhost: 8080 / app / hoge" with a browser → Check "hogehoge"

It was confirmed that it was deployed normally.

in conclusion

I've been indebted to Tomcat so far, but it was a good study because I had never deployed it myself. Rest assured that you can now handle it yourself without using the built-in tomcat of eclipse and the built-in tomcat of Spring Boot. I will try installing and deploying to the Linux environment in the future.

Recommended Posts

Deploy the Spring Boot project to Tomcat on XAMPP
Deploy the WEB application by Spring Boot to Tomcat server as WAR
Deploy Spring Boot applications to Heroku without using the Heroku CLI
[Java] Deploy the Spring Boot application to Azure App Service
Deploy the application created by Spring Boot to Heroku (public) ②
[For internal use] For those assigned to the Spring Boot project (under construction)
The story of raising Spring Boot 1.5 series to 2.1 series
Deploy a Spring Boot application on Elastic Beanstalk
[Spring Boot] How to refer to the property file
View the Gradle task in the Spring Boot project
Sign in to a Spring Boot web application on the Microsoft ID platform
05. I tried to stub the source of Spring Boot
How to create a Spring Boot project in IntelliJ
I tried to reduce the capacity of Spring Boot
[Spring Boot] How to create a project (for beginners)
Leverage Spring AOP + CyclicBarrier to ensure optimistic lock testing conditions on the Spring Boot app
Deploy Vapor Project to Heroku
Spring Boot on Microsoft Azure
Introduce Maven to Tomcat project
Introduction to Spring Boot ② ~ AOP ~
Introduction to Spring Boot Part 1
Try Spring Boot on Mac
The story of raising Spring Boot from 1.5 series to 2.1 series part2
Output embedded Tomcat access log to standard output with Spring Boot
How to deploy jQuery on Rails
How to deploy Laravel on CentOS 7
Spring Boot for the first time
gRPC on Spring Boot with grpc-spring-boot-starter
How to make a hinadan for a Spring Boot project using SPRING INITIALIZR
Hot deploy with Spring Boot development
Spring Boot: Restful API sample project
How to deploy Bootstrap on Rails
What I did in the migration from Spring Boot 1.4 series to 2.0 series
How to make CsrfRequestDataValueProcessor and original RequestDataValueProcessor coexist on Spring Boot
How to use ModelMapper (Spring boot)
What I did in the migration from Spring Boot 1.5 series to 2.0 series
Upgrade spring boot from 1.5 series to 2.0 series
I want to control the default error message of Spring Boot
Deploy Rails on Docker to heroku
How to apply thymeleaf changes to the browser immediately with #Spring Boot + maven
[Spring Boot] I investigated how to implement post-processing of the received request.
Create a Spring Boot app development project with the cURL + tar command
Procedure to make the value of the property file visible in Spring Boot
I used Docker to solidify the template to be developed with spring boot.
Create Spring Boot development environment on Vagrant
[Introduction to Spring Boot] Form validation check
Spring Boot 2.0.0 does not start built-in tomcat
Spring Boot environment construction memo on mac
Launch (old) Spring Boot project in IntelliJ
Deploy Java Servlet app locally on Tomcat
Deploy to Heroku [Ruby on Rails] Beginner
How to change the timezone on Ubuntu
Changes when migrating from Spring Boot 1.5 to Spring Boot 2.0
Changes when migrating from Spring Boot 2.0 to Spring Boot 2.2
Try Spring Boot 1 (Environment construction ~ Tomcat startup)
How to split Spring Boot message file
Deploy a Tomcat-based Eclipse project on Heroku
Pre-processing to display on the browser (compiler)
Add spring boot and gradle to eclipse
03. I sent a request from Spring Boot to the zip code search API
How to set environment variables in the properties file of Spring boot application