到目前为止,我一直在为我的 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
文件。
Spring Boot 可以自动处理静态文件(按照惯例),只需要把你所有的 html、js、css 等文件放到
src/main/resources/static
中,去掉你的 ViewResolver 和 Controller 的 '/' 就可以了,index.html
就可以了也可以通过 Spring Boot 映射到 /
。
除此之外,您当然可以通过在
@RequestMapping
s上使用正确的
@RestController
来使用 api 前缀创建 REST 端点
让我们看一下简单的情况:没有 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的所有路由来部分解决问题,但我对这种方法没有运气
您需要一个返回 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 并且应该会看到索引页面(如果您正确配置了端口)。
正如您所知,在 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 下的两个单独的文件夹中有两个不同的应用程序
就我而言,它们是两个证明概念,但它可能是一个微前端架构。
将 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