2

I have the following in my Spring Boot configuration:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.setOrder(Ordered.HIGHEST_PRECEDENCE)
            .addResourceHandler("**/*.*")
            .addResourceLocations("file:static/");
}

Since I'm creating a single page app I want this resource handler to deliver static files if the following is true:

  • URL does not start with /api
  • This resource handler contains a file that matches the path from the URL

If there are no matching file, the resource handler should not respond with 404 but let the call through to the controllers of the project.

In one of them I place my fallback to index.html annotation (again unless the URL starts with /api):

@GetMapping({"/**", "/"})

This last part works fine but the problem is that the resource handler returns a 404 if there are no matching files instead of letting the call through (I'm used to the middleware patterns of Node.js and Go) to the controllers. How can I achieve this? Can I create my own resource handler that acts more middleware like?

In Go with Echo for example you just need to enable HTML5 with a skipper function for /api:

func main() {
    server := echo.New()

    server.Use(middleware.Static("static"))
    server.Use(middleware.StaticWithConfig(middleware.StaticConfig{
        Root:    "static",
        HTML5:   true,
        Skipper: noHTML5IfAPICallSkipper,
    }))

    server.Logger.Fatal(server.Start(":1323"))
}

func noHTML5IfAPICallSkipper(context echo.Context) bool {
    if strings.HasPrefix(context.Path(), "/api/") {
        return true
    }

    return false
}

How to enable this single page app routing patterns in Spring Boot?

Oh, and by the way, it's crucial that the static files are served from disk rather than from a classpath or anything else that is packaged inside a jar. This service will run with Docker and it has to be possible to mount the files from outside the container.

tirithen
  • 3,219
  • 11
  • 41
  • 65
  • 1
    https://stackoverflow.com/a/47427729/1032167 probably similar, i ended up using approach with custom `ResourceResolver`. You can specify any location you want to in this custom `ResourceResolver`: file or classpath. It is just a direction for you to look at, because the link answer never passes anything to the controller and returns index page pretty much for every request except static files/api/custom controllers. – varren Dec 05 '17 at 10:13

1 Answers1

2

Try with this:

public class Application  extends WebMvcConfigurerAdapter { // or implements WebMvcConfigurer (Spring Boot 2)

    @Value("${static.path}")
    private String staticPath;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
         registry.addResourceHandler("/**/*.*").addResourceLocations("file:"+staticPath);
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("/index.html");
    }

    ...
}

You must to add to application.properties file the line:

`static.path=path/to/static/content`

If you want to use Docker, this path need to reference to internal docker container directory, an example: /opt/app/statics and then, map the external path to this:

You must to add to application.properties file the line: static.path=/opt/app/statics

And execute docker like this:

docker run ... -v /absolute/static/path/at/host:/opt/app/statics image:version

David Pérez Cabrera
  • 4,960
  • 2
  • 23
  • 37