How to fetch file from azure blob using spring boot - azure-blob-storage

I want to fetch files from Azure blob storage. Following code does it fine-
package com.<your-resource-group>.<your-artifact-name>;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.WritableResource;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
#RestController
#RequestMapping("blob")
public class BlobController {
#Value("azure-blob://<your-container-name>/<your-blob-name>")
private Resource blobFile;
#GetMapping("/readBlobFile")
public String readBlobFile() throws IOException {
return StreamUtils.copyToString(
this.blobFile.getInputStream(),
Charset.defaultCharset());
}
#PostMapping("/writeBlobFile")
public String writeBlobFile(#RequestBody String data) throws IOException {
try (OutputStream os = ((WritableResource) this.blobFile).getOutputStream()) {
os.write(data.getBytes());
}
return "file was updated";
}
}
My Question -
The #Value annotation provides value to the Resource that is static (i.e I cannot put any variable containing my path as a string inside #Value).
How can I implement the this

In application properties try storing the path
#application.properties
blob.path=
We can use #Value("${...property's name}") annotation to access the above property in the Java class as follows:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class ValueController {
#Value("${blob.path}")
private String path;
#GetMapping("")
..
}
}
Here try to use blob uri complete path in application properties and use the same in #value annotation as variable by map datatype
//
#Value("${blob.path}")
private Map<String, String> blobPath;
See this > java - How to read external properties based on value of local variable in Spring Boot? - Stack Overflow
& Value Spring: Spring #Value annotation tricks - DEV Community
Also see Requestmapping
Other references :
Spring Azure Blob Storage | DevGlan
spring batch - How to read the csv files from Azure Blob Storage in
Java with folder structure as 'dir1 / dir2 / dir3 /..'? - Stack Overflow

Related

ClassPath resource can not be accessed in Docker Spring

I have a userService file which includes this code:
package com.example.demo.services;
import com.example.demo.entity.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
#Service
public class UserService {
public static AtomicReference<UserService> INSTANCE = new AtomicReference<UserService>();
public static List<User> userList ;
public UserService() throws IOException {
final UserService previous = INSTANCE.getAndSet(this);
userList = new ObjectMapper().readValue(
new ClassPathResource("db/user.json").getFile(),
new ObjectMapper().getTypeFactory().constructCollectionType(List.class, User.class));
if(previous != null)
throw new IllegalStateException("Second singleton " + this + " created after " + previous);
}
public static UserService getInstance() {
return INSTANCE.get();
}
}
In this Service I am loading a JSON file into the variable userList and the JSON file is stored in src/main/resources/db/user.json. This works fine in the IDE. But when I creates a Jar file either via Intellij or manually, the db/user.json is stored in BOOT-INF/classes/db/user.json (inspected via this command: jar tf backend.jar).
The Docker Image could not get started as it could not find the file. So how would I change this so that it should work both in normal debug and Docker image?
To be noted, userList converts the JSON file in the List.

Transfer a file using Apache Camel file component

