gpt4 book ai didi

java - 如何使用Spring Boot打包React前端并运行可执行jar?

转载 作者:行者123 更新时间:2023-12-01 16:39:58 30 4
gpt4 key购买 nike

我有一个包含 REST 服务的 Java Spring Boot 后端应用程序。就在主 Spring Boot 项目文件夹内,我有一个用于前端的 React 应用程序。我可以运行 Spring Boot 应用程序并成功访问所有端点。我可以运行 React 应用程序,它也可以工作。但现在我想创建一个可执行的 jar 文件并将其作为单个应用程序运行,而不是两个。

我创建一个可执行的 fat jar 文件,如下所示:

mvn clean install

它创建一个 jar 文件。当我运行它时

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

后端启动正常,但前端不会像我单独运行它那样在浏览器窗口中弹出

npm start

我已经按照这些教程到达了我现在的位置。显然我错过了一些东西。 https://medium.com/@mukundmadhav/build-and-deploy-react-app-with-spring-boot-and-mysql-6f888eb0c600#37fa https://blogg.kantega.no/webapp-with-create-react-app-and-spring-boot/

这是 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

我在浏览器中看到:“公共(public)内容”

如果我直接访问后端,但终端显示:

n.t.m.security.jwt.AuthEntryPointJwt : Unauthorized error: Full authentication is required to access this resource

如果我进入浏览器: http://localhost:8080/home

它返回“出现意外错误(类型=未经授权,状态=401)。”

显然 Spring Security JWT 正在以某种方式进行干扰,但我就是无法弄清楚。主页不需要任何身份验证,但有些东西的行为却与此类似。这是后端树: enter image description here

我还应该提到,在应用程序启动期间,我看到了其中几个异常:

java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed

但这并不能阻止它运行。我通过将“&allowPublicKeyRetrieval=true”添加到 application.properties 文件中的 spring.datasource.url 解决了这个问题。

最佳答案

终于找到问题所在了。我添加了

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

到WebSecurityConfig.java 文件中的configure 方法。现在看起来像这样:

@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返回“公共(public)内容”。

关于java - 如何使用Spring Boot打包React前端并运行可执行jar?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61877069/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com