2 使用React构造前端应用

文章目录

  • 简单了解React和Node
  • 搭建开发环境
  • React框架
  • JavaScript客户端
  • ChallengeComponent
    • 组件的主要结构
    • 渲染
    • 与应用程序集成
  • 第一次运行前端
  • 调试
  • 将CORS配置添加到Spring Boot应用
  • 使用应用程序
  • 部署React应用程序
  • 小结

前端代码可从这里下载: 前端示例

后端使用这里介绍的Spring Boot应用程序:一个测试驱动的Spring Boot应用程序开发

现实世界中,用户不会通过REST API使用应用程序,因此,这里为这个服务构造前端应用,便于用户与应用程序进行交互。

简单了解React和Node

React是一个构建用户界面的JavaScript库,由Facebook开发,很流行,已被广泛使用。React基于组件构建,编写一段代码即可在多处复用,这很有优势。可以创建像 Thumbnail、LikeButton 和 Video 这样的组件,然后将它们组合成整个应用程序。
React 组件是 JavaScript 函数,学习 React 就是学习编程。可以在React中使用 JSX,这是由 React 推广的 JavaScript 语法扩展,它允许将 JSX 标签与相关的渲染逻辑放在一起,使得创建、维护和删除 React 组件变得容易。
React 组件接收数据并返回应该出现在屏幕上的内容。可以通过响应交互(例如用户输入)向它们传递新数据。然后,React 将更新屏幕以匹配新数据。也可以不用 React 去构建整个页面,而只是将 React 添加到现有的 HTML 页面中,在任何地方呈现交互式的 React 组件。
React 允许将组件放在一起,而不关注路由和数据获取。要使用 React 构建整个应用程序,建议使用像 Next.js 或 Remix 这样的全栈 React 框架。
React 也是一种架构。实现它的框架可以在服务端甚至是构建阶段使用异步组件来获取数据,也可以从文件或数据库读取数据,并将其传递给交互式组件。
简单的说 Node.js 就是运行在服务端的 JavaScript。Node.js 是一个基于 Chrome JavaScript 运行时建立的一个平台。Node.js 是一个事件驱动 I/O 服务端 JavaScript 环境,基于 Google 的 V8 引擎,V8 引擎执行 Javascript 的速度非常快,性能非常好。
如果你是一个前端程序员,想创建自己的服务,那么 Node.js 是一个非常好的选择。如果你熟悉 Javascript,那么将会很容易的学会 Node.js。当然,如果你是后端程序员,想部署一些高性能的服务,那么学习 Node.js 也是一个非常好的选择。

搭建开发环境

首先,需要到nodejs.org站点上下载应用程序包来安装Node.js,可以下载免安装的zip版本,配置相应的环境变量即可。安装后可以在控制台输入下列命令,查看Node.js和npm的版本:

> node -v
v16.14.2
> npm -v
9.8.1

现在,最新的长期支持的Node版本是20.9.0。
有了Node,就可以使用npx来创建React项目了,命令如下:

> npx create-react-app multiplication-frontend

下载并安装依赖后,会看到如下输出:

> npx create-react-app multiplication-frontend

Creating a new React app in Z:\_Learn\multiplication-frontend.

Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts with cra-template...


added 1463 packages in 42s

Initialized a git repository.

Installing template dependencies using npm...

added 69 packages, and changed 1 package in 5s
Removing template package using npm...


removed 1 package in 2m

Created git commit.

Success! Created multiplication-frontend at Z:\_Learn\multiplication-frontend
Inside that directory, you can run several commands:

  npm start
    Starts the development server.

  npm run build
    Bundles the app into static files for production.

  npm test
    Starts the test runner.

  npm run eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can’t go back!

We suggest that you begin by typing:

  cd multiplication-frontend
  npm start

Happy hacking!

进入项目目录,执行npm start命令,Node服务器就会启动并打开一个浏览器窗口,访问localhost:3000地址,显示刚刚生成的应用程序。

> cd .\multiplication-frontend\
> npm start

默认页面如图所示:
默认页面

React框架

在IDEA中,加载项目,create-react-app工具已经创建了许多文件,如图所示:
React项目框架

  • package.json和package-lock.json是npm文件,包含关于项目的基本信息,列出相关依赖,依赖项存储在node_modules文件夹中。
  • public存储所有创建后不再变动的静态文件。唯一的例外是index.html,应对其处理以包含生成的JavaScript代码。
  • src存储所有的React源文件及其相关资源。这里可以找到入口点文件index.js和一个React组件App,该示例组件附带自己的样式表App.css和一个测试文件App.test.js。