I am trying a demo file transfer program using Spring Boot and Apache Camel file component. I have exposed a REST Controller using Spring Boot which is calling an Apache Camel route and it is doing the file transfer. I have three files in the directory C:\CamelDemo\inputFolder namely input1.txt, input2.txt and input3.txt. I want to only transfer the file input2.txt in the output folder. My Spring Boot controller is as below:
package com.example.demo.controller;
import java.util.HashMap;
import java.util.Map;
import org.apache.camel.ProducerTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/camel")
public class FileTransferController {
#Autowired private ProducerTemplate producerTemplate;
#RequestMapping(value="/file", method=RequestMethod.GET)
public String callCamelRoute() {
String fileName = "input2.txt";
Map<String, Object> headerMap = new HashMap<String, Object>();
headerMap.put("fileName", fileName);
producerTemplate.sendBodyAndHeaders("direct:transferFile", null, headerMap);
return "Route invoked";
}
}
My Route is as below:
package com.example.demo.route;
import org.apache.camel.LoggingLevel;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;
#Component
public class FileTransferRoute extends RouteBuilder {
#SuppressWarnings("deprecation")
#Override
public void configure() {
errorHandler(defaultErrorHandler()
.maximumRedeliveries(3)
.redeliverDelay(1000)
.retryAttemptedLogLevel(LoggingLevel.WARN));
from("direct:transferFile")
.log("Route reached")
.log("file:C:\\CamelDemo\\inputFolder?fileName=${in.headers.fileName}&noop=true")
.pollEnrich("file://C:/CamelDemo/inputFolder?fileName=${in.headers.fileName}&noop=true")
.to("file://C:/CamelDemo/outputFolder?autoCreate=false")
.end();
}
}
But the first time I invoke this route, the file input1.txt is getting transferred even when I have specified the fileName parameter. Please help.
I think the issue is that your file name isn't being set, because you're not telling Camel that you're using a Simple expression, rather than a fixed URI.
Looking at the manual (https://camel.apache.org/manual/latest/pollEnrich-eip.html#_using_dynamic_uris), it implies that you will need
.pollEnrich().simple("file://C:/CamelDemo/inputFolder?fileName=${in.headers.fileName}&noop=true")
to be able to use the dynamic endpoint.

Is it possible to serve the swagger root from a sub path as opposed to the applcation context root?

I followed this example swagger configuration but would like to set the swagger root (the path with which the swagger.json is served) to <jersey-context-root>/api-or-some-other-path except that no matter what I pass to the config.setBasePath(some-sub-path); the swagger root is always the jersey app-context root defined in the application.yml file, i.e: spring.jersey.application-pathso it seems the basePath is hard-wired.
Look at your link and the code
this.register(ApiListingResource.class);
That ApiListingResource is the actual resource class that serves up the swagger.json endpoint. If you look at the link, you can see the class is annotated with the path (the {type:json|yaml} determines what type if data you will get back).
#Path("/swagger.{type:json|yaml}")
If you want to change the path, you need to register it differently. What you need to do is use the Resource.builder(ResourceClass) method to get a builder where we can change the path. For example you can do something like this.
Resource swaggerResource = Resource.builder(ApiListingResource.class)
.path("foobar/swagger.{type:json|yaml}")
.build();
Then instead of the the ResourceConfig#register() method, you use the ResourceConfig#registerResource(Resource) method.
this.registerResource(swaggerResource);
Here's a complete test using Jersey Test Framework
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.model.Resource;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class ResourceBuilderTest extends JerseyTest {
#Path("/swagger.{type:json|yaml}")
public static class ApiListingResource {
#GET
#Produces("text/plain")
public String get() {
return "Hello World!";
}
}
#Override
public ResourceConfig configure() {
Resource swaggerResource = Resource.builder(ApiListingResource.class)
.path("foobar/swagger.{type:json|yaml}")
.build();
ResourceConfig config = new ResourceConfig();
config.registerResources(swaggerResource);
return config;
}
#Test
public void testIt() {
Response response = target("foobar/swagger.json")
.request()
.get();
String data = response.readEntity(String.class);
System.out.println(data);
assertEquals("Hello World!", data);
}
}

Spring cannot serve end point

I have a simple Spring back-end. It has a folder that contains controllers.
package com.movieseat.controllers;
// Java imports
import java.util.List;
// Spring imports
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
// Project imports
import com.movieseat.models.Movie;
import com.movieseat.services.MovieService;
#RestController
#RequestMapping("/api/movies")
public class MovieController {
#Autowired
private MovieService movieService;
#RequestMapping(value = "/allMovies", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<Movie> getAllMovies() {
return movieService.getAllmovies();
}
}
In my Angular service I have a getAll() method:
public getAll<T>(): Observable<T[]> {
return this.http.get<T[]>('/api/movies/allMovies');
}
When I run the application I get a:
GET http://localhost:8090/api/movies/allMovies 404 ()
I have the server running on port 8090.
The following structure is used:
com
movieseat
Application.java
controllers
MovieController.java
models
MovieModel.java
repositories
MovieRepository.java
services
impl
MovieServiceImpl.java
MovieService.java
See if your controller class is picked up by spring scanning and performs mapping correctly. For example - If you are using Spring Boot, put a #SpringBootApplication on your main class that runs the app. The best way to know if your endpoint is scanned is to look for it when spring launches (in the log). You should look for something like
2017-09-17 14:45:49.522 INFO 2873 --- [main] RequestMappingHandlerMapping : Mapped "{[/allMovies],methods=[GET]}" onto public java.lang.String com.movieseat.controllers.MovieController.getAllMovies...

