Google App Engine Standard env - not found controller method - Spring Boot app - java

I was trying to deploy Spring Boot application on Google App Engine (standard environment). At first I cloned example app from this nice tutorial https://springframework.guru/spring-boot-web-application-part-4-spring-mvc/
For example I called http://localhost:8080/products and template with data was displayed.
So everything ran without problems, I was able to call all controller methods locally. Then I decided as experiment to deploy it on GAE. I adjusted pom.xml according to instructions from here https://github.com/GoogleCloudPlatform/getting-started-java/tree/master/appengine-standard-java8/springboot-appengine-standard
It means I excluded Tomcat dependency, changed packaging from jar to war, created appengine-web.xml file etc. As next step, I created GAE project in GAE console and copied APP ID into appengine-web.xml. Then I ran mvn clean package and war was created in target folder. Finally I started with GAE deployment and it also went smoothly without errors.
My app is now deployed on this URL https://20180109t135551-dot-oe-gae-test.appspot.com/
If you try it, you will see Hello World in browser. But if I try to call /products controller method like this https://20180109t135551-dot-oe-gae-test.appspot.com/products I get "not found" error.
Can you give me advice on which URL should I call my controller methods? Did I forget to implement something like web.xml servlet mapping? Or is it some specific Spring Boot - Google App Engine problem?
I will be grateful for any hint.
Thank you all in advance

