簡體   English   中英

如何 package React 前端與 Spring 啟動並運行可執行文件 jar?

[英]How to package React front end with Spring Boot and run the executable jar?

我有一個 Java Spring 引導后端應用程序,其中包含 REST 服務。 在主 Spring 引導項目文件夾中,我有一個用於前端的 React 應用程序。 我可以運行 Spring Boot 應用程序並成功訪問所有端點。 我可以運行 React 應用程序,它也可以工作。 但現在我想創建一個可執行的 jar 文件並將其作為單個應用程序運行,而不是兩個。

我創建了一個可執行的胖 jar 文件,如下所示:

mvn clean install

它會創建一個 jar 文件。 當我運行它時

java -jar target/medaverter-0.0.1-SNAPSHOT.jar

后端啟動正常,但前端沒有在瀏覽器中彈出 window 就像我單獨運行它一樣

npm start

我已經按照這些教程來了解我所在的位置。 顯然我錯過了一些東西。 https://medium.com/@mukundmadhav/build-and-deploy-react-app-with-spring-boot-and-mysql-6f888eb0c600#37fa https://with-blog.kantega.no/反應應用程序和彈簧啟動/

這是 pom.xml 文件。 插件部分在 React 應用程序中實現了合並的魔力:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>net.tekknow</groupId>
    <artifactId>medaverter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>medaverter</name>
    <description>Demo project for Spring Security</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20190722</version>
        </dependency>   
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.6</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
               <groupId>com.github.eirslett</groupId>
               <artifactId>frontend-maven-plugin</artifactId>
               <version>1.6</version>
               <configuration>
                   <workingDirectory>medaverter-front</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}/medaverter-front/build"/>
                                </copy>
                            </target>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <pluginManagement>
            <plugins>
                <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
                <plugin>
                    <groupId>org.eclipse.m2e</groupId>
                    <artifactId>lifecycle-mapping</artifactId>
                    <version>1.0.0</version>
                    <configuration>
                        <lifecycleMappingMetadata>
                            <pluginExecutions>
                                <pluginExecution>
                                    <pluginExecutionFilter>
                                        <groupId>
                                            org.apache.maven.plugins
                                        </groupId>
                                        <artifactId>
                                            maven-antrun-plugin
                                        </artifactId>
                                        <versionRange>
                                            [1.8,)
                                        </versionRange>
                                        <goals>
                                            <goal>run</goal>
                                        </goals>
                                    </pluginExecutionFilter>
                                    <action>
                                        <ignore></ignore>
                                    </action>
                                </pluginExecution>
                            </pluginExecutions>
                        </lifecycleMappingMetadata>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

我已經驗證了 react 文件夾中名為 medaverter-front 的相同文件被復制到 target/classes/public 文件夾中。

我的 package.json 文件中設置了以下代理:

  "proxy": {
    "/api": {
      "target": "http://localhost:8080",
      "ws": true
    }
  },

如果我進入瀏覽器: http://localhost:8080/api/test/all

我在瀏覽器中看到:“公共內容”

如果我直接訪問后端,我應該這樣做,但終端顯示:

ntmsecurity.jwt.AuthEntryPointJwt:未經授權的錯誤:訪問此資源需要完全身份驗證

如果我進入瀏覽器: http://localhost:8080/home

它返回“出現意外錯誤(類型=未授權,狀態=401)。”

顯然 Spring 安全 JWT 以某種方式干擾,但我就是想不通。 主頁不需要任何身份驗證,但有些東西就像它一樣。 這是后端樹: 在此處輸入圖像描述

我還應該提到,在應用程序啟動期間,我看到了以下幾個異常:

java.sql.SQLNonTransientConnectionException:不允許檢索公鑰

但這並不能阻止它運行。 我通過在 application.properties 文件中的 spring.datasource.url 中添加“&allowPublicKeyRetrieval=true”解決了這個問題。

我終於找到了問題所在。 我添加了

    .antMatchers("/home/**").permitAll()
    .antMatchers("/**").permitAll()

到 WebSecurityConfig.java 文件中的配置方法。 現在看起來像這樣:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors().and().csrf().disable()
        .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
        .authorizeRequests().antMatchers("/api/auth/**").permitAll()
        .antMatchers("/api/test/**").permitAll()
        .antMatchers("/home/**").permitAll()
        .antMatchers("/**").permitAll()
        .anyRequest().authenticated();

    http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}

我對這種方法感到困惑(現在仍然如此)。 我曾認為如果 /api/test/all 被處理,這就是我所需要的。 顯然不是。 為什么我會這么想? React 流程從 App.js 開始,其中包含

      <Route exact path={["/", "/home"]} component={Home} />

home.component.js 包含:

  componentDidMount() {
    UserService.getPublicContent().then(
      response => {
        this.setState({
          content: response.data
        });
      },

user.service.js 包含:

const API_URL = 'http://localhost:8080/api/test/';

class UserService {
  getPublicContent() {
    return axios.get(API_URL + 'all');
  }

SpringBoot TestController.java 處理后端調用:

@RequestMapping("/api/test")
public class TestController {
    @GetMapping("/all")
    public String allAccess() {
        return "Public Content.";
    }

因此,/ 或 /home 最終調用http://localhost:8080/api/test/all ,它返回“公共內容”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM