Java 使Spring/Tomcat与HTML5兼容
我有一个单页web应用程序,它使用Backbone.js客户端路由和pushState。为了让它正常工作,我必须告诉我的服务器(Java、Spring3、Tomcat),哪些URL应该在服务器上解析(实际的JSP视图、API请求),哪些应该发送到索引页面,由客户端处理。目前,我正在使用InternalResourceViewResolver为与URL请求名称匹配的JSP视图提供服务。由于客户端URL在服务器上没有视图,服务器返回404Java 使Spring/Tomcat与HTML5兼容,java,html,spring,tomcat,backbone.js,Java,Html,Spring,Tomcat,Backbone.js,我有一个单页web应用程序,它使用Backbone.js客户端路由和pushState。为了让它正常工作,我必须告诉我的服务器(Java、Spring3、Tomcat),哪些URL应该在服务器上解析(实际的JSP视图、API请求),哪些应该发送到索引页面,由客户端处理。目前,我正在使用InternalResourceViewResolver为与URL请求名称匹配的JSP视图提供服务。由于客户端URL在服务器上没有视图,服务器返回404 指定Spring(或Tomcat)的几个特定URL(我的客户
指定Spring(或Tomcat)的几个特定URL(我的客户端路由)都应该解析为index.jsp,其他任何内容都应该解析为InternalResourceViewResolver的最佳方式是什么?我会为我的URL提供一个清晰的方案,并将前端和后端分开 一些建议:
- 将从
开始的所有请求路由到后端,将所有其他请求路由到前端/server
- 设置两个不同的域,一个用于后端,一个用于前端李>
MVC:view controller
标签。这让我成功了:
<mvc:view-controller path="/" view-name="index" />
<mvc:view-controller path="/admin" view-name="index" />
<mvc:view-controller path="/volume" view-name="index" />
理论上,要通过history.pushState处理导航,您需要返回index.html以获取未处理的资源。如果您查看现代web框架的官方文档,它通常是基于404状态实现的 在spring中,您应该按照以下顺序处理资源:
- 路径映射REST控制器
- 应用程序静态资源
- 其他人的index.html
@Controller
static class SpaController {
@RequestMapping("resourceNotFound")
public String handle() {
return "forward:/index.html";
}
}
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return container -> container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/resourceNotFound"));
}
@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;
static class SpaWithHistoryPushStateHandler {
}
static class SpaWithHistoryPushStateHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(final Object handler) {
return handler instanceof SpaWithHistoryPushStateHandler;
}
@Override
public ModelAndView handle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) throws Exception {
response.getOutputStream().println("default index.html");
return null;
}
@Override
public long getLastModified(final HttpServletRequest request, final Object handler) {
return -1;
}
}
@Bean
public SpaWithHistoryPushStateHandlerAdapter spaWithHistoryPushStateHandlerAdapter() {
return new SpaWithHistoryPushStateHandlerAdapter();
}
@PostConstruct
public void setupDefaultHandler() {
requestMappingHandlerMapping.setDefaultHandler(new SpaWithHistoryPushStateHandler());
}
@Autowired
private ResourceProperties resourceProperties;
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations(resourceProperties.getStaticLocations())
.setCachePeriod(resourceProperties.getCachePeriod())
.resourceChain(resourceProperties.getChain().isCache())
.addResolver(new PathResourceResolver() {
@Override
public Resource resolveResource(final HttpServletRequest request, final String requestPath, final List<? extends Resource> locations, final ResourceResolverChain chain) {
final Resource resource = super.resolveResource(request, requestPath, locations, chain);
if (resource != null) {
return resource;
} else {
return super.resolveResource(request, "/index.html", locations, chain);
}
}
});
}
@Bean
public ErrorViewResolver customErrorViewResolver() {
final ModelAndView redirectToIndexHtml = new ModelAndView("forward:/index.html", Collections.emptyMap(), HttpStatus.OK);
return (request, status, model) -> status == HttpStatus.NOT_FOUND ? redirectToIndexHtml : null;
}