用Spring Boot打包你的React應用

2021-02-21 前端之巔

先講一講這篇文章的背景故事。之前我的團隊需要在我們需求的基礎架構上節省一些資金,並且由於我們要構建的這個應用程式中,大部分負載都會在客戶端而非服務端上,所以我們決定試驗一下能否將一個 Spring 應用程式與一個 React 應用結合起來,並打包成一個 war 文件。

這篇文章會告訴你如何將 Create React App 與 Spring Boot 結合使用,從而為你打包出單個 war 文件。

Spring Boot 和 Create React App 的基本功能介紹

https://www.oracle.com/java/technologies/javase-downloads.html

https://maven.apache.org/install.html

https://nodejs.org/en/download/

附註:我選擇的 IDE 是 IntelliJ。當使用 React 代碼時,我通常會切換到 VS Code。你可以隨意使用自己習慣的方法

GroupId:e.the.awesome

Artifact:spring-react-combo-app

3. 將下載的項目解壓縮到你的 git 目錄中並提交。 你的 SpringReactComboAppApplication 看起來應該像這樣。

package e.the.awesome.springreactcomboapp;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class SpringReactComboAppApplication  extends SpringBootServletInitializer{

    public static void main(String[] args) {
        SpringApplication.run(SpringReactComboAppApplication.class, args);
    }

}

我們將其稱為 DadJokesController。這應該在與 SpringReactComboAppApplication 文件所在的文件夾中創建。我知道這不是正確的 Rest API 格式,但現在暫時忽略它。

package e.the.awesome.springreactcomboapp;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DadJokesController {
    @GetMapping("/api/dadjokes")
    public String dadJokes() {
        return "Justice is a dish best served cold, if it were served warm it would be just water.";
    }
}

5. 在你的終端運行

然後在瀏覽器中檢查 http://localhost:8080/api/dadjokes。你應該會看到我們添加到控制器中的 dad joke。

6. 要創建你的 React 應用,只需在根目錄中運行

npx create-react-app basic-frontend-app

你可以隨心所欲地調用它,我這裡只調用我的 basic-frontend-app。

7. 要運行前端應用程式:

cd basic-frontend-app<br>npm start

由於我們要將 Dad Jokes 服務集成到前端,因此首先我們要解決代理問題。你可能已經注意到了,你的服務從 localhost:8080 開始,而前端從 localhost:3000 開始。如果我們嘗試從前端調用服務,具體取決於你的瀏覽器,你可能會收到一個 CORS 錯誤。

解決此問題的最簡單方法是讓前端代理處理從埠 3000 到 8080 的所有請求。此更改將在 package.json 文件中進行:

{
  "name": "basic-frontend-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^16.3.1",
    "react-dom": "^16.3.1",
    "react-scripts": "1.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "proxy": {
    "/api": {
      "target": "http://localhost:8080",
      "ws": true
    }
  }
}

import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {

    state = {};

        componentDidMount() {
            this.dadJokes()
        }

    dadJokes = () => {
        fetch('/api/dadjokes')
            .then(response => response.text())
            .then(message => {
                this.setState({message: message});
            });
    };

    render() {
        return (
            <div className="App">
            <header className="App-header">
            <img src={logo} className="App-logo" alt="logo"/>
            <h3 className="App-title">{this.state.message}</h3>
            </header>
            <p className="App-intro">
            To get started, edit <code>src/App.js</code> and save to reload.
        </p>
        </div>
    );
    }
}

export default App;

如果你也遇到了下圖的這個錯誤,我的做法是:首先刪除了 package-lock.json 文件;其次在 node_modules 文件夾中重新安裝了 npm 包並再次運行;然後重新啟動前端,問題就解決了。

你可以看到 dad jokes API 調用的結果。

現在我們的基本前端和後端已經完成,該創建生產版本和單個 war 文件了。

<!-- https://mvnrepository.com/artifact/com.github.eirslett/frontend-maven-plugin -->
<dependency>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.6</version>
</dependency>

在 pom 文件的 <plugins> 部分下,我們將添加以下命令,這些命令將在運行 mvn clean install 時執行以下操作。

