配置react以在Spring boot应用程序上提供服务

问题描述 投票:0回答:5

到目前为止,我一直在为我的 Spring boot 应用程序编写一堆端点,没有 html UI 端。现在,我想提供包含 React 代码的 HTML 文件和 js 文件。

当我访问

http://localhost:8443
我得到:

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Sun Nov 19 11:54:01 PST 2017
There was an unexpected error (type=Not Found, status=404).
Not Found

到目前为止我做了什么:

1.添加了一个扩展的Web配置类

WebMvcConfigurerAdapter
:

@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    @Bean
    public ViewResolver internalResourceViewResolver() {
        InternalResourceViewResolver bean = new InternalResourceViewResolver();
        bean.setPrefix("/resources/static/");
        bean.setSuffix(".html");
        return bean;
    }
}

2.添加了休息控制器端点:

@RestController
public class HomeController {

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ModelAndView getdata() {
        ModelAndView model = new ModelAndView("index");
        return model;
    }
}

我的项目中有

myproject/src/main/resources/static/index.html
文件。

java spring
5个回答
10
投票

Spring Boot 可以自动处理静态文件(按照惯例),只需要把你所有的 html、js、css 等文件放到

src/main/resources/static
中,去掉你的 ViewResolver 和 Controller 的 '/' 就可以了,
index.html
就可以了也可以通过 Spring Boot 映射到
/

除此之外,您当然可以通过在

@RequestMapping
s
 上使用正确的 
@RestController

来使用 api 前缀创建 REST 端点

8
投票

这实际上取决于您的设置。假设您想要类似的东西:

让我们看一下简单的情况:没有 thymeleaf 模板或 spring 静态文件。 Spring用于提供其余的api,其余的由react决定。但是您可以在任何请求映射 url 上使用控制器。

一种选择是使用

ResourceResolver
并按如下方式配置:

@Configuration
public class Config implements WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        ResourceResolver resolver = new ReactResourceResolver();
        registry.addResourceHandler("/**")
                .resourceChain(true)
                .addResolver(resolver);

        // Can try to play with
        // registry.addResourceHandler("/**")
        //        .addResourceLocations("classpath:/static/");
        // But this option can't map every path to index.html
        // Can try https://stackoverflow.com/a/42998817/1032167
        // to resolve this, but then you loose /api/** => rest
        // and to be honest it is some regex madness, so
        // it was easier for me to setup custom resource resolver


    }

    public class ReactResourceResolver implements ResourceResolver {
        // root dir of react files
        // example REACT_DIR/index.html
        private static final String REACT_DIR = "/static/";

        // this is directory inside REACT_DIR for react static files
        // example REACT_DIR/REACT_STATIC_DIR/js/
        // example REACT_DIR/REACT_STATIC_DIR/css/
        private static final String REACT_STATIC_DIR = "static";

        private Resource index = new ClassPathResource(REACT_DIR + "index.html");
        private List<String> rootStaticFiles = Arrays.asList("favicon.io",
                "asset-manifest.json", "manifest.json", "service-worker.js");

        @Override
        public Resource resolveResource(
            HttpServletRequest request, String requestPath,
            List<? extends Resource> locations, ResourceResolverChain chain) {

            return resolve(requestPath, locations);
        }

        @Override
        public String resolveUrlPath(
            String resourcePath, List<? extends Resource> locations,
            ResourceResolverChain chain) {

            Resource resolvedResource = resolve(resourcePath, locations);
            if (resolvedResource == null) {
                return null;
            }
            try {
                return resolvedResource.getURL().toString();
            } catch (IOException e) {
                return resolvedResource.getFilename();
            }
        }

        private Resource resolve(
            String requestPath, List<? extends Resource> locations) {

            if (requestPath == null) return null;

            if (rootStaticFiles.contains(requestPath)
                    || requestPath.startsWith(REACT_STATIC_DIR)) {
                return new ClassPathResource(REACT_DIR + requestPath);
            } else
                return index;
        }

    }
}

这里是 Spring 2.0.0.M4 的完整工作演示: https://github.com/varren/SpringBootReactExample


我有类似的问题,但设置有点不同:每个 url 路由和子路由的 Spring 单页“/a/** => /a/index.html except /a/static/**”.

还有一个选项可以使用正则表达式Spring捕获index.html的所有路由来部分解决问题,但我对这种方法没有运气


2
投票

您需要一个返回 ModelAndView 的 @Controller

    @Controller
    public class HomeController {

        @RequestMapping(value = {"/", "/index.html"})
        public ModelAndView sellerHome(HttpServletRequest request, 
                                       HttpServletResponse response) {
             return new ModelAndView("../static/index");
        }

    }

然后您可以访问 http://localhost:8443 并且应该会看到索引页面(如果您正确配置了端口)。


1
投票

正如您所知,在 Spring Boot 2.1.4 中,新配置是:

package com.simplicity.resourceserver.configs;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@EnableWebMvc
public class WebMvcConfiguration implements WebMvcConfigurer {

    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
            "classpath:/META-INF/resources/", "classpath:/resources/",
            "classpath:/static/", "classpath:/public/" };



    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
                .addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS);

        registry.addResourceHandler("/vanilla/**")
                .addResourceLocations("classpath:/vanilla/");

            registry.addResourceHandler("/react/**")
                    .addResourceLocations("classpath:/react/")
                .resourceChain(true);
    }

    @Bean
    public ViewResolver getViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setSuffix(".html");
        return resolver;
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.setUseTrailingSlashMatch(true);
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/react")
                .setViewName("forward:/react/index.html");
        registry.addViewController("/react/{path:[^\\.]*}")
                .setViewName("forward:/react/index.html");
        registry.addViewController("/react/**/{path:[^\\.]*}")
                .setViewName("forward:/react/index.html");

    }
}

Spring Boot 应该被定义为基于“视频扑克”的编程:尝试数千次(就像玩视频扑克时),细节上略有不同,直到它起作用。

就我而言,我在 src/main/resources 下的两个单独的文件夹中有两个不同的应用程序

  • src/main/resources/vanilla
  • src/main/resources/react

就我而言,它们是两个证明概念,但它可能是一个微前端架构。


0
投票

将 Fontend 构建添加到目标目录的静态文件夹中

<target>
<copy todir="${project.build.directory}/classes/static">
    <fileset dir="${project.basedir}/front-end/build"/>
</copy>

添加一个控制器类,将所有请求路由到静态文件夹中的index.html文件。

@GetMapping(value = "/**/{path:[^\\.]*}")
public String forward() {
    return "forward:/";
}

}

在application.properties中添加:

spring.mvc.pathmatch.matching-strategy=ant_path_matcher
© www.soinside.com 2019 - 2024. All rights reserved.