Angular 和 Spring 引导静态不起作用

Angular with Spring boot static does not work

我有一个 spring 引导应用程序,其中包含一个 angular 前端

像这样:

src/main/resources/static/zanori2

在 zanori2 中我得到的结果是 ng build 类似的:

index.html、index.js、favico.ico 等等

我试过这个资源句柄:

@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
    /*@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {*/
        //registry.addResourceHandler("/**/*")
        /*.addResourceLocations("classpath:/static/zanori2/")
        .resourceChain(true)
        .addResolver(new PathResourceResolver() {
            @Override
            protected Resource getResource(String resourcePath,
                Resource location) throws IOException {
                Resource requestedResource = location.createRelative(resourcePath);
                return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
                : new ClassPathResource("/static/zanori2/index.html");
            }
        });
    }
}

然而,当我去:localhost:8080/zanori2/index.html 它 return 我去 localhost:8080 并且 js 文件工作。

然而,这很奇怪,因为不允许我共享 url,因为如果我直接转到 localhost:8080,我会得到一个未找到的页面。

并使用其他配置:

@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private Environment env;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        /* Caching strategy */
        boolean prodMode = Arrays.asList(env.getActiveProfiles()).contains("pro");
        Integer cachePeriod = prodMode ? null : 0;
        boolean useResourceCache = prodMode;

        VersionResourceResolver versionResourceResolver = new VersionResourceResolver();
        versionResourceResolver.addContentVersionStrategy("/**/*.js", "/**/*.css");
        AppCacheManifestTransformer transformer = new AppCacheManifestTransformer();

        /* robots.txt */
        registry.addResourceHandler("/robots.txt")
                .addResourceLocations("classpath:/static/robots.txt");

        /* All other resources */
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/static/zanori2")
                .setCachePeriod(cachePeriod)
                .resourceChain(useResourceCache)
                .addResolver(versionResourceResolver)
                .addTransformer(transformer);
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        /* Make sure Thymeleaf views are not accessible directly as static resources */
        registry.addRedirectViewController("/app/*.html", "/");
        /* Default mapping */
        registry.addRedirectViewController("/", "/app/index.html");
        /* Application entry */
        registry.addViewController("/app/index.html").setViewName("index");
    }
}

我去 localhost:8080/zanori2/index.html 并保留在同一个 url 但是我的 js 文件找不到所以也不起作用。

我没有找到任何正常工作的例子。

问题示例:

静态资产映射

Spring 将自动在许多地方搜索与网络配置中的任何控制器或其他设置不匹配的路径。这些位置当前默认选中:

classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/

您可以通过设置

来覆盖此行为
spring.web.resources.static-locations

申请属性.

从一个干净的项目开始并添加:

spring.web.resources.static-locations=classpath:/static/zanori2/

您的 application.properties 将使 Spring 搜索静态资源的预期路径。

将 single-page 前端中的路径映射到 /

请记住,在下面的所有内容中,上面已经更改了到静态资产的映射,因此在下面,路径 /a/b 将真正获取 /static/zanori2/a/b。还请记住,Spring 控制器将始终优先于静态资产,因此如果您定义干扰静态路径的 Spring 控制器,它将被使用。

如果您还支持带有内部路由的 single-page 前端,则需要向 WebMvcConfigurer 添加一些配置。诀窍是仍然从其真实位置加载所有静态内容,但将 single-page 应用程序内的所有路径转发到 /。假设应用程序内的路径永远不会有一个文件后缀以句点 (.) 开头,这通常是来自后端的所有真实静态文件都有的,这可以通过在 WebMvcConfigurer.[=31= 中添加一些内容来完成]

添加取决于哪种 pattern matching is used in SpringMVC

路径模式匹配

使用路径模式匹配(这是up-to-date Spring Boot 中的新默认值):

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry
        .addViewController("/{path1:[\w]+}")
        .setViewName("forward:/")
    registry
        .addViewController("/{path1}/{path2:[\w]+}")
        .setViewName("forward:/")
    registry
        .addViewController("/{path1}/{path2}/{path3:[\w]+}")
        .setViewName("forward:/")
}

对于路径模式匹配,没有简单的方法可以针对任意数量的路径级别执行此操作,因此您必须为前端内部路径应支持的每个嵌套级别添加这些语句之一。这是因为路径模式只允许在模式末尾匹配多个路径级别 (**)。

以上最多支持三级所以在浏览器地址栏直接输入时:

/
/* / is served */

/a 
/* / is served which can then route internally to /a */

/a/b 
/* / is served which can then route internally to /a/b */

/a/b/c 
/* / is served which can then route internally to /a/b/c */

/a/b/c/d
/* will NOT work, tries to serve actual /a/b/c/d */

/a/b/c.txt 
/* / will NOT work, tries to serve actual /a/b/c.txt since contains a period */

这是怎么回事?如前所述,这些是您可以阅读的路径模式 here:

  • 每个{pathX}匹配一个路径段并将路径存储在变量pathX中(我们不关心)。
  • 每个变量在其匹配模式中必须具有唯一的名称。
  • 在最后一个路径段中,我们匹配一个non-empty 数字、字母和下划线序列。如果需要,您可以修改此正则表达式,但您可以执行的操作非常受限。目标是不匹配任何带有句点的路径,因为这些可能是真正的静态文件。
  • 还有其他有用的路径模式,但它们可能无法与我们最终的正则表达式模式结合使用。

蚂蚁模式匹配

ant pattern matching 曾经是默认值,适用类似的规则,但有一些差异。路径模式匹配通常更有效,但如前所述,它不允许您在最后的其他地方匹配任意数量的路径级别 (**)。

有了蚂蚁模式匹配,之前的配置可以简化为

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry
        .addViewController("/**/{path:[\w]+}")
        .setViewName("forward:/")
}

现在,我们在最后一个路径之前匹配任意数量的路径级别,产生以下结果:

/
/* / is served */

/a 
/* / is served which can then route internally to /a */

/a/b 
/* / is served which can then route internally to /a/b */

/a/b/c 
/* / is served which can then route internally to /a/b/c */

/a/b/c/d
/* / is served which can then route internally to /a/b/c/d */

/a/b/c.txt 
/* / will NOT work, tries to serve actual /a/b/c.txt since contains a period */

因此,根据您对应用其余部分的需求,我会选择其中一种解决方案,最好是带有蚂蚁模式的解决方案。