Angular2 和 Spring Boot。如何服务前端?

Posted

技术标签:

【中文标题】Angular2 和 Spring Boot。如何服务前端?【英文标题】:Angular2 and Spring Boot. How to serve front-end? 【发布时间】:2017-06-14 20:45:05 【问题描述】:

我有Spring Boot 作为后端和Angular2 作为前端。我想分别开发它们并部署到Heroku

它们不应该有任何共同的依赖关系,应该在单独的 git-repos 中。

据我了解,主要有两种实现方式:

    运行npm build并将dist文件夹复制到Spring应用程序的resource文件夹中,最后将其作为静态内容处理

    运行服务器以专门为 Angular 应用程序提供服务,该应用程序将与 Spring 应用程序通信(这里出现 CORS 问题?)所以总共有两台服务器

我认为第一种方法有点“肮脏”,因为我认为将文件夹从一个项目复制到另一个项目没有任何好处。

第二种方法有点矫枉过正,因为我有两台服务器(例如TomcatNode.js)。如果我可以简单地将Angular 放在Spring 中,我为什么要拥有带有Angular 应用程序的服务器?

有没有更正经的方法来做上述?

谢谢。

【问题讨论】:

【参考方案1】:

在我的组织中,我们有很多 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 属性是我需要的。谢谢,会试试的。【参考方案2】:

选项 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 中,该文件夹现在将同时为 API 和 Angular UI 提供服务。

【讨论】:

【参考方案3】:

到目前为止,我使用 Angular 和 spring-boot 创建了应用程序,使用一个 git 存储库,但有两个不同的 maven 项目,一个用于后端,一个用于前端。

我使用 Maven 构建了一个带有嵌入式 Tomcat 的胖 jar,并将其部署到 Amazon EC2。

我还对 Heroku 进行了实验,您肯定可以在其中部署相同的 fat jar。

对于下一个项目,我将采用另一种方法,将所有静态资源(如 html、javascript 等)部署到 Amazon S3,仅将 spring-boot 应用程序部署到 Heroku 等提供商。

这种方式的前端部署似乎更容易、更快、更便宜。

还有一篇关于Using AWS S3 to Store Static Assets and File Uploads的博文

【讨论】:

第一种方法我个人不喜欢。包括 maven 到前端...不。我根本不希望前端开发人员了解 Maven。第二种方式相当不错。

以上是关于Angular2 和 Spring Boot。如何服务前端?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用spring boot和angular 2登录

Angular2+Spring Boot:无法解决上下文路径问题 |前端没有数据

Angular2 Spring Boot JWT 缺少响应标头

SockJS over stomp 使用 angular2 和 spring boot

angular2 spring-boot项目结构

Spring Boot + Angular 2 结构