Angular2和Spring Boot,如何提供前端服务?

9
我有一个后端是Spring Boot,前端是Angular2的项目。我希望能够分开开发并将它们部署到Heroku上。
它们不应该有任何共同的依赖,并且应该在独立的git存储库中。
根据我的理解,有两种主要实现方式:
1. 运行npm build,并将dist文件夹复制到Spring应用程序的resource文件夹中,这样就可以将最终产品作为静态内容处理。 2. 运行服务器专门用于服务于Angular应用程序,该应用程序将与Spring应用程序通信(这里会出现CORS问题),因此总共有两个服务器。
我认为第一种方式有点“不规范”,因为我认为从一个项目复制文件夹到另一个项目中并不好。
第二种方法则过于复杂,因为我已经有了两个服务器(例如TomcatNode.js)。如果我可以简单地将Angular放在Spring中,为什么还需要一个Angular服务器呢?
是否还有更加恰当的方法来完成以上任务呢?
3个回答

10

在我的组织中,我们有很多Spring Boot和Angular应用程序。当两个服务器是不必要的时候,Spring Boot可以从任何支持的URL(例如“http:”或“file:”)提供静态内容。只需在启动时将此参数传递给您的应用程序:

--spring.resources.static-locations=<url>

Spring Boot也可以通过包含以下Web MVC配置来支持Angular单页应用程序路由。这可以确保即使用户在浏览器中刷新页面,Spring Boot仍然会为其他Angular路由提供index.html的内容。

public class SinglePageAppWebMvcConfigurer extends WebMvcConfigurerAdapter
{
    @Autowired
    private ResourceProperties resourceProperties;

    private String apiPath = "/api";

    public SinglePageAppWebMvcConfigurer()
    {
    }

    public SinglePageAppWebMvcConfigurer(String apiPath)
    {
        this.apiPath = apiPath;
    }

    protected String getApiPath()
    {
        return apiPath;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry)
    {
        registry.addResourceHandler("/**")
            .addResourceLocations(resourceProperties.getStaticLocations())
            .setCachePeriod(resourceProperties.getCachePeriod()).resourceChain(true)
            .addResolver(new SinglePageAppResourceResolver());
    }

    private class SinglePageAppResourceResolver extends PathResourceResolver
    {
        @Override
        protected Resource getResource(String resourcePath, Resource location) throws IOException
        {
            Resource resource = location.createRelative(resourcePath);
            if (resource.exists() && resource.isReadable()) {
                return resource;
            } else if (getApiPath() != null && ("/" + resourcePath).startsWith(getApiPath())) {
                return null;
            } else {
                LoggerFactory.getLogger(getClass()).info("Routing /" + resourcePath + " to /index.html");
                resource = location.createRelative("index.html");
                if (resource.exists() && resource.isReadable()) {
                    return resource;
                } else {
                    return null;
                }
            }
        }
    }
}

那个 application.properties 属性就是我需要的。谢谢,我会尝试的。 - fasth

5

选项1 一个服务器进程托管REST API,另一个服务器进程托管Angular UI

在微服务架构中,这是推荐的选项,其中单个API(或小型相关API组)通过在单独的服务器进程中托管它们来分别运行和扩展。在这种情况下,如果将Angular UI与REST API捆绑在一起,这意味着每次修复错误或增强Angular UI都需要重新构建和部署服务。当我们开始这样做时,它会打败基于微服务的架构的目的。

因此,在这种架构中,一个或多个服务器实例将仅托管Angular UI。 Angular UI将通过API网关使用某些服务发现机制调用各个API。但是,基于微服务的架构并不简单-它具有许多移动部件。这种复杂度可以为大型项目提供合理的解释。

选项2 一个服务器进程同时托管REST API和Angular UI

对于用户数为几百人的中小型项目,这是推荐的选项。

在这些项目中,创建一个单一的存储库,其中Maven项目将包含两个子模块-一个用于REST API,另一个用于Angular UI。

使用Maven插件“frontend-maven-plugin”构建UI部分。这将自动下载指定的NodeJs版本并调用适当的npm命令来构建Angular项目。最后,使用Maven元素将Angular dist文件夹复制到资源文件夹下的Spring Boot静态文件夹中。(在.gitignore文件中排除静态文件夹,以便不会将Angular分发文件与REST API一起检入源代码控制)。

现在,随着Java构建的开始,它将自动包括静态文件夹在fat jar中,该jar现在将同时提供API和Angular UI服务。


2
到目前为止,我使用angular和spring-boot创建了应用程序,使用一个git存储库,但是有两个不同的maven项目,一个用于后端,另一个用于前端。然后,我使用Maven构建了一个包含嵌入式Tomcat的fat jar,并将其部署到Amazon EC2。我还尝试过Heroku,并且可以在那里部署相同的fat jar。对于下一个项目,我会采取另一种方法,将所有静态资源(如html、javascript等)部署到Amazon S3,只将spring-boot应用程序部署到类似于Heroku的提供商。这种方式部署前端似乎更容易、更快速、更便宜。关于使用AWS S3存储静态资源和文件上传也有一篇博客文章(链接:Using AWS S3 to Store Static Assets and File Uploads)。

我个人不喜欢第一种方法。将Maven包含到前端中...算了吧。我不希望前端开发人员完全了解Maven。第二种方式相当不错。 - fasth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接