我正在尝试使用Spring将单页面应用程序(SPA)与普通REST API一起托管。
这意味着所有请求都应由相应的控制器处理,而其他请求应重定向到文件夹/static/built
中的资源。
我通过捕获所有NoHandlerFoundExceptions
并将其重定向到js
文件或html
文件,并使用WebMvcConfigurer
映射静态内容来使其工作。
但是,这似乎对我来说不太正式,那么有没有更好的方法可以实现同样的功能呢?
我正在尝试使用Spring将单页面应用程序(SPA)与普通REST API一起托管。
这意味着所有请求都应由相应的控制器处理,而其他请求应重定向到文件夹/static/built
中的资源。
我通过捕获所有NoHandlerFoundExceptions
并将其重定向到js
文件或html
文件,并使用WebMvcConfigurer
映射静态内容来使其工作。
但是,这似乎对我来说不太正式,那么有没有更好的方法可以实现同样的功能呢?
@Controller
public class RedirectController {
@GetMapping(value = {"/{regex:\\w+}", "/**/{regex:\\w+}"})
public String forward404() {
return "forward:/";
}
}
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
,以允许/激活**
模式。否则,您的应用程序将无法启动。\w
正则表达式字符,但可以在端点中使用,因此请将\\w
替换为[\\w-]
(正则表达式方括号以捕获额外的连字符字符)。句点.
也是一样,但作为端点名称较少见,可能指的是静态文件资源,因此我不会包含它。 - George Pantazes我让我的单页应用(SPA)与Spring后端API配合工作的最简单方法是使用两个不同的控制器:一个用于SPA的根索引页面,另一个控制器用于管理各种RESTful API端点:
这是我的两个控制器:
MainController.java
APIController.java
@Controller
public class MainController {
@RequestMapping(value = "/")
public String index() {
return "index";
}
}
MonitoringController.java
@RestController
@RequestMapping(value = "api")
public class MonitoringEndpoints {
@GetMapping(path = "/health", produces = "application/hal+json")
public ResponseEntity<?> checkHealth() throws Exception {
HealthBean healthBean = new HealthBean();
healthBean.setStatus("UP");
return ResponseEntity.ok(healthBean);
}
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<meta charset="UTF-8"/>
<title>EDP Monitoring Tool</title>
</head>
<body>
<!-- Entry point to our ReactJS single page web application -->
<div id="root"></div>
<script type="text/javascript" src="built/bundle.js"></script>
</body>
</html>
如果您不确定如何连接前端,无论是一个ReactJS应用程序还是其他什么,我相信这些信息会对您有所帮助。如果您有其他问题,请告诉我。
此外,如果您正在使用Webpack,您可以通过webpack.config.js文件中的entry键设置JS文件的入口点,就像这样:
Original Answer翻译成“最初的回答”
entry: ['./src/main/js/index.js']
WebMvcConfigurer
来添加一个ResourceHandler
。public class WebConfiguration implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/*").addResourceLocations("file:/opt/web/singlepageapp/");
}
file:
前缀,以及末尾的/
。HttpServletRequestWrapper
使用。@WebFilter("/*")
public class IndexFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if(indexLocation == null || indexLocation.isBlank()) {
LOG.warning("The indexLocation value was null or blank so this filter is disabled.");
chain.doFilter(request, response);
return;
}
final HttpServletRequest httpRequest = (HttpServletRequest) request;
final String relativePath = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length());
LOG.finest("the relative path is: " + relativePath);
if(staticFiles.stream().anyMatch(f -> relativePath.startsWith(f))) {
LOG.finest("it's a static file so chain forward");
chain.doFilter(request, response);
return;
}
chain.doFilter(new MyServletRequest(httpRequest), response);
}
private final class MyServletRequest extends HttpServletRequestWrapper {
public MyServletRequest(HttpServletRequest request) {
super(request);
}
@Override
public String getRequestURI() {
return getServletContext().getContextPath() + indexLocation;
}
}
Filter
和HttpServletRequestWrapper
的强大功能,这是不明显的。在Nginx中,这只需要一行代码,但是这种方法让你可以在Spring中完成所有操作。我还在存储库中包含了Jetty部署文件。我认为你在寻找URL重写这个术语。
例如:https://getpostcookie.com/blog/url-rewriting-for-beginners/
static/
目录中(你可以使用Maven前端插件来自动化)。然后,Spring Boot会将它们作为静态文件提供,你不需要担心重定向到HTML或JS。如果你在SPA中使用基于哈希的URL(如so.com/#/route/...),那么在Spring中就没有更多要做的了。 - Matt