这里,从index.html开始,删除注释后,内容如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

body很简单。index.js定义了渲染内容的入口,代码如下:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

reportWebVitals();

DOM(文档对象模型)是HTML元素的树结构表达,这段代码将元素React.StrictMode及其子元素App组件渲染到HTML中。具体地说,将渲染到ID为root的元素中,即插入index.html中的div标签。由于App是一个组件,可能包含其他组件,因此,最终会处理并渲染整个React应用程序。

JavaScript客户端

在创建第一个组件前,要确保可以访问前面创建的REST API接口,这需要使用JavaScript类。
JavaScript中的类与Java类类似,如下所示:

class ApiClient {
    static SERVER_URL = 'http://localhost:8080';
    static GET_CHALLENGE = '/challenges/random';
    static POST_RESULT = '/attempts';

    static challenge(): Promise<Response> {
        return fetch(ApiClient.SERVER_URL + ApiClient.GET_CHALLENGE);
    }

    static sendGuess(user: string,
                     a: number,
                     b: number,
                     guess: number): Promise<Response> {
        return fetch(ApiClient.SERVER_URL + ApiClient.POST_RESULT, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                userAlias: user,
                factorA: a,
                factorB: b,
                guess: guess
            })
        });
    }
}
export default ApiClient;

两个方法都返回Promise,JavaScript中的Promise与Java中的Future类相似:表示异步操作的结果。fetch函数用来与HTTP服务进行交互。
challenge()方法调用fetch函数的基本形式,默认对URL执行GET操作,返回Response对象。
sendGuess()方法接收请求所需的参数,与第二个参数一起使用,定义了HTTP方法(POST)的对象、请求体的内容类型(JSON)和请求体。
最后,为使类可以公开访问,添加了export default ApiClient,就可以将完整的类引入其他组件和类中了。

ChallengeComponent

下面,创建第一个React组件,来处理Challenge域,包括:

  • 将后端检索到的数据渲染到ChallengeComponent
  • 显示表单供用户发送猜测

下面是ChallengeComponent的代码:

import ApiClient from "../services/ApiClient";
import React from "react";

// 类从React.Component继承,这就是React创建组件的方式。
// 唯一要实现的方法是render(),该方法必须返回DOM元素才能在浏览器中显示。
class ChallengeComponent extends React.Component {
    // 构造函数,初始化属性及组件的state(如果需要的话),
    // 这里创建一个state来保持检索到的挑战,以及用户为解决尝试而输入的数据。
    constructor(props) {
        super(props);
        this.state = {
            a: '',
            b: '',
            user: '',
            message: '',
            guess: '',
        };
        // 两个绑定方法。如果想要在事件处理程序中使用,这是必要的,需要实现这些方法来处理用户输入的数据。
        this.handleSubmitResult = this.handleSubmitResult.bind(this);
        this.handleChange = this.handleChange.bind(this);
    }

    // 这是一个生命周期方法,用于首次渲染组件后立即执行逻辑。
    componentDidMount(): void {
        // 使用ApiClient实用程序类来调用服务,检索挑战。
        // 考虑到函数返回一个promise,使用then()来指定获取响应时的操作。
        ApiClient.challenge().then(res => {
            if (res.ok) {
                // 使用then()解析promise,将REST API响应中预期的factorA和factorB传递给setState()。
                res.json().then(
                    json => {
                        this.setState({
                            a: json.factorA,
                            b: json.factorB
                        });
                    }
                );
            } else {
                this.updateMessage("Can't reach the server");
            }
        });
    }

    handleChange(event) {
        const name = event.target.name;
        this.setState({
            [name]: event.target.value
        });
    }

    handleSubmitResult(event) {
        event.preventDefault();
        ApiClient.sendGuess(this.state.user,
            this.state.a,
            this.state.b,
            this.state.guess)
            .then(res => {
                if (res.ok) {
                    res.json().then(json => {
                        if (json.correct) {
                            this.updateMessage("Congratulations! Your guess is correct");
                        } else {
                            this.updateMessage("Oops! Your guess " + json.reaultAttempt + " is" +
                                " wrong, but keep playing!");
                        }
                    });
                } else {
                    this.updateMessage("Error: server error or not available");
                }
            });
    }

