简体   繁体   English

Angular 与 Spring 引导 static 不工作

[英]Angular with Spring boot static does not work

I have an spring boot app, which contains an angular front我有一个 spring 启动应用程序,其中包含一个 angular 前面

like this:像这样:

src/main/resources/static/zanori2 src/main/resources/static/zanori2

Where in zanori2 I have the result of ng build some like:在 zanori2 中,我得到了ng build的结果,例如:

index.html, index.js, favico.ico and so on index.html、index.js、favico.ico 等

I tried this resourceHandle:我试过这个资源句柄:

@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");
            }
        });
    }
}

However when I go to: localhost:8080/zanori2/index.html it return me to localhost:8080 and the js files works.但是,当我将 go 发送到: localhost:8080/zanori2/index.html时,它会将我返回到localhost:8080并且 js 文件有效。

However it is weird because I am not allowed to share the url because if I go directly to localhost:8080 I get a not found page.然而,这很奇怪,因为我不允许共享 url,因为如果我将 go 直接发送到 localhost:8080,我会得到一个未找到的页面。

And with this other configuration:并使用其他配置:

@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");
    }
}

I go to localhost:8080/zanori2/index.html and I keep in the same url however my js files are not found so is not working too.我 go 到localhost:8080/zanori2/index.html并且我保留在同一个 url 但是我的 js 文件找不到所以也不起作用。

I do not found any example of this working properly.我没有找到任何正常工作的例子。

Example of the problem:问题示例: 在此处输入图像描述

Mapping of static assets static资产映射

Spring will automatically search in a number of places for paths which aren't matched by any controllers or other settings in the web config. Spring 将自动在多个位置搜索与 web 配置中的任何控制器或其他设置不匹配的路径。 These locations are currently checked by default:这些位置当前默认选中:

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

You can override this behaviour by setting the您可以通过设置

spring.web.resources.static-locations

application property.应用程序属性。

Starting from a clean project and adding:从一个干净的项目开始并添加:

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

to your application.properties will make Spring search the intended path for static resources.到您的application.properties将使 Spring 搜索 static 资源的预期路径。

Mapping paths in single-page frontends to /将单页前端中的路径映射到/

Remember in all of the below that the mapping to static assets has already been changed by the above so in the below, the path /a/b will REALLY fetch /static/zanori2/a/b .请记住,在下面的所有内容中,到 static 资产的映射已被上面更改,因此在下面,路径/a/b将真正获取/static/zanori2/a/b Also remember that a Spring controller will always have precedence over static assets so if you define a Spring controller which interferes with a static path, it will be used instead.另请记住,Spring controller 将始终优先于 static 资产,因此如果您定义 Spring controller 干扰 static 路径,它将被使用。

If you also support a single-page frontend with internal routing, you need to add some configuration to the WebMvcConfigurer .如果您还支持具有内部路由的单页前端,则需要向WebMvcConfigurer添加一些配置。 The trick is to still load all static content from its real location but to forward all the paths inside the single-page app to / .诀窍是仍然从其真实位置加载所有 static 内容,但将单页应用程序内的所有路径转发到/ Assuming that paths inside the app will never have a file suffix preceded by a period (.), which typically all real static files from the backend have, this can be done by some additionss to your WebMvcConfigurer .假设应用程序内的路径永远不会有一个以句点 (.) 开头的文件后缀,通常来自后端的所有真实 static 文件都有,这可以通过向WebMvcConfigurer添加一些内容来完成。

The additions depend on which kind of pattern matching is used in SpringMVC .添加取决于SpringMVC 中使用哪种模式匹配

Path pattern matching路径模式匹配

With path pattern matching (which is the new default in up-to-date Spring Boot):使用路径模式匹配(这是最新 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:/")
}

With path pattern matching, there is no easy way to do this for an arbitrary number of path levels so you have to add one of these statements for every level of nesting your frontend internal paths should support.对于路径模式匹配,没有简单的方法可以针对任意数量的路径级别执行此操作,因此您必须为前端内部路径应支持的每个嵌套级别添加这些语句之一。 This is because path patterns only allow matching of multiple path levels ( ** ) at the end of a pattern.这是因为路径模式只允许在模式末尾匹配多个路径级别 ( ** )。

The above supports up to three levels so when directly entering in the browser address bar:以上最多支持三级所以在浏览器地址栏直接输入时:

/
/* / 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 */

What's going on here?这里发生了什么? As said, these are path patterns which you can read about here :如前所述,这些是您可以在此处阅读的路径模式:

  • Each {pathX} matches a path segment and stores the path in the variable pathX (which we don't care about).每个{pathX}匹配一个路径段并将路径存储在变量pathX (我们不关心)。
  • Each variable must have a unique name within its matching pattern.每个变量在其匹配模式中必须具有唯一的名称。
  • In the last path segment, we match a non-empty sequence of digits, letters and underscore.在最后一个路径段中,我们匹配一个非空的数字、字母和下划线序列。 You can modify this regex if you want but it's quite restricted what you can do.如果需要,您可以修改此正则表达式,但您可以执行的操作非常受限。 The goal is to NOT match any paths with periods in them because these are likely real static files.目标是不匹配任何带有句点的路径,因为这些可能是真实的 static 文件。
  • There are other path patterns which are useful but they may not be combined with our final regex pattern.还有其他有用的路径模式,但它们可能不会与我们最终的正则表达式模式结合使用。

Ant pattern matching Ant 模式匹配

With ant pattern matching , which used to be the default, similar rules apply but with some differences.对于ant 模式匹配,它曾经是默认的,适用类似的规则,但有一些不同。 Path pattern matching is generally more potent but as previously said, it does not allow you to match an arbitrary number of path levels ( ** ) at no other place then at the end.路径模式匹配通常更有效,但如前所述,它不允许您在最后的其他地方匹配任意数量的路径级别 ( ** )。

With ant pattern matching, the previous config can be simplified into加上ant模式匹配,前面的config可以简化为

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

Now, we match an arbitrary number of path levels before the last path, yielding the following results:现在,我们在最后一条路径之前匹配任意数量的路径级别,产生以下结果:

/
/* / 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 */

So depending on what you need in the rest of your app, I would choose one of these solutions, preferably the one with ant patterns.因此,根据您在应用程序 rest 中的需求,我会选择其中一种解决方案,最好是具有 ant 模式的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM