SpringBoot : ServletContext resource cannot resolve S3 URL - java

I'm developing a Spring Boot application in which I'm integrating Amazon S3 service. This class is my repository to access the S3 bucket :
public class S3FileRepository implements ImageRepository {
private String bucket;
private AmazonS3 s3Client;
private ResourceLoader resourceLoader;
public S3FileRepository(ResourceLoader resourceLoader, AmazonS3 s3Client, String bucket) {
this.resourceLoader = resourceLoader;
this.s3Client = s3Client;
this.bucket = bucket;
}
private static String toS3Uri(String bucket, String imageName) {
return String.format("s3://%s/%s", bucket, imageName);
}
#Override
public Resource getImage(String name) {
return resourceLoader.getResource(S3FileRepository.toS3Uri(this.bucket, name).concat(this.IMAGE_EXTENSION));
}
using Spring Boot Autoconfiguration as suggested. So in my pom.xml, among other things, I've
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-aws-autoconfigure</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-aws-context</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
Moreover I've an application.properties done like this:
cloud.aws.credentials.accessKey= (mykey)
cloud.aws.credentials.secretKey= (mysecret)
cloud.aws.credentials.instanceProfile=true
cloud.aws.region.static=eu-west-2
cloud.aws.stack.auto=false
The problem:
Everything works fine if i compile my project and then I simply run the JAR with java -jar target/myproject.jar, i correctly get the image that I ask for and everything is fine.
Instead if I run the project with the IDE default mvn spring-boot:run when I try to get an image (present in the bucket) an Exception occour saying following:
ServletContext resource [/s3://mybucket/test.jpeg] cannot be resolved to URL because it does not exist
java.io.FileNotFoundException: ServletContext resource [/s3://mybucket/test.jpeg] cannot be resolved to URL because it does not exist
So what I think is that it throws an Exception because it's like it goes inside the jar to look for something that match s3://mybucket/test.jpeg but I can't get why, and why it happens only running the project with mvn spring-boot:run and not running the jar.

You're likely hitting the spring-cloud-aws issue #384 whereupon the spring-boot-devtools dependency, which is activated when you start the application from the IDE, activates a different code path in resource loading.
You can test whether you're hitting this issue by removing the spring-boot-devtools dependency from your pom.xml file, reloading the project in your IDE, and running the same test.

There is a difference between app's launching with "java -jar" and "mvn spring-boot:run". From Spring Boot docs: "The Spring Boot Maven plugin includes a run goal that can be used to quickly compile and run your application. Applications run in an exploded form, as they do in your IDE". It can be a reason of problem.

Related

How I can deploy existing web applications (wars) in the Spring Boot embedded server (tomcat)

I have an application which allows to dynamically generate web applications (wars) and I would like to deploy these applications in a server to test them and I think of putting them in the same embedded server of spring, here is how I solved the problem with a simple main java.
public class Main {
private final static Logger logger = LoggerFactory.getLogger(Main.class);
private final static File catalinaHome = new File(
"C:\\Users\\Dev\\Desktop\\demo\\userstory-2\\compiler\\patternHost");
private static Tomcat tomcat = null;
public static void main(String[] args) {
tomcat = new Tomcat();
tomcat.setPort(8080);
tomcat.setBaseDir(catalinaHome.getAbsolutePath());
tomcat.getHost().setAutoDeploy(true);
tomcat.getHost().setDeployOnStartup(true);
tomcat.getServer().addLifecycleListener(new VersionLoggerListener());
tomcat.getHost().addLifecycleListener(new HostConfig());
try {
tomcat.start();
} catch (LifecycleException e) {
logger.error("Tomcat could not be started.");
e.printStackTrace();
}
logger.info("Tomcat started on " + tomcat.getHost());
tomcat.getServer().await();
}
}
How can I do the same with spring boot. ?
I have converted a non-spring app to spring boot in this way and it worked for me. I was able to run it with spring boot embedded tomcat. Hope this helps.
Spring boot is all about speed, it comes with embedded-tomcat server(provided you use spring-boot-starter-web dependency) and now all you need is java to run your standalone spring boot application. It reduces the manual steps of copying war file to tomcat's webapp folder and then starting it.
Try the approach which suits your app.
If your old app is spring based :
Create a new spring boot starter web project and copy your old source code to this new project. Modify application.properties, resources folder, add all required dependencies in pom.xml file and change package as war.
Do a mvn clean install it will generate a war file (with embedded
tomcat) in target folder of your project's root directory. Now to run it all you
need to do is, in your target folder open terminal and run java -jar your_warFileName.war it will start the application.
If your old app is not a spring based:
Again start with new spring boot starter web project and copy your source code but then to use your old code with spring-boot, first you have to do clean-up stuff like adding #RestController to controller classes, declaring beans by marking classes with #Service or #Component and autowiring beans in the appropriate places. Once your code compiles fine then to run it your can use step 2 as above.

Spring Boot app deployed to Heroku doesn't locate its' thymeleaf views

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

Deploying SpringBoot war file to Tomcat results in 404, local host works fine

I've been using SpringBoot to develop a webapp - running it on localhost works fine, both using a jar and war to run it from terminal such that:
mvn install && java -jar target/Eeeeek-0.0.1-SNAPSHOT.jar
and
java -jar target/Eeeeek-1.3.2.BUILD-SNAPSHOT.war
both work fine, I'm now only packaging as a war file.
The site is visible at http://localhost:8080
I'm now trying to deploy it to my tomcat manager hosted by digitalOcean.
visiting the ip of the droplet http://46.101.2.91:8080 shows the tomcat manager which is great, I then deploy using the manager but encounter errors when I try and access it.
Ideally I'd like the app to eb the landing page of the ipaddress. Any help is appreciated, thank you.
The url when I click the link in manager is http://46.101.2.91:8080/Eeeeek%2D1%2E3%2E2%2EBUILD%2DSNAPSHOT/ which doesn't look right...
EDIT: As per the answer given I've deleted the .war and filter from webapps, ran a mvn clean package. Then used the manager to upload the new shiny war. During the upload the page crashed with an error at URL http://46.101.2.91/manager/html/upload?org.apache.catalina.filters.CSRF_NONCE=846E819F21EFBBE715AFBFA39F349E34
I returned to the main and found that the app had been uploaded.
Checking webapps dir also confirmed but the same error persisted.
Does your main class extend the good class? It was my problem. Here an example:
#SpringBootApplication
public class DeployTestApplication extends SpringBootServletInitializer{
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(DeployTestApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(DeployTestApplication.class, args);
}
}
Also I had to add this to Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
Check Your web apps directory is this war file or any folder
(Eeeeek-1.3.2.BUILD-SNAPSHOT) is already there.
if it is so then delete it and reinstall using maven or copy the war file to the webapps directory and restart the Tomcat.
If again problem occurs then check ur web.xml otherwise another issue what i found in my project deploement was Major minor version Exception Problem.
I can't say exactly but u should try these solutions may work for you..
Thanks

Spring controllers extending external abstract class throws classNotFoundException

So I have a spring controller that looks like:
#Controller // the org.springframework.stereotype.Controller
#RequestMapping("/test")
public class TestController extends BaseController {
...
}
And this works fine. However when I am trying to refactor the code, to move BaseController to an external project "common", the project build will fail with followint stacktrace:
SEVERE: Servlet /mee threw load() exception
java.io.FileNotFoundException: class path resource [ca/wherego/common/controllers/BaseController.class] cannot be opened because it does not exist
at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:157)
at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:49)
at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:80)
I have tried two ways of using the external project:
1) Let maven uses it as:
<dependency>
<groupId>my.api</groupId>
<artifactId>common</artifactId>
<version>1.0.1</version>
<scope>system</scope>
<systemPath>${basedir}/lib/common-1.0.1.jar</systemPath>
</dependency>
and place the maven in the correct folder ( I don't have a private maven build, so I can't properly upload it as I use other public maven dependencies).
2) I tried to use the "common" project as the project dependency in the build path.
However none of the methods work.. Am I missing anything? Thanks!