    updateMessage(m: string) {
        this.setState({
            message: m
        });
    }

    render() {
        return (
            <div>
                <div>
                    <h3>Your new challenge is</h3>
                    <h1>
                        {this.state.a} x {this.state.b}
                    </h1>
                </div>
                <form onSubmit={this.handleSubmitResult}>
                    <label>
                        Your alias:
                        <input type="text" maxLength="12" name="user"
                               value={this.state.user} onChange={this.handleChange}/>
                    </label>
                    <br/>
                    <label>
                        Your guess:
                        <input type="number" min="0" name="guess"
                            value={this.state.guess} onChange={this.handleChange}/>
                    </label>
                    <br/>
                    <input type="submit" value="Submit"/>
                </form>
                <h4>{this.state.message}</h4>
            </div>
        );
    }
}
export default ChallengeComponent;

组件的主要结构

import ApiClient from "../services/ApiClient";
import React from "react";

// 类从React.Component继承,这就是React创建组件的方式。
// 唯一要实现的方法是render(),该方法必须返回DOM元素才能在浏览器中显示。
class ChallengeComponent extends React.Component {
    // 构造函数,初始化属性及组件的state(如果需要的话),
    // 这里创建一个state来保持检索到的挑战,以及用户为解决尝试而输入的数据。
    constructor(props) {
        super(props);
        this.state = {
            a: '',
            b: '',
            user: '',
            message: '',
            guess: '',
        };
        // 两个绑定方法。如果想要在事件处理程序中使用,这是必要的,需要实现这些方法来处理用户输入的数据。
        this.handleSubmitResult = this.handleSubmitResult.bind(this);
        this.handleChange = this.handleChange.bind(this);
    }

    // 这是一个生命周期方法,用于首次渲染组件后立即执行逻辑。
    componentDidMount(): void {
        // ... Component initialization
    }

    render() {
        return (
        // ... HTML as JSX ...
            )
    }
}

在React中,setState函数重新加载部分DOM。这意味着浏览器将再次渲染HTML被更改的部分,因此收到服务器响应后,会在页面上看到乘法因子。

渲染

JSX可以混合使用HTML和JavaScript。

    render() {
        return (
            <div>
                <div>
                    <h3>Your new challenge is</h3>
                    <h1>
                        {this.state.a} x {this.state.b}
                    </h1>
                </div>
                <form onSubmit={this.handleSubmitResult}>
                    <label>
                        Your alias:
                        <input type="text" maxLength="12" name="user"
                               value={this.state.user} onChange={this.handleChange}/>
                    </label>
                    <br/>
                    <label>
                        Your guess:
                        <input type="number" min="0" name="guess"
                            value={this.state.guess} onChange={this.handleChange}/>
                    </label>
                    <br/>
                    <input type="submit" value="Submit"/>
                </form>
                <h4>{this.state.message}</h4>
            </div>
        );
    }

ChallengeComponent有一个根div元素,包含3个主要代码块。第一个代码块通过state中的两个参数来显示挑战。最后一个代码块,展示message状态属性。第二个代码块创建了一个表单,可以让用户输入自己的猜测。在表单中,涉及相关的处理,用于处理用户输入。

    handleChange(event) {
        const name = event.target.name;
        this.setState({
            [name]: event.target.value
        });
    }

    handleSubmitResult(event) {
        event.preventDefault();
        ApiClient.sendGuess(this.state.user,
            this.state.a,
            this.state.b,
            this.state.guess)
            .then(res => {
                if (res.ok) {
                    res.json().then(json => {
                        if (json.correct) {
                            this.updateMessage("Congratulations! Your guess is correct");
                        } else {
                            this.updateMessage("Oops! Your guess " + json.reaultAttempt + " is" +
                                " wrong, but keep playing!");
                        }
                    });
                } else {
                    this.updateMessage("Error: server error or not available");
                }
            });
    }

表单提交时,调用服务器的API来发送猜测。当获取响应时,检查是否正常,解析JSON,然后,更新状态中的message属性,最后,相应部分的HTML DOM对象会被再次渲染。

与应用程序集成

现在,以及完成了组件的代码,就可以在应用程序中使用了。修改App.js,在其中添加创建的组件。

