0802api设计和实战-网络ajax请求1-react-仿低代码平台项目

文章目录

    • 1 API设计
      • 1.1 用户功能
        • 1.1.1 获取用户信息
        • 1.1.2 注册
        • 1.1.3 登录
      • 1.2 问卷功能
        • 1.2.1 获取单个问卷
        • 1.2.2 获取问卷列表
        • 1.2.3 创建问卷
        • 1.2.4 更新问卷
        • 1.2.5 批量彻底删除问卷
        • 1.2.6 复制问卷
      • 1.3 小结
    • 2 实战
      • 2.1配置axios
      • 2.2 封装API和测试
      • 2.3 新建问卷
      • 2.4 自定义hooks封装获取问卷信息
      • 2.5 使用useRequest重构Ajax请求-统一处理
      • 2.6 开发问卷列表
      • 2.7 第三方hook抽离搜索功能
      • 2.8 开发星标和回收站
    • 结语

1 API设计

1.1 用户功能

1.1.1 获取用户信息
  • method: get
  • path: /api/user/info
  • response:
    • 成功:{errno: 0, data{...}}
    • 失败:{errno: 10001, mes: 'xxx'}
1.1.2 注册
  • method: post

  • path: /api/user/register

  • request body: {username, password, nickname}

  • response: {errno: 0}

1.1.3 登录
  • method: post
  • path: /api/user/login
  • request body: {username, password}
  • response: {errno: 0, token}
    • Token令牌:使用jwt

1.2 问卷功能

1.2.1 获取单个问卷
  • method: get
  • path: /api/question/:id
  • response: {errno: 0, data: {id, title,...}}