npm 安裝指定版本的 node

運行我們前端的生產構建

存放生產構建

<plugin>
   <groupId>com.github.eirslett</groupId>
   <artifactId>frontend-maven-plugin</artifactId>
   <version>1.6</version>
   <configuration>
      <workingDirectory>basic-frontend-app</workingDirectory>
      <installDirectory>target</installDirectory>
   </configuration>
   <executions>
      <execution>
         <id>install node and npm</id>
         <goals>
            <goal>install-node-and-npm</goal>
         </goals>
         <configuration>
            <nodeVersion>v8.9.4</nodeVersion>
            <npmVersion>5.6.0</npmVersion>
         </configuration>
      </execution>
      <execution>
         <id>npm install</id>
         <goals>
            <goal>npm</goal>
         </goals>
         <configuration>
            <arguments>install</arguments>
         </configuration>
      </execution>
      <execution>
         <id>npm run build</id>
         <goals>
            <goal>npm</goal>
         </goals>
         <configuration>
            <arguments>run build</arguments>
         </configuration>
      </execution>
   </executions>
</plugin>
<plugin>
   <artifactId>maven-antrun-plugin</artifactId>
   <executions>
      <execution>
         <phase>generate-resources</phase>
         <configuration>
            <target>
               <copy todir="${project.build.directory}/classes/public">
                  <fileset dir="${project.basedir}/basic-frontend-app/build"/>
               </copy>
            </target>
         </configuration>
         <goals>
            <goal>run</goal>
         </goals>
      </execution>
   </executions>
</plugin>

附註:對於你的插件來說,順序正確是很重要的,因此請確保在複製構建文件執行之前執行 node/npm 安裝

添加此命令後,運行 mvn clean install,並驗證 target/classes 目錄同時包含了前端文件和 Java 文件。這裡你應該是一路暢通的。

最後看一下我的 pom 文件:

https://github.com/Emmanuella-Aninye/Spring-Boot-ReactJS-Starter/blob/master/pom.xml

這就是我的方法。如果你想看看 repo 或使用它,可以來我的 Github:

https://github.com/Emmanuella-Aninye/Spring-Boot-ReactJS-Starter

https://hackernoon.com/package-your-react-app-with-spring-boot-a-how-to-guide-cdfm329w

