繁体   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