1.2.2 获取问卷列表
  • method: get
  • path: /api/question/
  • response: {errno: 0, data:{list:[{...}}
1.2.3 创建问卷
  • method: post
  • path: /api/question
  • request body: 暂无
  • response: {errno: 0, data: {id}}
1.2.4 更新问卷
  • method: patch
  • path: /api/question/:id
  • response: {errno: 0}

tips:删除是“假删除”,实际 是更新isDeleted属性

1.2.5 批量彻底删除问卷
  • method: delete
  • path: /api/question
  • request body: {ids: [...]}
  • response: {errno: 0}
1.2.6 复制问卷
  • method: post
  • path: `/api/question/duplicate/:id``
  • response: {errno: 0, data: {id}}

1.3 小结

  • 使用Restful API
  • 用户验证使用JWT
  • 统一返回格式:{errno, data, msg}

2 实战

2.1配置axios

src/services/request.ts基础代码如下:

import axios from "axios";const request = axios.create({timeout: 5000,
});export default request;

添加返回类型和统一错误出来,request.ts代码如下:

import axios from "axios";
import { message } from "antd";const request = axios.create({timeout: 5000,
});// response 拦截:统一处理errno和msg
request.interceptors.response.use(res => {const resData = (res.data || {}) as ResTypeconst {errno, data, msg} = resDataif (errno !== 0) {// 错误提示if (msg) {message.error(msg)}throw new Error(msg);}return data as any}
)
export default request;export type ResDataType = {[key: string]: any;
};export type ResType = {errno: number;data?: ResDataType;msg?: string;
};

2.2 封装API和测试

获取问卷信息API,src/api/question.ts代码如下:

import request, { ResDataType } from "../services/request";export async function getQuestionApi(id: string): Promise<ResDataType> {const url = `/api/question/${id}`;const data = (await request.get(url)) as ResDataType;return data;
}

src/pages/quesiton/Edit/index.tsx代码如下:

import { FC, useEffect} from "react";
import { useParams } from "react-router-dom";
import { getQuestionApi } from "@/api/question";const Edit: FC = () => {const { id = "" } = useParams();// 获取问卷信息useEffect(()=> {async function fn() {const resData = await getQuestionApi(id)console.log(resData);}fn()}, [])return <div>Edit {id}</div>;
};export default Edit;

测试结果如下图所示:在这里插入图片描述

2.3 新建问卷

封装新建问卷API,question.ts代码如下:

import request, { ResDataType } from "../services/request";.../*** 新建问卷* @returns 问卷id*/
export async function createQuestionApi() {const url = `/api/question`;const data = (await request.post(url)) as ResDataType;return data;
}

ManageLayout.tsx中调用新建问卷,src/layouts/MangeLayout.tsx代码如下:

import { FC, useState } from "react";
import { Outlet, useNavigate, useLocation } from "react-router-dom";
import {PlusOutlined,BarsOutlined,StarOutlined,DeleteOutlined,
} from "@ant-design/icons";
import { Button, Space, Divider, message } from "antd";import { createQuestionApi } from "@/api/question";
import styles from "./ManageLayout.module.scss";const ManageLayout: FC = () => {const nav = useNavigate();const { pathname } = useLocation();const [loading, setLoading] = useState(false)// 点击创建问卷async function handleCreateClick() {setLoading(true)const data = await  createQuestionApi()const {id} = data || {}if (id) {nav(`/question/edit/${id}`)message.success("创建成功")}setLoading(false)}return (<div className={styles.container}><div className={styles.left}><Space direction="vertical"><Buttontype="primary"size="large"icon={<PlusOutlined />}onClick={handleCreateClick}disabled={loading}>新建问卷</Button>...);
};export default ManageLayout;

tips:接口请求有延迟,防止用户连续点击按钮,触发重复操作,这里添加loading控制按钮,后续可以用封装好的“防抖”操作替换。

2.4 自定义hooks封装获取问卷信息

在编辑页和统计页都需要获取带加载状态的问卷信息,这里我们通过自定义hooks抽取公共部分,src/hooks/useLoadQuestionData.ts代码如下:

import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";import { getQuestionApi } from "@/api/question";/*** 获取带加载状态的问卷信息* @returns loading状态,问卷信息*/
function useLoadQuestionData() {const { id = "" } = useParams();const [loading, setLoading] = useState(true);const [questionData, setQuestionData] = useState({});useEffect(() => {async function fn() {const data = await getQuestionApi(id);setQuestionData(data);setLoading(false);}fn();}, []);return { loading, questionData };
}export default useLoadQuestionData;

编辑页src/pages/question/Edit/index.tsx代码改造如下:

import { FC } from "react";
import useLoadQuestionData from "@/hooks/useLoadQuestionData";const Edit: FC = () => {// 获取问卷信息const { loading, questionData } = useLoadQuestionData();return (<div><p>Edit page</p><div>{loading ? <p>loading</p> : <p>{JSON.stringify(questionData)}</p>}</div></div>);
};export default Edit;

2.5 使用useRequest重构Ajax请求-统一处理

第三方ahooks-useRequst 当前功能有:

  • 自动/手动请求
  • 轮询
  • 防抖
  • 节流
  • 窗口聚焦刷新
  • 错误重试
  • 加载延迟
  • SWR(stale-while-revalidate)
  • 缓存

由于接口请求,每次都需要定义loading,data,使用useEffect执行函数,很繁琐,这里我们使用第三方ahooks提供的useRequest简化。

改造自定义hook-useLoadQuestionData,useLoadQuestionData.ts代码如下:

import { useParams } from "react-router-dom";
import { useRequest } from "ahooks";
import { getQuestionApi } from "@/api/question";/*** 获取带加载状态的问卷信息* @returns loading状态,问卷信息*/
function useLoadQuestionData() {const { id = "" } = useParams();async function load() {const data = await getQuestionApi(id);return data;}const { loading, data, error } = useRequest(load);return { loading, data, error };
}export default useLoadQuestionData;

改造创建问卷,ManageLayout.tsx代码如下:

import { FC, useState } from "react";
import { Outlet, useNavigate, useLocation } from "react-router-dom";
import {PlusOutlined,BarsOutlined,StarOutlined,DeleteOutlined,
} from "@ant-design/icons";
import { Button, Space, Divider, message } from "antd";import { createQuestionApi } from "@/api/question";
import styles from "./ManageLayout.module.scss";
import { useRequest } from "ahooks";const ManageLayout: FC = () => {const nav = useNavigate();const { pathname } = useLocation();// 点击创建问卷const {loading,// error,run: handleCreateClick,} = useRequest(createQuestionApi, {manual: true,onSuccess: (res) => {nav(`/question/edit/${res.id}`);message.success("创建成功");},});return (<div className={styles.container}><div className={styles.left}><Space direction="vertical"><Buttontype="primary"size="large"icon={<PlusOutlined />}onClick={handleCreateClick}disabled={loading}>新建问卷</Button>
...
};export default ManageLayout;

2.6 开发问卷列表

获取问卷列表mock接口 getQuestionList.js代码如下:

const Mock = require('mockjs');
const Random = Mock.Random;function getQuestionList(len = 10, isDeleted = false) {const list = [];for (let i = 0; i < len; i++) {list.push({_id: Random.id(),title: Random.ctitle(),isPublished: Random.boolean(),isStar: Random.boolean(),answerCount: Random.natural(50, 100),createdAt: Random.datetime(),isDeleted})}return list;
}module.exports = getQuestionList;

question.js代码如下:

const Mock = require('mockjs')const getQuestionList = require("./data/getQuestionList")const Random = Mock.Randommodule.exports = [
...{// 获取问卷列表url: '/api/question',method: 'get',response() {return {errno: 0,data: {list: getQuestionList(),total: 100}}}},
]

question.ts api代码如下所示:

/*** 获取问卷列表* @returns 问卷列表数据*/
export async function getQuestionListApi() {const url = `/api/question`;const data = (await request.get(url)) as ResDataType;return data;
}

List.tsx调用接口代码如下所示:

import { FC } from "react";
// import { useSearchParams } from "react-router-dom";
import { useRequest, useTitle } from "ahooks";
import { Typography, Spin, Divider } from "antd";import QuestionCard from "@/components/QuestionCard";
import ListSearch from "@/components/ListSearch";
import { getQuestionListApi } from "@/api/question";
import styles from "./common.module.scss";const { Title } = Typography;const List: FC = () => {useTitle("调查问卷-我的问卷");// const [searchParams] = useSearchParams();// console.log("keyword", searchParams.get("keyword"));//问卷列表数据const { data = {}, loading } = useRequest(getQuestionListApi);const { list = [], total = 0 } = data;return (<><div className={styles.header}><div className={styles.left}><Title level={3}>我的问卷</Title></div><div className={styles.right}><ListSearch /></div></div><div className={styles.content}>{loading && (<div style={{ textAlign: "center" }}><Spin /></div>)}{!loading &&list.length > 0 &&list.map((q: any) => {const { _id } = q;return <QuestionCard key={_id} {...q} />;})}</div><div className={styles.footer}>loadingMore 上划加载更多</div></>);
};export default List;

2.7 第三方hook抽离搜索功能

在我的问卷、星标问卷和回收站都有搜索功能,有相同的逻辑,这里我们通过自定义hook抽离公共逻辑。自定义搜索hook-useLoadQuestionListData.ts代码如下所示:

import { useSearchParams } from "react-router-dom";
import { useRequest } from "ahooks";
import { getQuestionListApi } from "@/api/question";import { LIST_SEARCH_PARAM_KEY } from "@/constant";/*** 获取问卷列表* @returns 问卷列表*/
function useLoadQuestionListData() {const [searchParams] = useSearchParams();const keyword = searchParams.get(LIST_SEARCH_PARAM_KEY) || "";async function load() {const data = await getQuestionListApi({ keyword });return data;}const { loading, data, error } = useRequest(load, {refreshDeps: [searchParams],});return { loading, data, error };
}export default useLoadQuestionListData;

getQuestionListApi.ts如下所示:

import request, { ResDataType } from "../services/request";type SearchOption = {keyword: string;
};.../*** 获取问卷列表* @param opt 请求参数* @returns 问卷列表数据*/
export async function getQuestionListApi(opt: Partial<SearchOption>
): Promise<ResDataType> {const url = `/api/question`;const data = (await request.get(url, {params: opt})) as ResDataType;return data;
}

说明

  • refreshDeps: useRequest 刷新依赖项,根据数组里面的变量重新执行useRequest
  • request.get(url, {params: opt})),params axios get请求传递参数,形式:url?a=b&b=1…

2.8 开发星标和回收站

星标问卷查询的数据 isStar=true;回收站查询的问卷列表isDeleted=true,我们需要扩展api接口参数。

useLoadQuestionListData.ts代码改造如下:

import { useSearchParams } from "react-router-dom";
import { useRequest } from "ahooks";
import { getQuestionListApi } from "@/api/question";import { LIST_SEARCH_PARAM_KEY } from "@/constant";type OptionType = {isStar: boolean;isDeleted: boolean;
};/*** 获取问卷列表* @returns 问卷列表*/
function useLoadQuestionListData(opt: Partial<OptionType>) {const { isStar, isDeleted } = opt;const [searchParams] = useSearchParams();const keyword = searchParams.get(LIST_SEARCH_PARAM_KEY) || "";async function load() {const data = await getQuestionListApi({ keyword, isStar, isDeleted });return data;}const { loading, data, error } = useRequest(load, {refreshDeps: [searchParams],});return { loading, data, error };
}export default useLoadQuestionListData;

星标问卷-Star.tsx代码如下所示:

import { FC } from "react";
import { useTitle } from "ahooks";
import { Typography, Empty, Spin } from "antd";import QuestionCard from "@/components/QuestionCard";
import ListSearch from "@/components/ListSearch";
import styles from "./common.module.scss";
import useLoadQuestionListData from "@/hooks/useLoadQuestionListData";const { Title } = Typography;const List: FC = () => {useTitle("调查问卷-星标问卷");//问卷列表数据const { data = {}, loading } = useLoadQuestionListData({ isStar: true });const { list = [], total = 0 } = data;return (<><div className={styles.header}><div className={styles.left}><Title level={3}>星标问卷</Title></div><div className={styles.right}><ListSearch /></div></div><div className={styles.content}>{loading && (<div style={{ textAlign: "center" }}><Spin /></div>)}{!loading && list.length === 0 && <Empty description="暂无数据" />}{!loading &&list.length > 0 &&list.map((q: any) => {const { _id } = q;return <QuestionCard key={_id} {...q} />;})}</div><div className={styles.footer}>分页</div></>);
};export default List;

回收站-Trash.tsx代码如下所示;

import { FC, useState } from "react";
import { useTitle } from "ahooks";
import {Typography,Empty,Table,Tag,Space,Button,Modal,message,Spin,
} from "antd";import { ExclamationCircleOutlined } from "@ant-design/icons";
import ListSearch from "../../components/ListSearch";
import styles from "./common.module.scss";
import useLoadQuestionListData from "@/hooks/useLoadQuestionListData";const { Title } = Typography;
const { confirm } = Modal;const List: FC = () => {useTitle("调查问卷-回收站");//问卷列表数据const { data = {}, loading } = useLoadQuestionListData({ isDeleted: true });const { list = [], total = 0 } = data;const columns = [{title: "标题",dataIndex: "title",},{title: "是否发布",dataIndex: "isPublished",render: (isPublished: boolean) =>isPublished ? <Tag color="processing">已发布</Tag> : <Tag>未发布</Tag>,},{title: "答卷",dataIndex: "answerCount",},{title: "创建时间",dataIndex: "createdAt",},];// 选择ids集合const [selectedIds, setSelectedIds] = useState<string[]>([]);function del() {confirm({title: "您确定要删除吗?",okText: "确定",cancelText: "取消",content: "删除以后不可找回!",icon: <ExclamationCircleOutlined />,onOk: () => message.success("删除成功"),});}const TableEle = (<><div style={{ marginBottom: "10px" }}><Space><Button type="primary" disabled={selectedIds.length === 0}>恢复</Button><Button danger disabled={selectedIds.length === 0} onClick={del}>彻底删除</Button></Space></div><TabledataSource={list}columns={columns}pagination={false}rowKey={(q: any) => q._id}rowSelection={{type: "checkbox",onChange: (selectRowKeys) => {setSelectedIds(selectRowKeys as string[]);},}}></Table></>);return (<><div className={styles.header}><div className={styles.left}><Title level={3}>回收站</Title></div><div className={styles.right}><ListSearch /></div></div><div className={styles.content}>{loading && (<div style={{ textAlign: "center" }}><Spin /></div>)}{!loading && list.length === 0 && <Empty description="暂无数据" />}{TableEle}</div><div className={styles.footer}>分页</div></>);
};export default List;

服务端星标问卷查询返回的isStar=true;回收站返回的isDeleted=true

index.js代码如下所示:

...async function getRes(fn, ctx) {return new Promise(resolve => {setTimeout(() => {const res = fn(ctx)resolve(res)}, 500);})
}// 注册mock路由
mockList.forEach(item => {const {url, method, response} = itemrouter[method](url, async ctx => {const res = await getRes(response, ctx)ctx.body = res})
})...

question.js代码如下:

...{// 获取问卷列表url: '/api/question',method: 'get',response(ctx) {const { url = '' } = ctxconst isStar = url.indexOf('isStar=true') >= 0const isDeleted = url.indexOf('isDeleted=true') >= 0return {errno: 0,data: {list: getQuestionList({isStar, isDeleted}),total: 100}}}},
]

getQuestionList.js如下所示:

const Mock = require('mockjs');
const Random = Mock.Random;function getQuestionList(opt = {}) {const { len = 10, isStar, isDeleted } = optconst list = [];for (let i = 0; i < len; i++) {list.push({_id: Random.id(),title: Random.ctitle(),isPublished: Random.boolean(),isStar: isStar || Random.boolean(),answerCount: Random.natural(50, 100),createdAt: Random.datetime(),isDeleted: isDeleted || Random.boolean()})}return list;
}module.exports = getQuestionList;

说明

  • 数据展示有3种状态:根据不同的状态有不同展示
    • 加载中:
    • 加载完成,数据为空
    • 加载完成,有数据
  • rowKey={(q: any) => q._id}:ts不设置any类型,程序不报错,但是ts检查错误

结语

❓QQ:806797785

⭐️仓库地址:https://gitee.com/gaogzhen

⭐️仓库地址:https://github.com/gaogzhen

[1]ahook官网[CP/OL].

[2]mock文档[CP/OL].

[3]Ant Design官网[CP/OL].

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android Kotlin AIDL 完整实现与优化指南

本文将详细介绍如何在Android中使用Kotlin实现AIDL&#xff08;Android Interface Definition Language&#xff09;&#xff0c;并提供多种优化方案。 一、基础实现 1. 创建AIDL文件 在src/main/aidl/com/example/myapplication/目录下创建&#xff1a; IMyAidlInterface.…

【数据结构】_栈和队列相关面试题

&#x1f525; 数据结构修炼场 &#x1f525; &#x1f4a5; 栈与队列 终极试炼 &#x1f4a5; &#x1f680; 理论已加载完毕&#xff0c;代码之魂觉醒时刻&#xff01; ⚡️ 是时候用实战点燃你的算法之力了—— 「题目风暴&#xff0c;来袭&#xff01;」 &#xff08;握…

精益数据分析(8/126):从Airbnb案例看精益创业与数据驱动增长

精益数据分析&#xff08;8/126&#xff09;&#xff1a;从Airbnb案例看精益创业与数据驱动增长 大家好&#xff01;一直以来&#xff0c;我都坚信在创业和技术的领域里&#xff0c;持续学习与分享是不断进步的关键。今天&#xff0c;咱们继续深入学习《精益数据分析》&#x…

专题二十:路由策略与策略路由

一、路由策略 1.1 路由策略的概念 路由策略是通过修改路由表的路由条目来控制数据流量的可达性。即对接受和发布的路由进过滤。这种方式称为路由策略 路由策略功能相关作用控制路由的发布可通过路由策略对所要发布的路由信息进行过滤&#xff0c;只允许发布满足条件的路由信…

VSCode 扩展离线下载方法

学习自该文章&#xff0c;感谢作者&#xff01; 2025 年 VSCode 插件离线下载攻略&#xff1a;官方渠道一键获取 - 知乎 获取扩展关键信息 方法一&#xff1a;官网获取 打开 VSCode 扩展官方网站 搜索要下载的扩展&#xff0c;以 CodeGeeX 为例&#xff0c;网址为&#xf…

一 、环境的安装 Anaconda + Pycharm + PaddlePaddle

《从零到一实践&#xff1a;系统性学习生成式 AI(NLP)》 一 、环境的安装 Anaconda Pycharm PaddlePaddle 1. Anaconda 软件安装 Anaconda 软件安装有大量的教程&#xff0c;此处不在说明&#xff0c;安装完成之后界面如下&#xff1a; 2. 创建 Anaconda 虚拟环境 Paddl…

软考教材重点内容 信息安全工程师 第23章 云计算安全需求分析与安全保护工程

23.1.云计算基本概念 云计算就是在这样的需求驱动下而产生的一种计算模式。云计算通过虚拟化及网络通信技术&#xff0c;提供一种按需服务、弹性化的 IT 资源池服务平台。云计算的主要特征如下。 1. IT 资源以服务的形式提供 IT 资源以一种服务产品的形式提供&#xff0c;满…

蓝桥杯 19. 最大比例

最大比例 原题目链接 题目描述 X 星球的某个大奖赛设了 M 级奖励。每个级别的奖金是一个正整数。 并且&#xff0c;相邻两个级别间的比例是一个固定值&#xff0c;也就是说&#xff1a;所有级别的奖金构成一个等比数列。 例如&#xff1a; 奖金数列为 16, 24, 36, 54&…

基于 Python 的自然语言处理系列(82):Transformer Reinforcement Learning

&#x1f517; 本文所用工具&#xff1a;trl、transformers、peft、bitsandbytes &#x1f4d8; 官方文档参考&#xff1a;https://huggingface.co/docs/trl 一、引言&#xff1a;从有监督微调到 RLHF 全流程 随着语言大模型的发展&#xff0c;如何在大规模预训练模型基础上更精…

JAVA猜数小游戏

import java.util.Random; import java.util.Scanner;public class HelloWorld {public static void main(String[] args) {Random rnew Random();int luck_number r.nextInt(100)1;while (true){System.out.println("输入猜数字");Scanner sc new Scanner(System…

GPU渲染阶段介绍+Shader基础结构实现

GPU是什么 &#xff08;CPU&#xff09;Center Processing Unit:逻辑编程 &#xff08;GPU&#xff09;Graphics Processing Unit&#xff1a;图形处理&#xff08;矩阵运算&#xff0c;数据公式运算&#xff0c;光栅化&#xff09; 渲染管线 渲染管线也称为渲染流水线&#x…

Spring Boot + MyBatis 动态字段更新方法

在Spring Boot和MyBatis中&#xff0c;实现动态更新不固定字段的步骤如下&#xff1a; 方法一&#xff1a;使用MyBatis动态SQL&#xff08;适合字段允许为null的场景&#xff09; 定义实体类 包含所有可能被更新的字段。 Mapper接口 定义更新方法&#xff0c;参数为实体对象&…

单例模式:确保唯一实例的设计模式

单例模式&#xff1a;确保唯一实例的设计模式 一、模式核心&#xff1a;保证类仅有一个实例并提供全局访问点 在软件开发中&#xff0c;有些类需要确保只有一个实例&#xff08;如系统配置类、日志管理器&#xff09;&#xff0c;避免因多个实例导致状态混乱或资源浪费。 单…

UnoCSS原子CSS引擎-前端福音

UnoCSS是一款原子化的即时按需 CSS 引擎&#xff0c;其中没有核心实用程序&#xff0c;所有功能都是通过预设提供的。默认情况下UnoCSS应用通过预设来实现相关功能。 UnoCSS中文文档&#xff1a; https://www.unocss.com.cn 前有很多种原子化的框架&#xff0c;例如 Tailwind…

【Qwen2.5-VL 踩坑记录】本地 + 海外账号和国内账号的 API 调用区别(阿里云百炼平台)

API 调用 阿里云百炼平台的海内外 API 的区别&#xff1a; 海外版&#xff1a;需要进行 API 基础 URL 设置国内版&#xff1a;无需设置。 本人的服务器在香港&#xff0c;采用海外版的 API 时&#xff0c;需要进行如下API端点配置 / API基础URL设置 / API客户端配置&#xf…

C语言笔记(鹏哥)上课板书+课件汇总(结构体)-----数据结构常用

结构体 目录&#xff1a; 1、结构体类型声明 2、结构体变量的创建和初始化 3、结构体成员访问操作符 4、结构体内存对齐*****&#xff08;重要指数五颗星&#xff09; 5、结构体传参 6、结构体实现位段 一、结构体类型声明 其实在指针中我们已经讲解了一些结构体内容了&…

UV: Python包和项目管理器(从入门到不放弃教程)

目录 UV: Python包和项目管理器&#xff08;从入门到不放弃教程&#xff09;1. 为什么用uv&#xff0c;而不是conda或者pip2. 安装uv&#xff08;Windows&#xff09;2.1 powershell下载2.2 winget下载2.3 直接下载安装包 3. uv教程3.1 创建虚拟环境 (uv venv) 4. uvx5. 此pip非…

网络开发基础(游戏方向)之 概念名词

前言 1、一款网络游戏分为客户端和服务端两个部分&#xff0c;客户端程序运行在用户的电脑或手机上&#xff0c;服务端程序运行在游戏运营商的服务器上。 2、客户端和服务端之间&#xff0c;服务端和服务端之间一般都是使用TCP网络通信。客户端和客户端之间通过服务端的消息转…

java将pdf转换成word

1、jar包准备 在项目中新增lib目录&#xff0c;并将如下两个文件放入lib目录下 aspose-words-15.8.0-jdk16.jar aspose-pdf-22.9.jar 2、pom.xml配置 <dependency><groupId>com.aspose</groupId><artifactId>aspose-pdf</artifactId><versi…

【C/C++】插件机制:基于工厂函数的动态插件加载

本文介绍了如何通过 C 的 工厂函数、动态库&#xff08;.so 文件&#xff09;和 dlopen / dlsym 实现插件机制。这个机制允许程序在运行时动态加载和调用插件&#xff0c;而无需在编译时知道插件的具体类型。 一、 动态插件机制 在现代 C 中&#xff0c;插件机制广泛应用于需要…