import React from "react";
import './App.css';
import ChallengeComponent from './components/ChallengeComponent';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <ChallengeComponent/>
      </header>
    </div>
  );
}

export default App;

框架应用程序在index.js中使用此App组件,构建代码时,生成的脚本包含在index.html文件中。
还需要调整App.test.js中包含的测试代码或直接删除。这里不会探讨React测试的细节,现在可以将其删除。

第一次运行前端

确保运行了Spring Boot应用程序,启动控制台,进入前端应用程序的文件夹,执行npm start命令来启动React前端。
成功编译后,会打开默认浏览器并显示位于localhost:3000的页面,显示如下:
空白前端
这里出问题了,应该去后端获取参数的,但现在的参数区域空白,下面看看如何进行调试。

调试

大多数浏览器都为开发者提供了功能强大的工具,打开开发者模式,刷新浏览器,就可以查看前端是否与后端正确交互。
上面的网页刷新,在开发者模式下,单击“网络”选项卡,会看到对http://localhost:8080/challenges/random的HTTP请求失败,如图所示:
火狐开发者模式
控制台还显示一条描述性消息:已拦截跨源请求:同源策略禁止读取位于 http://localhost:8080/challenges/random 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。状态码:200。
默认情况下,浏览器会阻止那些尝试访问前端所在域以外的域中的资源的请求,以避免浏览器中的恶意页面访问其他页面中的数据,这称为“同源策略”。本例中,虽然在本地主机中同时运行前端和后端,但是不同的端口,因此被认为是不同源的。
有多种方法可以解决该问题。这里,将启用跨域资源共享(CORS),这是一种可在服务器端启用的安全策略,允许前端使用来自不同源的REST API。

将CORS配置添加到Spring Boot应用

回到后端代码库,添加一个Spring Boot @Configuration类,配置CORS,代码如下:

package cn.zhangjuli.multiplication.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author Juli Zhang, <a href="mailto:zhjl@lut.edu.cn">Contact me</a> <br>
 */
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("http://localhost:3000");
    }
}

