【React】入门Day04 —— 项目搭建及登录与表单校验、token 管理、路由鉴权实现
项目搭建
-
创建项目
# 使用npx创建项目 npx create-react-app my-react-app # 进入项目目录 cd my-react-app # 创建项目目录结构 mkdir -p src/{apis,assets,components,pages,store,utils} touch src/{App.js,index.css,index.js}- 使用
npx create-react-app创建项目,进入项目目录后通过npm start启动。 - 调整项目目录结构,包括
apis、assets、components、pages等多个文件夹。
- 使用
-
使用技术
- 接入
scss预处理器,安装sass工具,创建全局样式文件index.scss。# 安装sass工具 npm i sass -D// 在src/index.scss中设置全局样式 body {font-family: Arial, sans-serif;background-color: #f4f4f4; } - 引入组件库
antd,安装后在Login页面测试Button组件。# 安装antd组件库 npm i antd// 在src/pages/Login/index.jsx中使用Button组件 import React from 'react'; import { Button } from 'antd';const Login = () => {return (<div><Button type='primary'>登录</Button></div>); };export default Login; - 使用
react-router-dom配置基础路由,创建Layout和Login组件并配置路由规则。# 安装react-router-dom npm i react-router-dom// 在src/router/index.js中配置路由 import { createBrowserRouter } from 'react-router-dom'; import Login from '../pages/Login'; import Layout from '../pages/Layout';const router = createBrowserRouter([{path: '/',element: <Layout />,},{path: '/login',element: <Login />,}, ]);export default router; - 通过
craco工具包配置别名路径,在craco.config.js中设置webpack别名,并在jsconfig.json中配置VsCode提示。# 安装craco工具包 npm i @craco/craco -D// 在craco.config.js中配置别名 const path = require('path'); module.exports = {webpack: {alias: {'@': path.resolve(__dirname,'src')}} };// 在package.json中修改scripts命令 "scripts": {"start": "craco start","build": "craco build","test": "craco test","eject": "react-scripts eject" }// 在src/router/index.js中使用别名 import { createBrowserRouter } from 'react-router-dom'; import Login from '@/pages/Login'; import Layout from '@/pages/Layout';const router = createBrowserRouter([{path: '/',element: <Layout />,},{path: '/login',element: <Login />,}, ]);export default router;// 在jsconfig.json中配置VsCode提示 {"compilerOptions": {"baseUrl": "./","paths": {"@/*": ["src/*"]}} }
- 接入
-
功能模块实现
-
登录模块
-
基本结构搭建
-
-
- 在
Login/index.js创建登录页面结构,引入antd组件,使用@/assets路径引入图片,在Login/index.scss中设置样式。 -
import React from 'react'; import { Card, Form, Input, Button } from 'antd'; import logo from '@/assets/logo.png'; import './index.scss';const Login = () => {return (<div className="login"><Card className="login-container"><img className="login-logo" src={logo} alt="" /><Form><Form.Item><Input size="large" placeholder="请输入手机号" /></Form.Item><Form.Item><Input size="large" placeholder="请输入验证码" /></Form.Item><Form.Item><Button type="primary" htmlType="submit" size="large" block>登录</Button></Form.Item></Form></Card></div>); };export default Login; -
表单校验实现
- 为
Form组件设置validateTrigger,为Form.Item组件设置name和rules属性进行表单校验。import React from 'react'; import { Form, Input, Button } from 'antd';const Login = () => {return (<Form validateTrigger={['onBlur']}><Form.Itemname="mobile"rules={[{ required: true, message: '请输入手机号' },{pattern: /^1[3-9]\d{9}$/,message: '手机号码格式不对'}]}><Input size="large" placeholder="请输入手机号" /></Form.Item><Form.Itemname="code"rules={[{ required: true, message: '请输入验证码' },]}><Input size="large" placeholder="请输入验证码" maxLength={6} /></Form.Item><Form.Item><Button type="primary" htmlType="submit" size="large" block>登录</Button></Form.Item></Form>); };export default Login;
- 为
-
获取登录表单数据
- 为
Form组件设置onFinish属性,在点击登录按钮时触发获取表单数据的函数。import React from 'react'; import { Form, Input, Button } from 'antd';const Login = () => {const onFinish = formValue => {console.log(formValue);};return (<Form onFinish={onFinish}><Form.Item><Input size="large" placeholder="请输入手机号" /></Form.Item><Form.Item><Input size="large" placeholder="请输入验证码" /></Form.Item><Form.Item><Button type="primary" htmlType="submit" size="large" block>登录</Button></Form.Item></Form>); };export default Login;
- 为
-
封装 request 工具模块
- 安装
axios,在utils/request.js中创建axios实例,配置baseURL、请求拦截器和响应拦截器。# 安装axios npm i axiosimport axios from 'axios';const http = axios.create({baseURL: 'http://example.com/api',timeout: 5000 });// 请求拦截器 http.interceptors.request.use(config => {return config; }, error => {return Promise.reject(error); });// 响应拦截器 http.interceptors.response.use(response => {return response.data; }, error => {return Promise.reject(error); });export { http };
- 安装
-
使用 Redux 管理 token
- 安装
react-redux和@reduxjs/toolkit,在store中创建userStore切片,设置token初始状态和setUserInfo等reducers,封装fetchLogin异步方法。# 安装react-redux和@reduxjs/toolkit npm i react-redux @reduxjs/toolkitimport { createSlice } from '@reduxjs/toolkit'; import { http } from '@/utils';const userStore = createSlice({name: 'user',initialState: {token: ''},reducers: {setUserInfo(state, action) {state.token = action.payload;}} });const { setUserInfo } = userStore.actions; const userReducer = userStore.reducer;const fetchLogin = loginForm => {return async dispatch => {const res = await http.post('/authorizations', loginForm);dispatch(setUserInfo(res.data.token));}; };export { fetchLogin }; export default userReducer;
- 安装
-
实现登录逻辑
- 在
Login组件中调用fetchLogin方法,登录成功后跳转到首页并提示。import React from 'react'; import { message } from 'antd'; import { useDispatch } from 'react-redux'; import { fetchLogin } from '@/store/modules/user';const Login = () => {const dispatch = useDispatch();const onFinish = async formValue => {await dispatch(fetchLogin(formValue));message.success('登录成功');};return (<div><form onSubmit={onFinish}>{/* 登录表单字段 */}</form></div>); };export default Login;
- 在
-
token 持久化
- 封装
setToken、getToken和clearToken方法,在userStore中setUserInfo时将token存入本地。// 在@/utils/token.js中封装存取方法 const TOKENKEY = 'token_key';function setToken(token) {return localStorage.setItem(TOKENKEY, token); }function getToken() {return localStorage.getItem(TOKENKEY); }function clearToken() {return localStorage.removeItem(TOKENKEY); }export {setToken,getToken,clearToken };// 在userStore中使用token持久化方法 import { createSlice } from '@reduxjs/toolkit'; import { http } from '@/utils'; import { getToken, setToken } from '@/utils/token';const userStore = createSlice({name: 'user',initialState: {token: getToken() || ''},reducers: {setUserInfo(state, action) {state.token = action.payload;setToken(state.token);}} });export default userStore;
- 封装
-
请求拦截器注入 token
- 在
request.js的请求拦截器中,判断是否有token,有则添加到请求头Authorization中。// 在utils/request.js中注入token import axios from 'axios';const http = axios.create({baseURL: 'http://example.com/api',timeout: 5000 });http.interceptors.request.use(config => {const token = getToken();if (token) {config.headers.Authorization = `Bearer ${token}`;}return config; }, error => {return Promise.reject(error); });http.interceptors.response.use(response => {return response.data; }, error => {return Promise.reject(error); });export { http };
- 在
-
路由鉴权实现
- 在
components/AuthRoute/index.jsx中创建路由鉴权高阶组件,判断本地是否有token,决定是否重定向到登录页面。import React from 'react'; import { Navigate } from 'react-router-dom'; import { getToken } from '@/utils';const AuthRoute = ({ children }) => {const isToken = getToken();if (isToken) {return <>{children}</>;} else {return <Navigate to="/login" replace />;} };export default AuthRoute;// 在src/router/index.js中使用AuthRoute组件 import { createBrowserRouter } from 'react-router-dom'; import Login from '@/pages/Login'; import Layout from '@/pages/Layout'; import AuthRoute from '@/components/AuthRoute';const router = createBrowserRouter([{path: '/',element: <AuthRoute><Layout /></AuthRoute>,},{path: '/login',element: <Login />,}, ]);export default router;
- 在
-
Layout 模块
-
基本结构和样式 reset
- 在
pages/Layout/index.js中使用antd/Layout组件创建页面结构,引入antd的Menu和Popconfirm等组件,设置样式并安装normalize.css进行样式 reset。import React from 'react'; import { Layout, Menu, Popconfirm } from 'antd'; import { HomeOutlined, DiffOutlined, EditOutlined, LogoutOutlined } from '@ant-design/icons'; import './index.scss'; import 'normalize.css';const { Header, Sider } = Layout;const items = [{label: '首页',key: '1',icon: <HomeOutlined />,},{label: '文章管理',key: '2',icon: <DiffOutlined />,},{label: '创建文章',key: '3',icon: <EditOutlined />,}, ];const GeekLayout = () => {return (<Layout><Header className="header"><div className="logo" /><div className="user-info"><span className="user-name">用户名</span><span className="user-logout"><Popconfirm title="是否确认退出?" okText="退出" cancelText="取消"><LogoutOutlined /> 退出</Popconfirm></span></div></Header><Layout><Sider width={200} className="site-layout-background"><Menumode="inline"theme="dark"defaultSelectedKeys={['1']}items={items}style={{ height: '100%', borderRight: 0 }}></Menu></Sider><Layout className="layout-content" style={{ padding: 20 }}>内容</Layout></Layout></Layout>); };export default GeekLayout;
- 在
-
二级路由配置
- 在
pages目录创建Home、Article、Publish页面文件夹,在router/index.js中配置嵌套子路由,在Layout中配置二级路由出口,使用Link修改左侧菜单内容实现路由切换。// 在pages目录创建Home.jsx import React from 'react';const Home = () => {return <div>首页内容</div>; };export default Home;// 在pages目录创建Article.jsx import React from 'react';const Article = () => {return <div>文章管理内容</div>; };export default Article;// 在pages目录创建Publish.jsx import React from 'react';const Publish = () => {return <div>发布文章内容</div>; };export default Publish;// 在src/router/index.js中配置二级路由 import { createBrowserRouter } from 'react-router-dom'; import Login from '@/pages/Login'; import Layout from '@/pages/Layout'; import Publish from '@/pages/Publish'; import Article from '@/pages/Article'; import Home from '@/pages/Home'; import { AuthRoute } from '@/components/AuthRoute';const router = createBrowserRouter([{path: '/',element: (<AuthRoute><Layout /></AuthRoute>),children: [{index: true,element: <Home />,},{path: 'article',element: <Article />,},{path: 'publish',element: <Publish />,},],},{path: '/login',element: <Login />,}, ]);export default router;// 在Layout组件中配置二级路由出口 import React from 'react'; import { Outlet } from 'react-router-dom';const GeekLayout = () => {return (<Layout className="layout-content" style={{ padding: 20 }}><Outlet /></Layout>); };export default GeekLayout;
- 在
-
路由菜单点击交互实现
- 为
Menu组件设置onClick属性实现点击菜单跳转路由,通过useLocation获取当前路由路径实现菜单反向高亮。import React from 'react'; import { Outlet, useNavigate } from 'react-router-dom'; import { HomeOutlined, DiffOutlined, EditOutlined, LogoutOutlined } from '@ant-design/icons';const items = [{label: '首页',key: '/',icon: <HomeOutlined />,},{label: '文章管理',key: '/article',icon: <DiffOutlined />,},{label: '创建文章',key: '/publish',icon: <EditOutlined />,}, ];const GeekLayout = () => {const navigate = useNavigate();const menuClick = route => {navigate(route.key);};return (<Layout><Header className="main-header"><div className="logo" /><div className="user-info"><span className="user-name">用户名</span><span className="user-logout"><Popconfirm title="是否确认退出?" okText="退出" cancelText="取消"><LogoutOutlined /> 退出</Popconfirm></span></div></Header><Layout><Sider width={200} className="site-layout-background"><Menumode="inline"theme="dark"selectedKeys={['1']}items={items}style={{ height: '100%', borderRight: 0 }}onClick={menuClick}></Menu></Sider><Layout className="layout-content" style={{ padding: 20 }}><Outlet /></Layout></Layout>); };export default GeekLayout;// 菜单反向高亮实现 import React from 'react'; import { Outlet, useLocation } from 'react-router-dom'; import { HomeOutlined, DiffOutlined, EditOutlined, LogoutOutlined } from '@ant-design/icons';const items = [{label: '首页',key: '/',icon: <HomeOutlined />,},{label: '文章管理',key: '/article',icon: <DiffOutlined />,},{label: '创建文章',key: '/publish',icon: <EditOutlined />,}, ];const GeekLayout = () => {const location = useLocation();const selectedKey = location.pathname;return (<Layout><Header className="main-header"><div className
- 为
-
展示个人信息
- 在
store/userStore.js中编写获取用户信息的逻辑,在Layout组件中触发fetchUserInfo方法获取信息并渲染用户名。// store/userStore.js import { createSlice } from '@reduxjs/toolkit'; import { http } from '@/utils'; import { getToken, setToken } from '@/utils';const userStore = createSlice({name: 'user',initialState: {token: getToken() || '',userInfo: {}},reducers: {setUserToken(state, action) {state.token = action.payload;setToken(state.token);},setUserInfo(state, action) {state.userInfo = action.payload;},clearUserInfo(state) {state.token = '';state.userInfo = {};clearToken();}} });// 解构出actionCreater const { setUserToken, setUserInfo, clearUserInfo } = userStore.actions; // 获取reducer函数 const userReducer = userStore.reducer;const fetchLogin = (loginForm) => {return async (dispatch) => {const res = await http.post('/authorizations', loginForm);dispatch(setUserToken(res.data.token));}; };const fetchUserInfo = () => {return async (dispatch) => {const res = await http.get('/user/profile');dispatch(setUserInfo(res.data));}; };export { fetchLogin, fetchUserInfo, clearUserInfo }; export default userReducer;
- 在
-
退出登录实现
- 为
Popconfirm添加确认回调事件,在store/userStore.js中新增clearUserInfo方法删除token和用户信息,在回调事件中调用该方法并返回登录页面。// pages/Layout/index.js import React, { useEffect } from 'react'; import { Layout, Menu, Popconfirm } from 'antd'; import {HomeOutlined,DiffOutlined,EditOutlined,LogoutOutlined, } from '@ant-design/icons'; import { useDispatch, useSelector } from 'react-redux'; import { fetchUserInfo } from '@/store/modules/user';const { Header, Sider } = Layout;const items = [// 菜单配置项 ];const GeekLayout = () => {const dispatch = useDispatch();const name = useSelector(state => state.user.userInfo.name);useEffect(() => {dispatch(fetchUserInfo());}, [dispatch]);const loginOut = () => {dispatch(clearUserInfo());// 假设这里有合适的导航函数,替换为实际的导航逻辑// navigate('/login'); };return (<Layout><Header className="header"><div className="logo" /><div className="user-info"><span className="user-name">{name}</span><span className="user-logout"><Popconfirmtitle="是否确认退出?"okText="退出"cancelText="取消"onConfirm={loginOut}><LogoutOutlined /> 退出</Popconfirm></span></div></Header><Layout><Sider width={200} className="site-layout-background"><Menumode="inline"theme="dark"defaultSelectedKeys={['1']}items={items}style={{ height: '100%', borderRight: 0 }}></Menu></Sider><Layout className="layout-content" style={{ padding: 20 }}>{/* 页面内容 */}</Layout></Layout></Layout>); };export default GeekLayout;
- 为
-
处理 Token 失效
- 在
http.interceptors.response中判断响应状态码为401时,清除token,跳转到登录页面并刷新页面。// 在http.js(假设是配置axios请求相关的文件)中处理Token失效 import axios from 'axios';const http = axios.create({baseURL: 'http://example.com/api',timeout: 5000 });http.interceptors.response.use((response) => {return response.data; }, (error) => {if (error.response && error.response.status === 401) {// 假设这里有合适的获取和清除token的函数,替换为实际的逻辑const token = getToken();if (token) {clearToken();}// 假设这里有合适的导航函数,替换为实际的导航逻辑// navigate('/login'); window.location.reload();}return Promise.reject(error); });export { http };
- 在
-
相关文章:
【React】入门Day04 —— 项目搭建及登录与表单校验、token 管理、路由鉴权实现
项目搭建 创建项目 # 使用npx创建项目 npx create-react-app my-react-app # 进入项目目录 cd my-react-app # 创建项目目录结构 mkdir -p src/{apis,assets,components,pages,store,utils} touch src/{App.js,index.css,index.js} 使用npx create-react-app创建项目࿰…...
CMake 属性之目录属性
【写在前面】 CMake 的目录属性是指在特定目录(及其子目录)范围内有效的设置。 这些属性不同于全局变量或目标(Target)属性,它们提供了一种机制,允许开发者为项目中的不同部分定义不同的构建行为。 通过目录…...
ChatGPT:引领人工智能新潮流!
一、ChatGPT 是什么? 1. ChatGPT 的强大功能和广泛应用。 ChatGPT 作为一款先进的 AI 语言模型,拥有众多强大功能。它可以进行文本生成、文本分类、情感分析、机器翻译等多种自然语言处理任务。同时,ChatGPT 还能进行对话式交互,…...
【银河麒麟高级服务器操作系统】安全配置基线相关分析全过程及解决方案
了解更多银河麒麟操作系统全新产品,请点击访问 麒麟软件产品专区:https://product.kylinos.cn 开发者专区:https://developer.kylinos.cn 文档中心:https://documentkylinos.cn 服务器环境以及配置 【机型】物理机或虚机 【…...
用Python实现图片转ASCII艺术:图像处理与字符艺术的完美结合
解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 ASCII艺术是一种通过字符来表现图像的艺术形式,最早用于早期计算机显示器,它仅支持字符显示。如今,尽管图像分辨率和显示技术得到了极大的提升,ASCII艺术作为一种复古而别具一格的图像表现形式,仍然受到许多…...
大数据-162 Apache Kylin 全量增量Cube的构建 Segment 超详细记录 多图
点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…...
Redis-缓存过期淘汰策略
缓存淘汰策略 生产上redis内存设置为多少 设置为最大内存的 3/4 redis 会占用物理机多少内存 默认大小是 0,64 位系统下表示不限制内存大小,32位系统表示 3G 如何设置修改redis内存大小 config get maxmemory 查看修改方式 配置文件 单位是字节 2.…...
如何设置LED电子显示屏的屏幕参数?
LED电子显示屏因其高亮度、低能耗和长寿命等优点,在广告、信息显示等领域得到了广泛应用。正确设置屏幕参数对于确保显示屏的最佳性能至关重要。以下是LED电子显示屏设置屏幕参数的步骤: 1. 确定屏幕参数 在开始设置之前,需要了解显示屏的基本…...
Spring Boot Starter Parent介绍
引言 spring-boot-starter-parent 是一个特殊的项目,为基于 Spring Boot 的应用程序提供默认配置和默认依赖。 在本 Spring Boot 教程中,我们将深入了解所有 Spring Boot 项目内部使用的 spring-boot-starter-parent 依赖项。我们将探讨此依赖项所提供…...
【含开题报告+文档+PPT+源码】基于SpringBoot乡村助农益农平台的设计与实现
开题报告 近年来,随着社会经济的快速发展和人民生活水平的提高,人们对优质农产品的需求越来越高。然而,传统的农产品销售管理模式存在一些问题。首先,农产品供应链信息不透明,导致生产者难以了解市场需求和价格变动趋…...
数据中心运维挑战:性能监控的困境与智能化解决方案的探寻
随着数字化进程的加速,数据中心已成为企业信息架构的核心支撑,其运维管理的复杂度和重要性也随之提升。运维团队需应对设备老化、资源分配失衡、性能波动等多重难题,以确保数据中心持续高效运行。 其中,性能监控作为运维管理的关键…...
基于SSM的民宿管理系统【附源码】
基于SSM的民宿管理系统(源码L文说明文档) 目录 4 系统设计 4.1 系统概要设计 4.2 系统功能结构设计 4.3 数据库设计 4.3.1 数据库E-R图设计 4.3.2 数据库表结构设计 5 系统实现 5.1用户信息管理 5.2 房东信息管理…...
显卡 3090 vs v100
1.3090 Date: 2020 AmperePielines/ Cuda cores: 10496 2.V100 Date: 2018 VoltaPielines/ Cuda cores: 5129 3.结构 & Core比较: v100优点: v100功耗小v100较快的双精度(fp64)和混合精度(fp16fp32)pcie版的NVLink与2080ti完全一致 v100缺点: 不支持整数格式计算&…...
怎么在单片机裸机程序中移植EasyLogger?
1、介绍 EasyLogger 是一款超轻量级、高性能的C日志库,非常适合对资源敏感的软件项目。例如:IoT产品、可穿戴设备、智能家居等等。相比log4c、zlog这些知名的C日志库,EasyLogger的功能更加简单,提供给用户的接口更少,但…...
C/C++解析文件名和目录路径
文章目录 主要函数使用注意事项示例程序总结 #include <libgen.h> 是一个 C/C 语言的头文件,主要用于字符串处理,特别是在处理文件路径时。它提供了一些函数来帮助你解析文件名和目录路径。 主要函数 以下是 libgen.h 中一些常见的函数ÿ…...
Git 基本命令行操作
Git是一个开源的分布式版本控制系统,用于管理源代码和文档的版本。以下是Git的基本命令行操作: 一、配置 安装完成后,需要配置Git的用户名和邮箱,以便在提交记录时记录操作者的信息。 配置全局用户名:git config --g…...
【Rust练习】17.泛型
练习题来自:https://practice-zh.course.rs/generics-traits/generics.html 函数 1 // 填空 struct A; // 具体的类型 A. struct S(A); // 具体的类型 S. struct SGen<T>(T); // 泛型 SGen.fn reg_fn(_s: S) {}fn gen_spec_t(_s: SGen<A&…...
java脚手架系列4--测试用例、拦截器
异常处理、拦截器、数据库连接 1 测试用例 单元测试是一个老生常谈的问题,无论是后端对自己的代码质量把的第一道关也好,也是对测试减缓压力。这里就不过多讲述测试用例的重要性,但是有2个框架我们必须了解一下。 1.1 JUnit和mockito 我们…...
论文推荐 |【Agent】自动化Agent设计系统
论文标题: Automated Design of Agentic Systems 论文地址: https://arxiv.org/abs/2408.08435 GitHub地址: https://github.com/ShengranHu/ADAS 自动化代理设计在性能和通用性方面显著超越了手动方法。 • 引入了自动化代理系统设计&am…...
Linux操作系统提供了五种主要的IO(输入/输出)模型
Linux操作系统提供了五种主要的IO(输入/输出)模型,这些模型旨在优化应用程序对输入输出操作的管理和处理。以下是关于这五种IO模型的详细介绍。 一、阻塞IO(Blocking IO) 阻塞IO是最常见、最传统的IO模型。在这种模型…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