Following this steps translates into the following for the code:
In pom.xml, change <packaging>jar</packaging> to <packaging>war</packaging>
In the package guru.springframework add this class:
Code:
package guru.springframework;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class SpringBootWebApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootWebApplication.class, args);
}
}
Remove Tomcat Starter:
Find this dependency in the POM:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
And add these lines:
<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>
Exclude Jetty dependencies and include the Servlet API dependency:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
Add the App Engine Standard plugin:
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>appengine-maven-plugin</artifactId>
<version>1.3.1</version>
</plugin>
Add a file called appengine-web.xml in src/webapp/WEB-INF with these contents:
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<threadsafe>true</threadsafe>
<runtime>java8</runtime>
</system-properties>
</appengine-web-app>
Exclude JUL to SLF4J Bridge by locating this dependency in the pom:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
and modifying it this way:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
Avoiding out of memory errors:
In src/main/resources add a logging.properties file with:
.level = INFO
and inside src/main/webapp/WEB-INF/appengine-web.xml paste this:
<system-properties>
<property name="java.util.logging.config.file" value="WEB-INF/classes/logging.properties" />
</system-properties>
EDIT:
For steps 3 and 7 you can also go to the project explorer (in case you're using Eclipse) and navigate to Libraries -> Maven dependencies and select each library individually (jul-to-slf4j-1.7.25 and spring-boot-starter-tomcat-1.5.3.RELEASE in my case). Right click on each library and go to Maven -> Exclude Maven artifact... And click Ok. This will have the same effect on the POM as editing.

Related

Adding jsp to spring boot project

I am starting a new project and I am trying to configure spring boot as a web project to use jsp's. I am using Spring Tools Suite 4.
I have added the spring web option while setting up.
I have added the following in the application.properties
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
I have also have the following dependencies in my pom file
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!-- Need this to compile JSP -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
When I try to add a tsp to the main/webapp/WEB-INF/jsp folder I dont get the jsp option.
Try installing the plugin from eclipse marketplace
Go to help -> eclipse marketplace
Then search Eclipse Java EE Developer Tools
Install it and restart your IDE

What do spring.mvc.view.prefix and spring.mvc.view.suffix have to be?

I created a Spring Boot demo app with Maven using Spring Initializr (that's my almost the very first usage of Spring). It works, but for some reason doesn't show any pages besides index.html. If I'm right, that's because of configuration in application.properties, but I just don't know, what have I add there.
My project's sources structure:
src
main
java
irimi
springbootdemo
SpringBootDemoApplication.java
SpringBootDemoApplicationController.java
resources
static
index.html
templates
test-form.html
test-page.jsp
application.properties
I tried to add different prefixes and suffixes into application.properties, but nothing works. Just as an example:
spring.mvc.view.prefix=/templates/
spring.mvc.view.suffix=.html
Again, index.html opens perfectly.
Maybe, it would be good to show here my dependences too:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
That's an error page:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sat Jan 15 11:49:12 MSK 2022
There was an unexpected error (type=Not Found, status=404).
No message available
If my error is really in application.properties, what have I put there?
With Default Rendering with template
If you are using default "/resources/templates" for rendering view.Spring Boot only includes auto-configuration support for the following templating engines:
FreeMarker
Groovy
Thyme-leaf
Velocity
Example:
Step1:
For using thymeleaf you should add dependency either with gradle and maven
Gradle:
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf', version: '2.5.4'
OR
Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.5.4</version>
</dependency>
Step2:
Add below code with properties file
(Optional)spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
With MVC support
By default, this handler serves static content from any of /static, /public, /resources, and /META-INF/resources directories that are on the classpath. Since src/main/resources is typically on the classpath by default, we can place any of these directories there.
Only static folder is available for rendering view.You can customise using below code with properties file.By default Spring Boot will serve static content from a folder called /static (or /public or /resources or /META-INF/resources) in the classpath or from the root of the ServletContext. It uses the ResourceHttpRequestHandler from Spring MVC so you can modify that behavior by adding your own WebMvcConfigurerAdapter and overriding the addResourceHandlers method.
spring.mvc.static-path-pattern=/content/**
spring.web.resources.static-locations=classpath:/files/,classpath:/static-files
More information visit
https://docs.spring.io/spring-boot/docs/1.1.5.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-static-content
https://www.baeldung.com/spring-mvc-static-resources

spring boot tomcat jsp is downloaded not rendered

I am bootstrapping my spring application to spring boot and I have the problem that the embedded tomcat is not rendering the jsp files instead the file will be downloaded.
I have googled and tried everything what I have found so far but I still do anything wrong.
I have the following dependencies in my pom.xml file
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<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>
Clipping from the application.properties
server.port=8080
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
Clipping from the Controller
#GetMapping(value= "/")
public String showPage(Model theModel) {
theModel.addAttribute("scrumbled", new Scrumbled());
return "main";
}
What am I doing wrong that the jsp file is downloaded instead of showing and rendered in the browser?
Thanks in Advance
The problem is with the jasper version. It worked with the below version irrespective of the tomcat version.
<!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-jasper -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper</artifactId>
<version>9.0.24</version>`enter code here`
</dependency>
My tomcat version was 9.0.63.
I have solved the issue.
The problem was a corrupted jar dependency. I had to maven clean, maven install the whole project to see the error. After deleting the jar from the file system maven downloaded the dependency again and now its working.

Maven in Eclipse project: package javax.ws.rs does not exist

In Eclipse, when I go to myProject -> right click -> Run As -> Maven build, I am getting multiple errors in the console outlining that certain packages does not exist, like:
javax.ws.rs does not exist
javax.ws.rs.core does not exist
javax.servlet does not exist
javax.servlet.http doest not exist
Although in my pom.xml, I have provided those dependencies:
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs</artifactId>
<version>1.0</version>
</dependency>
etc
under
<dependencyManagement><dependecies>
tags (don't have any errors in pom.xml).
I do also have proxy settings configured in settings.xml file, and this file is properly linked.
I've also got these jars included locally to WebContent\WEB-INF\lib folder and added to the classpath (I can run my REST service on tomcat, the error "package does not exist" appears only when I am trying to use Maven build".
The reason I need that I want to generate and deploy a .war file.
How I can solve this? Is there a war to force Maven look in local libraries instead?
If you have:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</dependencyManagement>
then you need to have a separate:
<dependencies>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs</artifactId>
</dependency>
</dependencies>
section.
Typically you would define dependencyManagement in a parent pom.xml file and then use the second dependencies fragment in child pom.xml files. This ensures that all your modules depend upon the same consistent artifacts.

Spring boot - Unable to resolve jsp views

I am trying to build a basic MVC app using Spring boot with Hibernate as ORM and MySql as Database. The problem that I am facing is that the jsp views are not getting resolved.
I get a 404 error when I try to fetch the registration form using a GET request with the following URL:
http://localhost:9000/users/register/
This is the set-up that I have in my application.
Directory structure:
-src
-main
-java
-com
ApplicationStart.java
-controllers
UserController.java
-repositories
UserRepository.java
-webapp
-WEB-INF
-jsp
register.jsp
-resources
application.properties
UserController:
#RestController
public class UserController {
private UserRepository userRepository;
#Autowired
public UserController(UserRepository userRepository)
{
this.userRepository = userRepository;
}
#RequestMapping(value = "/users/register", method = RequestMethod.GET)
public String Register()
{
return "register";
}
}
Application.properties:
server.port: 9000
spring.datasource.url: jdbc:mysql://localhost/Contacts
spring.datasource.driverClassName: com.mysql.jdbc.Driver
spring.datasource.username: root
spring.datasource.password:
spring.view.prefix: /WEB-INF/jsp/
spring.view.suffix: .jsp
POM.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- HIBERNATE -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<!-- MYSQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
</dependencies>
MAIN CLASS
#ComponentScan
#Configuration
#EnableAutoConfiguration
public class ApplicationStart {
public static void main(String[] args)
{
SpringApplication.run(ApplicationStart.class, args);
}
}
This is the current setup of my application. Any help on how to resolve the issue is much appreciated.
Please comment if more information is required.
Thanks-
Spring Boot has limited support for JSP, because of its use of an embedded servlet container. From the Spring Boot reference documentation:
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.
Jetty does not currently work as an embedded container with JSPs.
There is a JSP sample so you can see how to set things up.
Start by making your app an executable war, and make sure that you use Tomcat (check the log when you start the application). Unless you explicitly have stated you Jetty should be included, you are using Tomcat since that is provided by default. Alternatively, try change your view technology, which probably requires more initial work, but can significantly reduce the turnaround time during development, see Hotswapping.
I ran into this problem recently while upgrading an old project that needed to have jsps as the view technology with tomcat as an embedded servlet-container. Caveat: Pick an alternative templating engine, and avoid jsps if you can. But if you can't avoid jsps, and your application is not able to resolve them, at the time of this writing (spring-boot 2.x.x), ensure the following:
Ensure that application packaged as a war and not a jar. Although it is not impossible to get jsps to work with a jar packaging, it is a little complicated due to certain limitations. You could just run them with a war package in a server or container just fine like: java -jar war-filename.war
Verify that your controllers have the #Controller annotation
BUT NOT the annnotation #EnableWebMvc. That's because you are using spring-boot to configure WebMVC for you.
Is your controller being scanned and injected as a component? If you have defined your controllers in a different package, maybe you are missing a #ComponentScan annotation?
Are you jsps located and configured correctly? For example, let's say your jsps are located in /src/main/webapp/WEB-INF/jsp/, then your application.properties should have something like so:
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
Also, since you are using spring-boot, there is no need for your Application to extend the SpringBootServletInitializer. It will work too, but to keep it simple, all you need is a class like below:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
FYI, the minimal set of dependencies needed are mentioned below (Maven Example):
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
</parent>
<dependencies>
<!-- spring-boot dependencies below -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- jstl and jsp compilation support below -->
<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>
</dependencies>
Agree with #code4kix, If all of this doesn't work, try adding below property in your application.properties file
spring.thymeleaf.enabled=false
In my case that solved my problem
Location of JSP file: src/main/resources -> /META-INF/resources/WEB-INF/jsp/sayHello.jsp
In pom.xml :
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
In application.properties:
spring.mvc.view.prefix= /WEB-INF/jsp/
spring.mvc.view.suffix= .jsp
#For debug reason
logging.level.org.springframework=debug
In Contoller:
#Controller
public class HelloController {
#RequestMapping("say-hello-jsp")
public String sayHelloJsp() {
return "sayHello";
}
}
Intellij still show it as error, but it works
In IntelliJ, if you have the same configurations and it still doesn't work do this:
File -> Invalidate Caches -> mark first 2 lines -> Invalidate and Restart. Then it will work fine

Categories

Resources