这里通过CorsRegistry 实例完成工作,添加一个映射,允许前端的源访问任何路径(用/**表示)。也可以省略allowedOrigins部分,这样,所有的源域都可以访问。

注意:当前端和后端部署到不同的主机时,应该提供有选择的CORS配置策略,避免为所有的源域添加完全访问权限。

使用应用程序

现在,前后端可以协同工作了,重新启动前后端应用程序,刷新浏览器,如图所示:
使用
这是一个测试,可以完成猜测游戏了。

部署React应用程序

目前为止,前端一直使用的是开发模式,这不是生产环境的工作方式。
要想部署React应用程序,首先需要构建它,使用npm run build命令来构建用于生产部署的React应用程序。执行如下:

> npm run build

> multiplication-frontend@0.1.0 build
> react-scripts build

Creating an optimized production build...
One of your dependencies, babel-preset-react-app, is importing the
"@babel/plugin-proposal-private-property-in-object" package without
declaring it in its dependencies. This is currently working because
"@babel/plugin-proposal-private-property-in-object" is already in your
node_modules folder for unrelated reasons, but it may break at any time.

babel-preset-react-app is part of the create-react-app project, which
is not maintianed anymore. It is thus unlikely that this bug will
ever be fixed. Add "@babel/plugin-proposal-private-property-in-object" to
your devDependencies to work around this error. This will make this message
go away.

Compiled successfully.

File sizes after gzip:

  47.14 kB  build\static\js\main.b3d22150.js
  1.79 kB   build\static\js\787.444a2e11.chunk.js
  515 B     build\static\css\main.f855e6bc.css

The project was built assuming it is hosted at /.
You can control this with the homepage field in your package.json.

The build folder is ready to be deployed.
You may serve it with a static server:

  serve -s build

Find out more about deployment here:

  https://cra.link/deployment

该命令在build文件夹下生成了所有脚本和文件,还可以在其中找到放在public文件夹中的文件的副本。这些日志还说明了如何使用npm安装静态Web服务器。
另外,Spring Boot应用程序已经嵌入了Web服务器Tomcat,也可以直接使用。最简单的方式是,将整个应用程序(前端和后端)打包在同一个可部署单元中:Spring Boot生成的胖JAR文件。需要做的就是,将前端build文件夹中的所有文件复制到Multiplication代码库的src/main/resources/static文件夹中。Spring Boot的默认服务器配置为静态Web文件添加了一些预定义的位置,static文件夹就是其中之一。如图所示:
将build结果放入静态资源中
可根据需要配置这些资源位置及其映射。其中一个需要微调的就是WebMvcConfigurer接口实现。这里不需要改动,因为前端和后端共享同一个源域http://localhost:8080,当然,也可以删除它。

小结

文章介绍了如何基于React创建一个前端Web应用程序的过程。首先,使用create-react-app工具创建React应用程序框架,然后创建一个ApiClient类来实现与后端API服务的访问,并创建一个使用该服务并显示结果的React组件。为了使前后端能够协同,在后端增加了CORS配置。最后,介绍了如何构建用于生产环境的React应用程序,以及如何在Spring Boot的嵌入式Tomcat中集成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/180738.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C语言】函数(三):为什么要有函数声明

目录 前言函数定义函数声明为什么要有函数声明原因1&#xff1a;分模块编程原因2&#xff1a;静态库文件 前言 在上文中已经介绍了函数调用&#xff0c;分为传值调用和传址调用&#xff0c;以及嵌套调用和链式访问。在本文中将介绍函数的声明和定义&#xff0c;以及为什么要有函…

使用 Pinia 的五个技巧

在这篇文章中&#xff0c;想与大家分享使用 Pinia 的五大技巧。 以下是简要总结&#xff1a; 不要创建无用的 getter在 Option Stores 中使用组合式函数&#xff08;composables&#xff09;对于复杂的组合式函数&#xff0c;使用 Setup Stores使用 Setup Stores 注入全局变量…

SQL零基础入门教程,贼拉详细!贼拉简单! 速通数据库期末考!(十二)

SUM&#xff08;&#xff09;求和函数 SUM() 函数返回数值列的总和。 语法&#xff1a; SELECT SUM(column_name) FROM table_name;column_name:字段名&#xff08;必须是数值字段&#xff09; table_name&#xff1a;表名 示例&#xff1a; 查询每位同学的总分&#xff1a…

2、单片机及开发板介绍

单片机介绍 单片机&#xff0c;英文Micro Controller Unit,简称&#xff1a;MCU 内部集成&#xff1a;CPU、RAM(随机存储器)、ROM&#xff08;只读存储器&#xff09;、定时器、中断系统、通讯接口等 作用&#xff1a;信息采集&#xff08;传感器&#xff09;、处理&#xff0…

[autojs]利用console实现悬浮窗日志输出

"ui"; ui.layout(<vertical><button id"autoFloatWindow" text"开启悬浮窗" textSize"15sp" /><button id"autoService" text"开启无障碍服务" textSize"15sp" /><button id"…

聚水潭连接API,集成无代码开发,优化电商平台运营

聚水潭连接API&#xff0c;实现电商平台的高效运营 聚水潭作为一款SaaS ERP解决方案&#xff0c;通过其出色的产品和服务&#xff0c;迅速在市场上占据了一席之地。而其无代码开发的特点&#xff0c;为电商系统和客服系统的连接与集成提供了便利。聚水潭开放平台的优势在于&am…

[ChatGPT]ChatGPT免费,不用翻墙!?——你需要的装备

系列文章目录 【AIGC】服务于人类&#xff5c;一种新的人工智能技术-CSDN博客 文章目录 目录 系列文章目录 文章目录 前言 一、天意云网站 ​编辑 二、使用步骤 可以看到有云服务器、Rstudio以及我们的ChatGPT&#xff0c;我这次主要分享ChatGPT&#xff0c;其他的有机会我再给…

如何避免Steam搬砖项目中账号被盗

购买steam余额有风险吗&#xff1f;及N种被红锁的情况 相信最近很多人都已经听说过steam游戏搬砖这个项目&#xff0c;也叫CSGO游戏搬砖项目&#xff0c;还有人叫它&#xff1a;国外steam游戏汇率差项目&#xff0c;无论怎么称呼&#xff0c;都是同一个项目。 那么什么是stea…

【SpringMVC】 参数传递

一.项目目录 SpringBoot项目创建之后会生成很多目录 删除不需要的这四个文件/目录 目录 二.Spring MVC 和 MVC Spring MVC(Spring Web MVC) Spring Web MVC 是⼀个 Web 框架 MVC : Model View Controller 它是一种思想 , 它把一个项目分成了三个部分. View视图层 界面显示…

HOOPS Web平台助力开发3D应用,实现超大规模3D web轻量化渲染与数据格式转换!

一、包含的软件开发工具包 HOOPS Web平台帮助开发人员构建基于Web的工程应用程序&#xff0c;提供高级3D Web可视化、准确快速的CAD数据访问和3D数据发布。 HOOPS Web平台包括三个集成软件开发工具包 (SDK)&#xff1a; &#xff08;1&#xff09;Web端3D可视化引擎 HOOPSCom…

labview 安捷伦 34970A 采集温度等

本文详细描述了怎么用安捷伦34970A采集温度&#xff0c;并列出了labview的下载链接&#xff0c;具有一定的参考价值。 1.必要条件&#xff1a; RS-232电缆一根 IO Libraries Suite 软件 BenchLink Data Logger 软件 软件可以在http://www.keysight.com.cn下载 检查RS-232…

Hadoop学习总结(MapReduce的数据去重)

现在假设有两个数据文件 file1.txtfile2.txt2018-3-1 a 2018-3-2 b 2018-3-3 c 2018-3-4 d 2018-3-5 a 2018-3-6 b 2018-3-7 c 2018-3-3 c2018-3-1 b 2018-3-2 a 2018-3-3 b 2018-3-4 d 2018-3-5 a 2018-3-6 c 2018-3-7 d 2018-3-3 c 上述文件 file1.txt 本身包含重复数据&…

本地canal安装和使用

1、组件版本 canal.deployer-1.1.7 kafka_2.13-2.6.0 jdk8 apache-zookeeper-3.6.0-bin mysql5.7 2、解压canal.deployer-1.1.7 2.1、修改canal.properties配置文件 ##改为kafka canal.serverModekafka## 改为instance canal.destinations instance## 改为true&#x…

强化学习------贝尔曼方程

目录 前言基础知识马尔可夫决策过程 (Markov decision process, MDP)回报(Return)折扣回报(Discounted Return) State Value&#xff08;状态价值函数&#xff09;贝尔曼方程的推导贝尔曼方程的矩阵形式Action Value&#xff08;动作价值函数&#xff09;贝尔曼最优公式 前言 …

基于 Modbus 的工业数据采集、控制(part 2)

基本处理流程 服务器 parse_and_process(char * input)//input :post请求发送的正文 {...// 请求 modbus 数据else if(strstr(input, "modbus_get")){return handle_get(sock, input);}// 控制 modbus 设备else if(strstr(input, "modbus_set")){return …

【OpenAI】经营权争夺战关系图

《OpenAI新模型曝重大飞跃&#xff1a;AGI雏形或威胁人类&#xff0c;也成Altman被解雇导火索&#xff01;》摘要如下: [一句话总结] OpenAI的Q*项目取得突破&#xff0c;解决了以前未见过的数学问题&#xff0c;为AI发展带来重要的技术里程碑。 [文章概览要点] OpenAI内部研…

redis运维(十四) hash缓存案例

一 缓存案例 ① 需求 ② 个人理解 策略&#xff1a;不更新缓存&#xff0c;而是删除缓存大部分观点认为&#xff1a;1、做缓存不应该是去更新缓存,而是应该删除缓存2、然后由下个请求去缓存,发现不存在后再读取数据库,写入redis缓存 高并发场景下,到底先更新缓存还是先更…

完美解决RuntimeError: implement_array_function method already has a docstring

文章目录 一、报错原因--numpy版本太低二、更新numpy总结 一、报错原因–numpy版本太低 当收到 "RuntimeError: implement_array_function method already has a docstring" 错误时&#xff0c;这可能是由于在numpy的某个版本中&#xff0c;该方法的文档字符串&…

vue3-生命周期

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来vue篇专栏内容:vue3-生命周期 目录 vue3生命周期 vue3生命周期钩子 1.1 onMounted() 1.2 onUpdated() 1.3 onU…

2024年天津专升本招生计划及其收费标准

2024年天津专升本招生计划及其收费标准 天津农学院 文史类 人力资源管理 20 4400 文史类 物流管理 20 4400 理工类 人力资源管理 10 4400 理工类 物流管理 10 4400 理工类 水文与水资源工程 30 5400 有专业限制 理工类 水产养殖学 20 4400 有专业限制 天津…