FileNotFoundException in test case run with maven using Spring resource loader

Our program is sending mails. For sending mails it includes an attachment.
The project is set up with maven. The JUnit test case loads the spring configuration first. Spring is loading the File with its DefaultResourceLoader. When running this directly within the workspace its running fine, however as a maven test it fails.
Spring Configuration for resource loader:
<property name="defaultResourceLoader">
<bean class="org.springframework.core.io.DefaultResourceLoader" />
</property>
ImplementingClass:
#Service
public class SomeClassA {
#Autowired
private DefaultResourceLoader defaultResourceLoader;
#Value("${mailLogoPath}")
private String mailLogo;
public void someMethod(){
String filePath = defaultResourceLoader.getResource(mailLogo).getFile().getAbsolutePath();
}
}
The exception points to the actual problem and difference:
java.io.FileNotFoundException: class path resource [templates/efmaillogo.jpg] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/C:/IBM/workspace/efMy10/ef-mvxsrv-reactor/ef-mvxsrv-service-resources/target/ef-mvxsrv-service-resources-1.5.23-SNAPSHOT.jar!/templates/efmaillogo.jpg
at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:204)
at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:52)
at SomeClassA.someMethod(SomeClassA.java:9)
Spring tries to look the file up within the jar. When running it as a junit test within eclipse, everything is working, because spring finds the file directly within the workspace. However when running the same unit test with maven it fails, because it doesn't find the file, because its in a jar in a different module. The file in the other module is needed by different modules, so I don't want to move it. On the application server where everything is deployed its working as well, because the .ear file is expanded.
I'm wondering if there is a different way to access the file with Spring, so that I don't have to skip this test case with maven.
Update
Tried doing a lookup for the file with:
String filePath = defaultResourceLoader.getResource(mailLogo).getURL.getFile();
However it now fails when actually sending the mail with Transport.send(msg).
java.io.FileNotFoundException: file:\C:\Users\uhe.m2\repository\com\clavisit\ef\mvxsrv\ef-mvxsrv-service-resources\1.5.23-SNAPSHOT\ef-mvxsrv-service-resources-1.5.23-SNAPSHOT.jar!\templates\efmaillogo.jpg (The filename, directory name, or volume label syntax is incorrect.)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1141)
at javax.mail.Transport.send0(Transport.java:195)
at javax.mail.Transport.send(Transport.java:124)
at com.clavisit.ef.ep.service.integration.handler.mail.SendMail.sendMessage(SendMail.java:153)
String filePath = defaultResourceLoader.getResource(mailLogo).getURL().getFile();
The above code change must work as per the discussion in this thread http://www.coderanch.com/t/474047/Spring/Spring-cannot-find-file-classpath

Categories