Spring 捕获 index.html 的所有路由

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39331929/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 01:12:36  来源:igfitidea点击:

Spring catch all route for index.html

springspring-mvcspring-bootsingle-page-applicationcatch-all

提问by oli

I'm developing a spring backend for a react-based single page application where I'm using react-router for client-side routing.

我正在为基于 react 的单页应用程序开发 spring 后端,其中我使用 react-router 进行客户端路由。

Beside the index.html page the backend serves data on the path /api/**.

在 index.html 页面旁边,后端提供路径上的数据/api/**

In order to serve my index.html from src/main/resources/public/index.htmlon the root path /of my application I added a resource handler

为了src/main/resources/public/index.html/我的应用程序的根路径上提供我的 index.html,我添加了一个资源处理程序

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/").addResourceLocations("/index.html");
}

What I want to is to serve the index.html page whenever no other route matches, e.g. when I call a path other than /api.

我想要的是在没有其他路由匹配时为 index.html 页面提供服务,例如,当我调用/api.

How do I configure such catch-all route in spring?

如何在 spring 中配置这种包罗万象的路由?

回答by Petri Ryh?nen

Since my react app could use the root as forward target this ended up working for me

由于我的反应应用程序可以使用根作为前向目标,这最终对我有用

@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {

  @Override
  public void addViewControllers(ViewControllerRegistry registry) {
      registry.addViewController("/{spring:\w+}")
            .setViewName("forward:/");
      registry.addViewController("/**/{spring:\w+}")
            .setViewName("forward:/");
      registry.addViewController("/{spring:\w+}/**{spring:?!(\.js|\.css)$}")
            .setViewName("forward:/");
  }
}

To be honest I have no idea why it has to be exactly in this specific format to avoid infinite forwarding loop.

老实说,我不知道为什么它必须完全采用这种特定格式以避免无限转发循环。

回答by Dan Syrstad

I have a Polymer-based PWA hosted inside of my Spring Boot app, along with static web resources like images, and a REST API under "/api/...". I want the client-side app to handle the URL routing for the PWA. Here's what I use:

我在 Spring Boot 应用程序中托管了一个基于 Polymer 的 PWA,以及静态 Web 资源(如图像)和“/api/...”下的 REST API。我希望客户端应用程序处理 PWA 的 URL 路由。这是我使用的:

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    /**
     * Ensure client-side paths redirect to index.html because client handles routing. NOTE: Do NOT use @EnableWebMvc or it will break this.
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // Map "/"
        registry.addViewController("/")
                .setViewName("forward:/index.html");

        // Map "/word", "/word/word", and "/word/word/word" - except for anything starting with "/api/..." or ending with
        // a file extension like ".js" - to index.html. By doing this, the client receives and routes the url. It also
        // allows client-side URLs to be bookmarked.

        // Single directory level - no need to exclude "api"
        registry.addViewController("/{x:[\w\-]+}")
                .setViewName("forward:/index.html");
        // Multi-level directory path, need to exclude "api" on the first part of the path
        registry.addViewController("/{x:^(?!api$).*$}/**/{y:[\w\-]+}")
                .setViewName("forward:/index.html");
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/webapp/");
    }
}

This should work for Angular and React apps as well.

这也适用于 Angular 和 React 应用程序。

回答by alexbt

Avoid @EnableWebMvc

避免@EnableWebMvc

By default Spring-Boot serves static content in src/main/resources:

默认情况下,Spring-Boot 在src/main/resources以下位置提供静态内容:

  • /META-INF/resources/
  • /resources/
  • /static/
  • /public/
  • /元信息/资源/
  • /资源/
  • /静止的/
  • /民众/

Take a look at thisand this;

看看这个这个

Or keep @EnableWebMvc and override addViewControllers

或者保留 @EnableWebMvc 并覆盖 addViewControllers

Did you specify @EnableWebMvc? Take a look a this: Java Spring Boot: How to map my app root (“/”) to index.html?

你指定了@EnableWebMvc吗?看看这个:Java Spring Boot:如何将我的应用程序根目录(“/”)映射到 index.html?

Either you remove @EnableWebMvc, or you can re-define addViewControllers:

要么删除@EnableWebMvc,要么重新定义addViewControllers

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/").setViewName("forward:/index.html");
}

Or define a Controller to catch /

或者定义一个控制器来捕捉 /

You may take a look a this spring-boot-reactjs sample project on github:

您可以在 github 上查看这个spring-boot-reactjs 示例项目

It does what you want using a Controller:

它使用控制器执行您想要的操作:

@Controller
public class HomeController {

    @RequestMapping(value = "/")
    public String index() {
        return "index";
    }

}

Its index.htmlis under src/main/resources/templates

index.htmlsrc/main/resources/templates

回答by user3086678

I use react and react-router in my spring boot app, and it was as easy as creating a controller that has mapping to /and subtrees of my website like /users/**Here is my solution

我在 Spring Boot 应用程序中使用 react 和 react-router,这就像创建一个控制器一样简单,该控制器具有映射到/我网站的子树和子树,例如/users/**Here is my solution

@Controller
public class SinglePageAppController {
    @RequestMapping(value = {"/", "/users/**", "/campaigns/**"})
    public String index() {
        return "index";
    }
}

Api calls aren't caught by this controller and resources are handled automatically.

此控制器不会捕获 Api 调用,并且会自动处理资源。

回答by oli

Found an answer by looking at this question

通过查看这个问题找到了答案

@Bean
public EmbeddedServletContainerCustomizer notFoundCustomizer() {
    return new EmbeddedServletContainerCustomizer() {
        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/"));
        }
    };
}

回答by Gandalf

To answer your specific question which involves serving up the Single Page App (SPA) in all cases exceptthe /apiroute here is what I did to modify Petri's answer.

要回答您的特定问题,该问题涉及在所有情况下提供单页应用程序 (SPA),这里的/api路由是我为修改 Petri 的答案所做的工作。

I have a template named polymer that contains the index.html for my SPA. So the challenge became let's forward all routes except /api and /public-api to that view.

我有一个名为polymer 的模板,其中包含我的SPA 的index.html。所以挑战变成了让我们将除 /api 和 /public-api 之外的所有路由转发到该视图。

In my WebMvcConfigurerAdapter I override addViewControllers and used the regular expression: ^((?!/api/|/public-api/).)*$

在我的 WebMvcConfigurerAdapter 中,我覆盖了 addViewControllers 并使用了正则表达式:^((?!/api/|/public-api/).)*$

In your case you want the regular expression: ^((?!/api/).)*$

在您的情况下,您需要正则表达式:^((?!/api/).)*$

public class WebMvcConfiguration extends WebMvcConfigurerAdapter {

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/{spring:^((?!/api/).)*$}").setViewName("polymer");
    super.addViewControllers(registry);
}

This results in being able to hit http://localhostor http://localhost/communityto serve up my SPA and all of the rest calls that the SPA makes being successfully routed to http://localhost/api/posts, http://localhost/public-api/posts, etc.

这导致能够点击http://localhosthttp://localhost/community来提供我的 SPA 以及 SPA 成功路由到http://localhost/api/posts 的所有其余调用,http ://localhost/public-api/posts