使用 Spring Boot 和 React Router 提供静态文件夹

Jur*_*ass 2 javascript java reactjs spring-boot react-router

我有一个 React 客户端应用程序,它被构建并编译到 Java 资源文件夹中

src/main/resources/static
Run Code Online (Sandbox Code Playgroud)

然后,标准 Spring Boot 应用程序将毫无问题地提供静态文件夹的内容。

但是,当我开始使用 React Router 时,我需要能够解析此路径:

localhost:8080/userSettingsPage
Run Code Online (Sandbox Code Playgroud)

进入index.html

src/resource/static/index.html
Run Code Online (Sandbox Code Playgroud)

我知道我可以在控制器中执行此操作,如下所示:

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

不过我想以更通用的方式指定我的控制器:

  1. 如果 URL {path}“.html”、“.js”、“.json”、“.csv”、“.css”、“.png”、“.svg”、“.eot”、“ .ttf", ".woff", ".appcache", ".jpg", ".jpeg", ".gif", ".ico" ,然后返回/static/{path}中的文件
  2. 否则返回/static/index.html

我怎样才能实现它?

Jur*_*ass 5

经过大量研究并尝试各种方法后,我得出的结论是,最简单的解决方案是自己实现 Filter 并处理静态 Web 文件的服务,这绕过了 Spring 的处理:

@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());
    }
}
Run Code Online (Sandbox Code Playgroud)