最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Serve static folder with Spring Boot and React Router - Stack Overflow

programmeradmin5浏览0评论

I have a React client application which is build and piled into the Java resource folder

src/main/resources/static

Content of the static folder is then served by standard Spring Boot application with no issues.

However, when I will start to use React Router, I need to be able to resolve this path:

localhost:8080/userSettingsPage

into index.html:

src/resource/static/index.html

I'm aware that I can do this in Controller as follow:

@Controller
public class MyController {
    @RequestMapping("/userSettingsPage")
    public String getIndex() {
       return "index.html";
    }
}

However I would like to specify my Controller in more generic way:

  1. If URL {path} ends with any of ".html", ".js", ".json", ".csv", ".css", ".png", ".svg", ".eot", ".ttf", ".woff", ".appcache", ".jpg", ".jpeg", ".gif", ".ico", then return file in /static/{path}
  2. Else return /static/index.html

How can I achieve it?

I have a React client application which is build and piled into the Java resource folder

src/main/resources/static

Content of the static folder is then served by standard Spring Boot application with no issues.

However, when I will start to use React Router, I need to be able to resolve this path:

localhost:8080/userSettingsPage

into index.html:

src/resource/static/index.html

I'm aware that I can do this in Controller as follow:

@Controller
public class MyController {
    @RequestMapping("/userSettingsPage")
    public String getIndex() {
       return "index.html";
    }
}

However I would like to specify my Controller in more generic way:

  1. If URL {path} ends with any of ".html", ".js", ".json", ".csv", ".css", ".png", ".svg", ".eot", ".ttf", ".woff", ".appcache", ".jpg", ".jpeg", ".gif", ".ico", then return file in /static/{path}
  2. Else return /static/index.html

How can I achieve it?

Share Improve this question asked Jun 29, 2021 at 12:21 JurassJurass 5961 gold badge7 silver badges20 bronze badges 2
  • Does this answer your question stackoverflow./questions/39331929/… – dee Commented Jun 29, 2021 at 12:41
  • Unfortunatelly it doesn't. – Jurass Commented Jun 30, 2021 at 11:24
Add a ment  | 

3 Answers 3

Reset to default 5

After lot of research and trying various approaches I have e to conclusion that the simplest solution would be to implement Filter and handle serving of static web files on my own, which bypasses the Spring's handling:

@Component
public class StaticContentFilter implements Filter {
    
    private List<String> fileExtensions = Arrays.asList("html", "js", "json", "csv", "css", "png", "svg", "eot", "ttf", "woff", "appcache", "jpg", "jpeg", "gif", "ico");
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        doFilter((HttpServletRequest) request, (HttpServletResponse) response, chain);
    }
    
    private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String path = request.getServletPath();
        
        boolean isApi = path.startsWith("/api");
        boolean isResourceFile = !isApi && fileExtensions.stream().anyMatch(path::contains);
        
        if (isApi) {
            chain.doFilter(request, response);
        } else if (isResourceFile) {
            resourceToResponse("static" + path, response);
        } else {
            resourceToResponse("static/index.html", response);
        }
    }
    
    private void resourceToResponse(String resourcePath, HttpServletResponse response) throws IOException {
        InputStream inputStream = Thread.currentThread()
                .getContextClassLoader()
                .getResourceAsStream(resourcePath);
        
        if (inputStream == null) {
            response.sendError(NOT_FOUND.value(), NOT_FOUND.getReasonPhrase());
            return;
        }
        
        inputStream.transferTo(response.getOutputStream());
    }
}

Jurass's answer worked for me, but I needed to set ContentType headers. Without correct headers the browser would print the HTML as text in quotes. This is how I enabled natural paths in React.

import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;

@Component
public class StaticContentFilter implements Filter {

    private List<String> fileExtensions = Arrays.asList("html", "js", "json", "csv", "css", "png", "svg", "eot", "ttf", "woff", "appcache", "jpg", "jpeg", "gif", "ico");

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        doFilter((HttpServletRequest) request, (HttpServletResponse) response, chain);
    }

    private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String path = request.getServletPath();

        boolean isApi = path.startsWith("/api");
        boolean isResourceFile = !isApi && fileExtensions.stream().anyMatch(path::contains);

        if (isApi) {
            chain.doFilter(request, response);
        } else if (isResourceFile) {
            resourceToResponse("static" + path, response);
        } else {
            resourceToResponse("static/index.html", response);
        }
    }

    private void resourceToResponse(String resourcePath, HttpServletResponse response) throws IOException {
        InputStream inputStream = Thread.currentThread()
                .getContextClassLoader()
                .getResourceAsStream(resourcePath);

        if (inputStream == null) {
            response.sendError(HttpStatus.NOT_FOUND.value(), HttpStatus.NOT_FOUND.getReasonPhrase());
            return;
        }

        //headers
        if (resourcePath.endsWith(".html")) {
            response.setContentType("text/html");
        }
        if (resourcePath.endsWith(".css")) {
            response.setContentType("text/css");
        }
        if (resourcePath.endsWith(".js")) {
            response.setContentType("text/javascript");
        }

        inputStream.transferTo(response.getOutputStream());
    }
}

If you've found a better solution, please let me know.

I think what you're looking for is a ResourceHandler https://www.baeldung./spring-mvc-static-resources#3-chaining-resourceresolvers resp. https://github./eugenp/tutorials/blob/c9882f2090e918d0f441eeebf1f456e89dda2a17/spring-static-resources/src/main/java//baeldung/spring/MvcConfig.java#L57

Hope that helps you to have a starting point for your research :)

发布评论

评论列表(0)

  1. 暂无评论