narzero
narzero

Reputation: 2299

Spring Boot (Gradle) app deployed to Google App Engine returns 404 Not Found

I have a Spring Boot (2.1.7) (Gradle project) that I want to deploy to Google App Engine.

I am able to successfully deploy the app (using the documentation found here) but when visiting the app url it returns a 404 Not Found screen:

<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>404 Not Found</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Not Found</h1>
</body></html>

Here's what my build.gradle file looks like:

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }

    dependencies {
        classpath 'com.google.cloud.tools:appengine-gradle-plugin:2.1.0'
        classpath 'org.akhikhl.gretty:gretty:+'
    }
}

plugins {
    id 'org.springframework.boot' version '2.1.7.RELEASE'
    id 'io.spring.dependency-management' version '1.0.8.RELEASE'
}

apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'org.akhikhl.gretty'
apply plugin: 'com.google.cloud.tools.appengine'

group = 'com.company'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    mavenCentral()
}

configurations.all {
    exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
    exclude group: 'org.slf4j', module: 'jul-to-slf4j'
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-jetty'
    providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
    providedCompile 'com.google.appengine:appengine:+'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

gretty {
    httpPort = 8080
    contextPath = '/'
    servletContainer = 'jetty9'  // What App Engine Flexible uses
}

appengine {
    deploy {
        version = "3"
        projectId = "apprealtest"
        stopPreviousVersion = true  // default - stop the current version
        promote = true              // default - & make this the current version
    }
}

Here is what my {projectRoot}/src/main/appengine/app.yaml file looks like:

runtime: java
env: flex

runtime_config:  # Optional
  jdk: openjdk8

handlers:
- url: /.*
  script: this field is required, but ignored

manual_scaling:
  instances: 1

This is what my {projectRoot}/src/main/webapp/WEB-INF/appengine-web.xml file looks like:

<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
  <runtime>java8</runtime>
  <threadsafe>true</threadsafe>
</appengine-web-app>

This is what the {projectRoot}/src/main/java/com/company/hello/HelloApplication.java looks like:

package com.company.hello;

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

@SpringBootApplication
public class HelloApplication {

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

}

This is what the {projectRoot}/src/main/java/com/company/hello/HelloController.java looks like:

package com.company.hello;

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

@RestController
public class HelloController {

    @GetMapping("/")
    public String get() {
        return System.currentTimeMillis() + "";
    }

    @GetMapping("/greeting")
    public String getGreeting() {
        return "Greetings!";
    }
}

I'm making the call to https://apprealtest.appspot.com and https://apprealtest.appspot.com/greeting.

What am I doing wrong?

Upvotes: 1

Views: 1024

Answers (2)

Pravanjan
Pravanjan

Reputation: 1016

As I have not found a complete example of spring boot with the Gradle build tool. Added a complete example with updated spring boot version 2.2.3 and AppEngine Gradle plugin 2.2.0.

  buildscript {
  repositories {
    mavenCentral()
    maven{
        url "https://plugins.gradle.org/m2/"
    }
   }
  dependencies {
        classpath 'com.google.cloud.tools:appengine-gradle-plugin:2.2.0'
  }
 }

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

repositories {
   mavenCentral()
   jcenter()
 }
 configurations.all {
          exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
        exclude group: 'org.slf4j', module: 'jul-to-slf4j'
  }
 dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-web'
  compile "com.google.appengine:appengine-api-1.0-sdk:+"
  providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1'
  providedCompile "com.google.appengine:appengine-api-stubs:+"
  providedCompile "com.google.appengine:appengine-testing:+"
  providedCompile 'org.slf4j:jul-to-slf4j:1.7.25'

  testImplementation 'org.springframework.boot:spring-boot-starter-test'
  compile group: 'net.bytebuddy', name: 'byte-buddy', version: '1.10.3'
}

 apply plugin: "com.google.cloud.tools.appengine"
 appengine {  // App Engine tasks configuration
   run {      // local (dev_appserver) configuration (standard environments only)
    jvmFlags = ['-Ddatastore.backing_store=../../src/main/webapp/WEB- 
   INF/appengine-generated/local_db.bin', '-Dappengine.fullscan.seconds=5']
    port = 8812              // default
  }
  deploy {   // deploy configuration\
    stopPreviousVersion = false  // default - stop the current version
    promote = false              // default - & make this the current version
    version = 'pr'
    projectId = '' 
   }
}

This repo has a complete example and the test case for its controller. hope it would help.

Upvotes: 0

TasosZG
TasosZG

Reputation: 1294

To deploy it in GAE Standard you can download this official SpringBoot for App Engine Standard sample.

The instructions are for maven but to do it with Gradle you can simply add this build.gradle file:

buildscript {    // Configuration for building
  repositories {
    jcenter()    // Bintray's repository - a fast Maven Central mirror & more
    mavenCentral()
  }
  dependencies {
    classpath 'com.google.cloud.tools:appengine-gradle-plugin:1.+'    // Latest 1.x.x release
  }
}

repositories {   // repositories for Jar's you access in your code
  maven {
    url 'https://oss.sonatype.org/content/repositories/snapshots' // SNAPSHOT repository (if needed)
  }
  mavenCentral()
  jcenter()
}

apply plugin: 'java'                              // standard Java tasks
apply plugin: 'war'                               // standard Web Archive plugin
apply plugin: 'com.google.cloud.tools.appengine'  // App Engine tasks
apply plugin: 'maven-publish'

dependencies {
    compile 'com.google.appengine:appengine-api-1.0-sdk:+'  // Latest App Engine Api's
    compile 'org.springframework.boot:spring-boot-starter-web:2.1.1.RELEASE'
    testCompile 'org.springframework.boot:spring-boot-starter-test:2.1.1.RELEASE'
    providedCompile 'org.slf4j:jul-to-slf4j:1.7.25'
    providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
}

configurations.all {
    exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
    exclude group: 'org.slf4j', module: 'jul-to-slf4j'
}

group = 'com.google.appengine.demos'
version = '0.0.1-SNAPSHOT'
description = 'springboot-appengine-standard'
sourceCompatibility = '1.8'

publishing {
    publications {
        maven(MavenPublication) {
            from(components.java)
        }
    }
}

tasks.withType(JavaCompile) {
    options.encoding = 'UTF-8'
}

And you can deploy it with gradle appengineDeploy.

I tested it myself and it worked. If you want to do it in GAE Flexible the corresponding sample would be this one which also has instructions for Maven so you would have to do the necessary migration to Gradle.

Upvotes: 1

Related Questions