My Spring Boot app runs perfectly at localhost but when I'm deploying it to Heroku, my app's controller stops seeing the views which are normally located at /templates/ directory. Why does this happen? How can I be sure that heroku actually uploads and compiles my views? If it does, should I change actual values of #RequestMapping of my #Controller class in order to make them reachable when they are at heroku?
You can find my whole working webapp here: https://github.com/slavicketernity/testik56
Here is my uploaded and runnung app: https://testik56app.herokuapp.com/login
In my case it was fault of the slashes on the beginning of the String returned by Controller's method with template location.
After I changed the String returned by controller's methods from
#RequestMapping(value = "/orders/{orderId}/create_entry")
String create(#PathVariable String orderId) {
return "/order_entries/create";
}
to
#RequestMapping(value = "/orders/{orderId}/create_entry")
String create(#PathVariable String orderId) {
return "order_entries/create";
}
then it started to work.
Are you deploying this application as a .jar? I have seen some infrastructures require that you deploy applications as a .war to provide access to your webpage directory.
If that is the issue you can apply the war plugin via gradle.
https://docs.gradle.org/current/userguide/war_plugin.html
Related
I have a spring boot app hosted on AWS Ubuntu instance, deployed using WAR deployment from Jenkins, in Apache tomcat(8.5.14) container.
I have one environment variable defined in application-test.properties file as below-
drehr.config.upload.image = /home/ubuntu/ehrFiles/
(application-test.properties file is used because active profile is set to test)
My java code accesses this property using following syntax:-
import org.springframework.beans.factory.annotation.Value;
#Value("${drehr.config.upload.image}")
private String imagePath;
But I am unable to get its value in imagePath variable, it is coming blank and the code is failing. Please provide some way to the solution for this.
Also tried changing the property value inside apache-tomcat-x/webapps/drehrweb-0.0.1/WEB-INF/classes/application-test.properties. Still doesn't work.
The strange thing is the same code works fine on development environment(using spring tool suite).
I want to use Thymeleaf in a Spring Boot 2.1.5 based application. But I do not need it to create html output for a RestController. Instead of that I want it to create html files that the application can store on disk.
Because of this I create two beans templateResolver and templateEngine like the docs describe. The templates are stored in the same location I would use for the RestController: src/main/resources/templates. One for example is called index.html.
But no matter which path I configure (with or without classpath) I get the same error message:
templateResolver.setApplicationContext(this.applicationContext);
templateResolver.setPrefix("classpath:/resources/templates/");
templateResolver.setSuffix(".html");
java.io.FileNotFoundException: class path resource
[resources/templates/index.html] cannot be opened because it does not
exist
How do I need to configure the path to make it work a) inside STS and b) inside the created jar ?
An alternative to solving this problem would be using spring-boot-starter-thymeleaf instead and "grabbing" its generated output instead of exposing it via the embedded Tomcat but I do not know how to get this to work:
#GetMapping("/noneedforthis")
public String getIndexFileContent(#RequestParam(name="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
return "index";
}
I checked both the local target directory of my Eclipse workspace and the jar created by running maven install: instead of resources/templates the templates are stored in templates.
Shortening the path in my code helped and now Thymeleaf can find the templates.
Using the Spring Boot Starter for Thymeleaf would still be an interesting alternative but so far I have not found an approach.
I have a spring boot 2 app with embedded vuejs font-end at /static, using gradle 5.1. The app is designed to be hosted on different servers, so the API url for vuejs app must be dynamic.
The most reasonable solution i can think of is to set API_IP environment variables at the servers and let the vuejs app retrieve them like this:
let url = `http://${process.env.API_IP}:9090/api`;
if (process.env.NODE_ENV === 'development') {
url = `http://localhost:8090/api`;
}
gradle build script:
bootJar {
dependsOn ':ui:jar'
into('BOOT-INF/classes/static') {
from "${project(':ui').projectDir}/dist"
}
launchScript {
properties 'inlinedConfScript': 'startScript'
}
}
However, i'm failing to pass the environment variable to vue app. Each try ends up with process.env.API_IP being undefined. process.env always consists only of BASE_URL and NODE_ENV.
tried:
export API_IP=*ip* and then run the spring boot app.
set the variable in /etc/environment, logout, login, run the spring boot app
pass it as run argument -DAPI_IP=*api*
set JAVA_OPTS=-DAPI_IP=*api*
according to https://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html :
create file for inlinedConfScript containing API_IP=*api* and JAVA_OPTS=-DAPI_IP=*api* or only one of each.
create .conf file in the same dir with the .jar file withe the same value options as in #5.
Please help :)
Partial solution was in removing the ip/domain from the vuejs requests as the #tianzhipeng's comment. However i can run the back-end only at port 8080 in this case.
I have a Spring Boot app. I have deployed it to .jar and everything works perfectly.
I have tried deploying it to .war that I place in webapps in Tomcat. My app has a login page, an index page, and one other page on /patchdetails.
I have a MVC controller that returns that page:
#RequestMapping(value = "/patchdetails", method = RequestMethod.GET)
#ResponseStatus(value = HttpStatus.OK)
public String patchDetail() {
return "patchDetails";
}
The page is located on src/main/resources/templates/patchDetails.html.
When I try to access this page the server(Tomcat) shows the 404 error page.
Can anybody explain why deploying to jar works but deploying to war doesn't?
I have an AWS lambda RequestHandler class which is invoked directly by AWS. Eventually I need to get it working with Spring Boot because I need it to be able to retrieve data from Spring Cloud configuration server.
The problem is that the code works if I run it locally from my own dev environment but fails to inject config values when deployed on AWS.
#Configuration
#EnableAutoConfiguration
#ComponentScan("my.package")
public class MyClass implements com.amazonaws.services.lambda.runtime.RequestHandler<I, O> {
public O handleRequest(I input, Context context) {
ApplicationContext applicationContext = new SpringApplicationBuilder()
.main(getClass())
.showBanner(false)
.web(false)
.sources(getClass())
.addCommandLineProperties(false)
.build()
.run();
log.info(applicationContext.getBean(SomeConfigClass.class).foo);
// prints cloud-injected value when running from local dev env
//
// prints "${path.to.value}" literal when running from AWS
// even though Spring Boot starts successfully without errors
}
}
#Configuration
public class SomeConfigClass {
#Value("${path.to.value}")
public String foo;
}
src/main/resources/bootstrap.yml:
spring:
application:
name: my_service
cloud:
config:
uri: http://my.server
failFast: true
profile: localdev
What have I tried:
using regular Spring MVC, but this doesn't have integration with #Value injection/Spring cloud.
using #PropertySource - but found out it doesn't support .yml files
verified to ensure the config server is serving requests to any IP address (there's no IP address filtering)
running curl to ensure the value is brought back
verified to ensure that .jar actually contains bootstrap.yml at jar root
verified to ensure that .jar actually contains Spring Boot classes. FWIW I'm using Maven shade plugin which packages the project into a fat .jar with all dependencies.
Note: AWS Lambda does not support environment variables and therefore I can not set anything like spring.application.name (neither as environment variable nor as -D parameter). Nor I can control the underlying classes which actually launch MyClass - this is completely transparent to the end user. I just package the jar and provide the entry point (class name), rest is taken care of.
Is there anything I could have missed? Any way I could debug this better?
After a bit of debugging I have determined that the issue is with using the Maven Shade plugin. Spring Boot looks in its autoconfigure jar for a META-INF/spring.factories jar see here for some information on this. In order to package a Spring Boot jar correctly you need to use the Spring Boot Maven Plugin and set it up to run during the maven repackage phase. The reason it works in your local IDE is because you are not running the Shade packaged jar. They do some special magic in their plugin to get things in the right spot that the Shade plugin is unaware of.
I was able to create some sample code that initially was not injecting values but works now that I used the correct plugin. See this GitHub repo to check out what I have done.
I did not connect it with Spring Cloud but now that the rest of the Spring Boot injection is working I think it should be straightforward.
As I mentioned in the comments you may want to consider just a simple REST call to get the cloud configuration and inject it yourself to save on the overhead of loading a Spring application with every request.
UPDATE: For Spring Boot 1.4.x you must provide this configuration in the Spring Boot plugin:
<configuration>
<layout>MODULE</layout>
</configuration>
If you do not then by default the new behavior of the plugin is to put all of your jars under BOOT-INF as the intent is for the jar to be executable and have the bootstrap process load it. I found this out while addressing adding a warning for the situation that was encountered here. See https://github.com/spring-projects/spring-boot/issues/5465 for reference.