Set specific URL for static files using Spark Framework
Asked Answered
M

1

8

I'm using Spark to serve a web page.. For the static files I initialize Spark like stated here:

So I have this structure:

/src/main/resources/public/
                      |-- foo/
                           |-- css/
                           |    |-- bootstrap.css
                           |-- js/
                           |    ...
                           |-- img/
                                ...

I made the foo folder to make a trick because my webpage is located under /foo url..like this:

http://www.example.com/foo/index

So my static files are loaded like this for example:

http://www.example.com/foo/css/bootstrap.css

What I want now is to have this path variable.. Because I have different environments and for example if I deploy this app in another domain I want it to be:

http://www.example2.com/superfoo/css/bootstrap.css

But for this I have to change the release and change the folder...

For the controllers I made this easily:

Example:

    Spark.get(this.appBasePath + "/users", (request, response) -> {
        return this.getUsersView(request);
    }, new FreeMarkerEngine());

this.appBasePath comes from a configuration that is loaded deciding the environment.

So what I am asking is to set programmatically the static files URL without making any folder. Is there any way to achieve this?

Misname answered 29/1, 2015 at 20:58 Comment(12)
why change the code per environment. build your app around conventions. eg. put all your static external to the app. the app can then call the same path, filenames, and the environment supplies different versions.Instructor
@domfarr I just want to change the url per env, not the code, thats why.Misname
I think we are saying the same thing. The path foo vs superfoo is what needs to change. Agree the standard, or convention if you will, then the code does not change between deployment to different environments.Instructor
Perhaps it would be easier if you explain why you need different directory paths for different environments?Instructor
Ok, then post an answer telling me how to do that. What I am saying is that there seems to be no way of doing that without changing the folder's name.Misname
Can you explain the difference between foo and superfoo (are the bootstrap.css files the same?)Instructor
without understand the difference between environments or bootstrap.css I cannot offer a workable solution.Instructor
I think you are not understanding my question (maybe I didn't ask the correct way). The problem is that Spark uses the folder's path to serve the static content in an specific path. So if change the folder's name, then the static files should be accesed in a different url. What I wan't to achieve is that coming from a property that changes depending on the env, set the context in which the application would run. So that in one environment I would have /env1/css/bootstrap.css and in another I would have /env1/css/bootstrap.css withoud changing the code, just a property.Misname
I cannot do thas because I would have to change the folder's name and that means using a different release.Misname
Let us continue this discussion in chat.Instructor
I would also like to be able to change my web root. Currently it looks like this requires serving everything dynamically.Bedew
@Bedew yes, I didn't find a solution to this. SorryMisname
B
5

I ended up working around this problem by generating a get route for all my static files. It is entirely possible that there are way easier ways of doing this directly in spark, but it took less time to write this code than to understand the details of the spark.resource package.

First, I define some helper functions to let me iterate over all files in a particular resource directory (requires Java 8):

/**
 * Find all resources within a particular resource directory
 * @param root base resource directory. Should omit the leading / (e.g. "" for all resources)
 * @param fn Function called for each resource with a Path corresponding to root and a relative path to the resource.
 * @throws URISyntaxException
 */
public static void findResources(String root,BiConsumer<Path,Path> fn) throws URISyntaxException {
    ClassLoader cl = Main.class.getClassLoader();
    URL url = cl.getResource(root);     
    assert "file".equals(url.getProtocol());
    logger.debug("Static files loaded from {}",root);
    Path p = Paths.get(url.toURI());
    findAllFiles(p, (path) -> fn.accept(p,p.relativize(path)) );
}
/**
 * Recursively search over a directory, running the specified function for every regular file.
 * @param root Root directory
 * @param fn Function that gets passed a Path for each regular file
 */
private static void findAllFiles(Path root, Consumer<Path> fn) {
    try( DirectoryStream<Path> directoryStream = Files.newDirectoryStream(root)) {
        for(Path path : directoryStream) {
            if(Files.isDirectory(path)) {
                findAllFiles(path, fn);
            } else {
                fn.accept(path);
            }
        }
    } catch (IOException ex) {}
}

Then I use this to define a new GET route for each file

String webroot = "/server1";
findResources("static", (root,path) -> {
    String route = webroot+"/"+path;
    String resourcePath = "/static/"+path.toString();
    logger.debug("Mapping {} to {}",route, resourcePath);
    get(webroot+"/"+path, (req,res) -> {
        Files.copy(root.resolve(path), res.raw().getOutputStream());
        AbstractFileResolvingResource resource = new ExternalResource(resourcePath);
        String contentType = MimeType.fromResource(resource);
        res.type(contentType );
        return "";
    } );
});
Bedew answered 11/11, 2016 at 21:17 Comment(1)
Were there any aspects of your question this doesn't answer?Bedew

© 2022 - 2024 — McMap. All rights reserved.