How to service external static HTML files in Spring Boot Embedded tomcat?

I'm new to Spring framework and Spring Boot.
I've implemented a very simple RESTful Spring Boot web application.
You can see the nearly full source code in another question: Spring Boot: How to externalize JDBC datasource configuration?
How can the app service external static HTML, css js files?
For example, the directory structure may be as follows:
MyApp\
MyApp.jar (this is the Spring Boot app that services the static files below)
static\
index.htm
images\
logo.jpg
js\
main.js
sub.js
css\
app.css
part\
main.htm
sub.htm
I've read the method to build a .WAR file that contains static HTML files, but since it requires rebuild and redeploy of WAR file even on single HTML file modification, that method is unacceptable.
An exact and concrete answer is preferable since my knowledge of Spring is very limited.
I see from another of your questions that what you actually want is to be able to change the path to static resources in your application from the default values. Leaving aside the question of why you would want to do that, there are several possible answers.
One is that you can provide a normal Spring MVC #Bean of type WebMvcConfigurerAdapter and use the addResourceHandlers() method to add additional paths to static resources (see WebMvcAutoConfiguration for the defaults).
Another approach is to use the ConfigurableEmbeddedServletContainerFactory features to set the servlet context root path.
The full "nuclear option" for that is to provide a #Bean definition of type EmbeddedServletContainerFactory that set up the servlet container in the way you want it. If you use one of the existing concrete implementations they extend the Abstract* class that you already found, so they even have a setter for a property called documentRoot. You can also do a lot of common manipulations using a #Bean of type EmbeddedServletContainerCustomizer.
Is enough if you specify '-cp .' option in command 'java -jar blabla.jar' and in current directory is 'static' directory
Take a look at this Dave Syer's answer implementation.
You can set the document root directory which will be used by the web context to serve static files using ConfigurableEmbeddedServletContainer.setDocumentRoot(File documentRoot).
Working example:
package com.example.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.io.File;
import java.nio.file.Paths;
#Configuration
public class WebConfigurer implements ServletContextInitializer, EmbeddedServletContainerCustomizer {
private final Logger log = LoggerFactory.getLogger(WebConfigurer.class);
private final Environment env;
private static final String STATIC_ASSETS_FOLDER_PARAM = "static-assets-folder";
private final String staticAssetsFolderPath;
public WebConfigurer(Environment env, #Value("${" + STATIC_ASSETS_FOLDER_PARAM + ":}") String staticAssetsFolderPath) {
this.env = env;
this.staticAssetsFolderPath = staticAssetsFolderPath;
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
if (env.getActiveProfiles().length > 0) {
log.info("Web application configuration, profiles: {}", (Object[]) env.getActiveProfiles());
}
log.info(STATIC_ASSETS_FOLDER_PARAM + ": '{}'", staticAssetsFolderPath);
}
private void customizeDocumentRoot(ConfigurableEmbeddedServletContainer container) {
if (!StringUtils.isEmpty(staticAssetsFolderPath)) {
File docRoot;
if (staticAssetsFolderPath.startsWith(File.separator)) {
docRoot = new File(staticAssetsFolderPath);
} else {
final String workPath = Paths.get(".").toUri().normalize().getPath();
docRoot = new File(workPath + staticAssetsFolderPath);
}
if (docRoot.exists() && docRoot.isDirectory()) {
log.info("Custom location is used for static assets, document root folder: {}",
docRoot.getAbsolutePath());
container.setDocumentRoot(docRoot);
} else {
log.warn("Custom document root folder {} doesn't exist, custom location for static assets was not used.",
docRoot.getAbsolutePath());
}
}
}
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
customizeDocumentRoot(container);
}
}
Now you can customize your app with command line and profiles (src\main\resources\application-myprofile.yml):
> java -jar demo-0.0.1-SNAPSHOT.jar --static-assets-folder="myfolder"
> java -jar demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=myprofile

Resources