相關焦點

  • Spring Boot項目打包部署最佳實踐
    war包打包問題解決spring boot打war包的步驟如下<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation
  • Spring boot 應用啟動原理分析
    spring boot時,通常會有這些疑問打包為單個jar時,spring boot的啟動方式maven打包之後,會生成兩個jar文件:demo-0.0.1-SNAPSHOT.jardemo-0.0.1-SNAPSHOT.jar.original
  • Spring Boot | 一個90後女孩的第一個 Spring Boot 應用
    創建 Maven Module創建一個 Module,選擇 Maven 工程,勾選以前用的 web 骨架</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies></project>編寫 Spring Boot
  • 部署 Spring Boot 應用到 K8S 教程
    boot應用整體上來說是一件比較繁瑣的事情,而Spring Boot Operator則能帶給你更清爽簡單的體驗。打包Docker鏡像在講部署之前我們需要先將我們的SpringBoot應用打包成標準的DockerImage。java項目打包鏡像用maven/gradle插件比較多,我的另一篇文章構建SpringBoot的Docker鏡像,這裡在介紹一個新的google開源的插件Jib,該插件使用起來比較方便。
  • 使用Spring Boot Operator將Spring Boot部署到Kubernetes
    在講部署之前我們需要先將我們的Spring Boot應用打包成標準的DockerImage。Java項目打包鏡像用Maven/Gradle插件比較多,我的另一篇文章構建Spring Boot的Docker鏡像[2]有介紹,這裡再介紹一個新的Google開源的插件Jib,該插件使用起來比較方便。
  • Spring Boot入門
    Spring默認使用jdk1.6,如果你想使用jdk1.8,你需要在pom.xml的屬性裡面添加java.version,如下:<properties>    <java.version>1.8</java.version></properties>添加spring-boot-starter-web
  • Spring Boot (十九):使用 Spring Boot Actuator 監控應用
    為了保證 actuator 暴露的監控接口的安全性,需要添加安全控制的依賴spring-boot-start-security依賴,訪問應用監控端點時,都需要輸入驗證信息。Security 依賴,可以選擇不加,不進行安全管理,但不建議這麼做。
  • Spring Boot基礎--web應用開發-模板引擎FreeMarker
    一.spring boot的web應用開發,是基於spring mvc二.Spring boot 在spring默認基礎上,自動配置添加了以下特性
  • Spring Boot 2.0(四):使用 Docker 部署 Spring Boot
    Docker 技術發展為微服務落地提供了更加便利的環境,使用 Docker 部署 Spring Boot 其實非常簡單,這篇文章我們就來簡單學習下。
  • Spring Boot2 系列教程(三)理解 spring-boot-starter-parent
    前面和大夥聊了 Spring Boot 項目的三種創建方式,這三種創建方式,無論是哪一種,創建成功後,
  • Spring Boot 2.x基礎教程:快速入門
    在你第n次使用Spring框架的時候,是否覺得一堆反覆黏貼的配置有一些厭煩?那麼您就不妨來試試使用Spring Boot來讓你更易上手,更簡單快捷地構建Spring應用!Spring Boot讓我們的Spring應用變的更輕量化。我們不必像以前那樣繁瑣的構建項目、打包應用、部署到Tomcat等應用伺服器中來運行我們的業務服務。
  • Spring Boot 如何自定義Starter,你知道嗎?
    helloworld-spring-boot-starter-autoconfigure(以下簡稱autoconfigure):該模塊用來實現 Helloworld 的自動配置功能,它的打包方式為 jar;helloworld-spring-boot-starter
  • 面試題:說一下Spring 和 Spring Boot 的區別
    SpringBoot很久的同學來說,還不是很理解 SpringBoot到底和 Spring有什麼區別,看完文章中的比較,或許你有了不同的答案和看法!<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId> spring-boot-starter-web</artifactId>
  • 優化Spring Boot應用Docker鏡像,提高CI/CD效率
    通常我們可以通過如下的Dockerfile把Spring Boot應用的fat jar打包成docker鏡像:FROM adoptopenjdk:8-jre-hotspotARG JAR_FILE=target/*.jarCOPY ${JAR_FILE}
  • Spring 和 Spring Boot 最核心的 3 大區別,詳解!
    概述對於Spring和SpringBoot到底有什麼區別,我聽到了很多答案,剛開始邁入學習SpringBoot的我當時也是一頭霧水,隨著經驗的積累、我慢慢理解了這兩個框架到底有什麼區別,相信對於用了SpringBoot很久的同學來說,還不是很理解SpringBoot到底和Spring有什麼區別,看完文章中的比較,或許你有了不同的答案和看法!
  • Spring Boot 應用可視化監控,一目了然!
    1、Spring Boot 應用暴露監控指標【版本 1.5.7.RELEASE】首先,添加依賴如下依賴:<dependency>          <groupId>org.springframework.boot</groupId>
  • Spring Boot 應用容器化之 Docker、Gradle
    本文演示了如何用 Docker、Gradle 來構建、運行、發布來一個 Spring Boot 應用。Docker 簡介Docker 是一個 Linux 容器管理工具包,具備「社交」方面,允許用戶發布容器的 image (鏡像),並使用別人發布的 image。
  • Spring Boot 開發 Web 應用
    (點擊上方公眾號,可快速關注)來源:翟永超,blog.didispace.com/springbootweb/
  • 最詳細的 Spring Boot 多模塊開發與排坑指南
    優化依賴是的,Spring Boot 應用在改造成多模塊後成功運行了起來,但是你貌似發現一個問題,模塊 common 和模塊 web 都繼承了主 pom ,主 pom 中有 Lombok 、Spring Boot Web 和  Spring Boot Test 依賴,而 common 模塊裡只用到了 Lombok 啊,卻一樣繼承了 Spring
  • 使用 Docker 部署 Spring Boot 項目
    一個簡單 Spring Boot 項目在 pom.xml 中 ,使用 Spring Boot 2.0 相關依賴<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent