react-问卷星项目(7)
实战
React表单组件
入门
重点在于change的时候改变state的值,类似vue的双向数据绑定v-model,即数据更新的时候页面同步更新,页面数据更新时数据源也能获得最新的值,只是Vue中设置在data中的属性默认绑定,React中需要state触发页面更新
使用原先较多测试组件的项目写基础
input组件
import React, { useState, ChangeEvent } from "react";
// 上下两种引入方式都可以
// import type { ChangeEvent } from "react";function App() {const [text, setText] = useState<string>("hello");function handleChange(event: ChangeEvent<HTMLInputElement>) {// event.target.value就是当前input的值setText(event.target.value);}return (<div><input defaultValue={text} onChange={handleChange} /><button onClick={() => console.log(text)}>打印</button></div>);
}export default App;
- 受控组件:值同步到state,使用value属性,可获可控
- 非受控组件:值不同步到state,使用defaultValue属性,能够设置默认值,但是无法获得更改后最新的数值
- React推荐使用受控组件,看似繁琐(没有规律),但更加可控(有规律,可读)
textarea组件
function App() {const [text, setText] = useState<string>("hello");function handleChange(event: ChangeEvent<HTMLTextAreaElement>) {// event.target.value就是当前input的值setText(event.target.value);}function genHtml() {return { __html: text.replaceAll("\n", "<br>") };}return (<div>{/* <input defaultValue={text} onChange={handleChange} /> */}<textarea value={text} onChange={handleChange}></textarea>{/* {text.replaceAll("\n", "<br>")} */}{/* 上面这个方法中为了防止XSS注入,React会将br换成明文展示在页面而不是换行,可以通过下列方式解决 */}<p dangerouslySetInnerHTML={genHtml()}></p></div>);
}export default App;
radio单选框
function App() {const [gender, setGender] = useState("male");function handleChange(event: ChangeEvent<HTMLInputElement>) {// event.target.value就是当前input的值setGender(event.target.value);}return (<div><label htmlFor="radio1">男</label><inputtype="radio"id="radio1"name="gender"value="male"checked={gender == "male"}onChange={handleChange}/><label htmlFor="radio2">女</label><inputtype="radio"id="radio2"name="gender"value="female"checked={gender === "female"}onChange={handleChange}/><button onClick={() => console.log(gender)}>打印</button></div>);
}export default App;
checkbox复选
function App() {const [selectedList, setSelectedList] = useState<string[]>([]);function handleCityChange(event: ChangeEvent<HTMLInputElement>) {// event.target.value就是当前input的值const city = event.target.value;if (selectedList.includes(city)) {setSelectedList(selectedList.filter((c) => {if (c == city) return false;return true;}),);} else {// 添加setSelectedList(selectedList.concat(city));}}return (<>{/* htmlFor 点击的时候也会触发切换 */}<label htmlFor="checkbox1">北京</label><inputtype="checkbox"id="checkbox1"value="beijing"checked={selectedList.includes("beijing")}onChange={handleCityChange}/><label htmlFor="checkbox2">上海</label><inputtype="checkbox"id="checkbox2"value="shanghai"checked={selectedList.includes("shanghai")}onChange={handleCityChange}/><label htmlFor="checkbox3">深圳</label><inputtype="checkbox"id="checkbox3"value="shenzhen"checked={selectedList.includes("shenzhen")}onChange={handleCityChange}/>{/* 方便表单获取和提交 */}<inputtype="hidden"name="cityInput"value={JSON.stringify(selectedList)}/></>);
}export default App;
select下拉框
function App() {const [lang, setLang] = useState("js");function handleChange(event: ChangeEvent<HTMLSelectElement>) {// event.target.value就是当前input的值setLang(event.target.value);}return (<>{/* 不设置state的话选择了没反应 */}<select value={lang} onChange={handleChange}><option value="java">Java</option><option value="C++">C++</option><option value="python">Python</option></select></>);
}
form表单组件
function App() {function handleSubmit(event: ChangeEvent<HTMLFormElement>) {event.preventDefault(); // 阻止默认行为,即不会提交到action// 可以自行处理提交的逻辑}return (<>{/* 点击提交后会将相应的数据发送到action中填写的接口。提交的就是name和value */}{/* 没有name,没有value的话会导致提交无法识别 */}{/* 隐藏input(type:hidden)的价值就在于可以把想要提交的数据偷偷提交上去 */}{/* onSubmit提交前调用的钩子函数,可以阻止默认行为,不然点击就直接提交了 */}<form action="/api/post" onSubmit={handleSubmit}><input /><br /><textarea /><input type="hidden" /><button type="submit">提交</button></form></>);
}
Ant Design 实现
为什么地址要添加参数,避免刷新的时候搜索数据丢失,不保存的话一刷新页面内容就重置了,保存了之后就算是刷新,由于地址附有参数,刷新时地址不会改变,所以仍能展示出搜索后的数据
同时也是为了避免组件之间的耦合,最好不要一搜索就更新列表组件或者一分页就更新列表组件,而是通过一个更加公共的比如地址栏进行搜索或者分页信息的传递,也能避免刷新后数据无法保存,比如搜索栏一刷新原来的搜索词就没有了,但是可以通过从路径获取参数来达到“保存”的效果
新建constants文件夹,其中设置index.tsx文件保存常用变量,跟router中导出常用变量类似
// 存储所有的常量
export const LIST_SEARCH_PARAM_KEY = "keyword";
搜索栏组件
ListSearch.tsx
import React, { FC, useEffect, useState } from "react";
import { Input } from "antd";
import type { ChangeEvent } from "react";
import { useNavigate, useLocation, useSearchParams } from "react-router-dom";
import { LIST_SEARCH_PARAM_KEY } from "../constants";const { Search } = Input;const ListSearch: FC = () => {const [val, setVal] = useState("");const nav = useNavigate();const { pathname } = useLocation();function handleChange(event: ChangeEvent<HTMLInputElement>) {setVal(event.target.value);}function handleSearch(value: string) {// 跳转页面增加URL参数nav({pathname,search: `${LIST_SEARCH_PARAM_KEY}=${value}`,});}// 获取url参数,并设置到input valueconst [searchParams] = useSearchParams();useEffect(() => {// 每当searchParams有变化就执行函数// serchParams用来获得上面nav中设置的参数const newVal = searchParams.get(LIST_SEARCH_PARAM_KEY) || "";setVal(newVal);}, [searchParams]);return (<SearchallowClearplaceholder="请输入关键字"value={val}onChange={handleChange}onSearch={handleSearch}style={{ width: "260px" }}/>);
};
export default ListSearch;
开发注册页
Register.module.scss
.contain{height: 100vh;width: 100vw;display: flex;flex-direction: column;justify-content: center;align-items: center;background-image: linear-gradient(to top, #5ee7df 0%, #b490ca 100%);// background-image: linear-gradient(to top, #9890e3 0%, #b1f4cf 100%);
}
Register.tsx
import React, { FC } from "react";
import { Typography, Space, Form, Input, Button } from "antd";
import { UserAddOutlined } from "@ant-design/icons";
import styled from "./Register.module.scss";
import { Link } from "react-router-dom";
import { LOGIN_PATHNAME } from "../router";const { Title } = Typography;const Register: FC = () => {// any表示任意类型都可const onFinish = (values: any) => {console.log(values);};return (<div className={styled.contain}><div><Space><Title level={2}><UserAddOutlined /></Title><Title level={2}>注册新用户</Title></Space></div><div><FormlabelCol={{ span: 6 }}wrapperCol={{ span: 16 }}onFinish={onFinish}><Form.Item label="用户名" name="userName"><Input /></Form.Item><Form.Item label="密码" name="passWord"><Input.Password /></Form.Item><Form.Item label="确认密码" name="conFirm"><Input.Password /></Form.Item><Form.Item label="昵称" name="nickName"><Input /></Form.Item><Form.Item wrapperCol={{ offset: 8, span: 16 }}><Space>{/* htmlType就是之前html里的type,只是前面设置属性被占用了,用这个一样的效果都是为了触发方法 */}<Button type="primary" htmlType="submit">注册</Button></Space><Link to={LOGIN_PATHNAME}>已有账户,登录</Link></Form.Item></Form></div></div>);
};
export default Register;
开发登录页
Login.module.scss
.contain{height: 100vh;width: 100vw;display: flex;flex-direction: column;justify-content: center;align-items: center;background-image: linear-gradient(to top, #5ee7df 0%, #b490ca 100%);// background-image: linear-gradient(to top, #9890e3 0%, #b1f4cf 100%);
}
Login.tsx
// 登陆页面
import React, { FC, useEffect } from "react";
import { Link, useNavigate } from "react-router-dom";
import { Space, Typography, Form, Input, Button, Checkbox } from "antd";
import { UserAddOutlined } from "@ant-design/icons";
import { REGISTER_PATHNAME } from "../router";
import styled from "./Login.module.scss";const { Title } = Typography;const USERNAME_KEY = "USERNAME";
const PASSWORD_KEY = "PASSWORD";function rememberUser(username: string, password: string) {localStorage.setItem(USERNAME_KEY, username);localStorage.setItem(PASSWORD_KEY, password);
}function deleteUser() {localStorage.removeItem(USERNAME_KEY);localStorage.removeItem(PASSWORD_KEY);
}function getUser() {return {username: localStorage.getItem(USERNAME_KEY),password: localStorage.getItem(PASSWORD_KEY),};
}const Login: FC = () => {const nav = useNavigate();// 第三方hook,即第三方提供的组件const [form] = Form.useForm();const onFinish = (values: any) => {const { username, password, remember } = values;if (remember) {rememberUser(username, password);} else {deleteUser();}};// 依赖不填写,默认在组件渲染完成后执行useEffect(() => {const { username, password } = getUser();// 这里如果不小心写成了setFieldValue会报错,差了个s,这个只能输入一个参数,有s的才能输入多个form.setFieldsValue({ username, password });}, []);return (<div className={styled.contain}><div><Space><Title level={2}><UserAddOutlined /></Title><Title level={2}>用户登录</Title></Space></div><div><FormlabelCol={{ span: 6 }}wrapperCol={{ span: 16 }}onFinish={onFinish}// 默认remember设置为trueinitialValues={{ remember: true }}// 将返回值关联起来,即使其变成受控组件form={form}><Form.Item label="用户名" name="username"><Input /></Form.Item><Form.Item label="密码" name="password"><Input.Password /></Form.Item><Form.Itemname="remember"valuePropName="checked"wrapperCol={{ offset: 6, span: 16 }}>{/* 表单需要有name和value才能提交,valuePropname就是将Checkbox的checked属性,即选中的属性(true || false)当作值 */}<Checkbox>记住我</Checkbox></Form.Item><Form.Item wrapperCol={{ offset: 6, span: 16 }}><Space><Button type="primary" htmlType="submit">登录</Button><Link to={REGISTER_PATHNAME}>注册新用户</Link></Space></Form.Item></Form></div></div>);
};
export default Login;
表单校验
先在注册里进行校验,使用的都是antd里form的功能,然后复制到登录就行
Register.tsx
// 注册界面
import React, { FC } from "react";
import { Typography, Space, Form, Input, Button, message } from "antd";
import { UserAddOutlined } from "@ant-design/icons";
import styled from "./Register.module.scss";
import { Link } from "react-router-dom";
import { LOGIN_PATHNAME } from "../router";const { Title } = Typography;const Register: FC = () => {// any表示任意类型都可const onFinish = (values: any) => {console.log(values);};return (<div className={styled.contain}><div><Space><Title level={2}><UserAddOutlined /></Title><Title level={2}>注册新用户</Title></Space></div><div><FormlabelCol={{ span: 6 }}wrapperCol={{ span: 16 }}onFinish={onFinish}><Form.Itemlabel="用户名"name="username"rules={[{ required: true, message: "请输入用户名" },// string表示按长度计算区间范围,不然变成数字就成最小5最大20了{type: "string",min: 5,max: 20,message: "字符长度在5-20之间",},{pattern: /^\w+$/,message: "只能是字母数字下划线",},]}><Input /></Form.Item><Form.Itemlabel="密码"name="password"// required表示必填项,会出现红点rules={[{ required: true, message: "请输入密码" }]}><Input.Password /></Form.Item><Form.Itemlabel="确认密码"name="confirm"// 依赖password属性,password变化会重新触发验证dependencies={["password"]}rules={[{ required: true, message: "请确认输入的密码" },// 这个校验传递进去的是一个函数({ getFieldValue }) => ({validator(_, value) {if (getFieldValue("password") === value) {return Promise.resolve();} else {return Promise.reject(new Error("两次密码不一致"));}},}),]}><Input.Password /></Form.Item><Form.Item label="昵称" name="nickname"><Input /></Form.Item><Form.Item wrapperCol={{ offset: 8, span: 16 }}><Space>{/* htmlType就是之前html里的type,只是前面设置属性被占用了,用这个一样的效果都是为了触发方法 */}<Button type="primary" htmlType="submit">注册</Button><Link to={LOGIN_PATHNAME}>已有账户,登录</Link></Space></Form.Item></Form></div></div>);
};
export default Register;
Login.tsx
// 登陆页面
import React, { FC, useEffect } from "react";
import { Link, useNavigate } from "react-router-dom";
import { Space, Typography, Form, Input, Button, Checkbox } from "antd";
import { UserAddOutlined } from "@ant-design/icons";
import { REGISTER_PATHNAME } from "../router";
import styled from "./Login.module.scss";const { Title } = Typography;const USERNAME_KEY = "USERNAME";
const PASSWORD_KEY = "PASSWORD";function rememberUser(username: string, password: string) {localStorage.setItem(USERNAME_KEY, username);localStorage.setItem(PASSWORD_KEY, password);
}function deleteUser() {localStorage.removeItem(USERNAME_KEY);localStorage.removeItem(PASSWORD_KEY);
}function getUser() {return {username: localStorage.getItem(USERNAME_KEY),password: localStorage.getItem(PASSWORD_KEY),};
}const Login: FC = () => {const nav = useNavigate();// 第三方hook,即第三方提供的组件const [form] = Form.useForm();const onFinish = (values: any) => {const { username, password, remember } = values;if (remember) {rememberUser(username, password);} else {deleteUser();}};// 依赖不填写,默认在组件渲染完成后执行useEffect(() => {const { username, password } = getUser();// 这里如果不小心写成了setFieldValue会报错,差了个s,这个只能输入一个参数,有s的才能输入多个form.setFieldsValue({ username, password });}, []);return (<div className={styled.contain}><div><Space><Title level={2}><UserAddOutlined /></Title><Title level={2}>用户登录</Title></Space></div><div><FormlabelCol={{ span: 6 }}wrapperCol={{ span: 16 }}onFinish={onFinish}// 默认remember设置为trueinitialValues={{ remember: true }}// 将返回值关联起来,即使其变成受控组件form={form}><Form.Itemlabel="用户名"name="username"rules={[{ required: true, message: "请输入用户名" },// string表示按长度计算区间范围,不然变成数字就成最小5最大20了{type: "string",min: 5,max: 20,message: "字符长度在5-20之间",},{pattern: /^\w+$/,message: "只能是字母数字下划线",},]}><Input /></Form.Item><Form.Itemlabel="密码"name="password"rules={[{ required: true, message: "请输入密码" }]}><Input.Password /></Form.Item><Form.Itemname="remember"valuePropName="checked"wrapperCol={{ offset: 6, span: 16 }}>{/* 表单需要有name和value才能提交,valuePropname就是将Checkbox的checked属性,即选中的属性(true || false)当作值 */}<Checkbox>记住我</Checkbox></Form.Item><Form.Item wrapperCol={{ offset: 6, span: 16 }}><Space><Button type="primary" htmlType="submit">登录</Button><Link to={REGISTER_PATHNAME}>注册新用户</Link></Space></Form.Item></Form></div></div>);
};
export default Login;
相关文章:
react-问卷星项目(7)
实战 React表单组件 入门 重点在于change的时候改变state的值,类似vue的双向数据绑定v-model,即数据更新的时候页面同步更新,页面数据更新时数据源也能获得最新的值,只是Vue中设置在data中的属性默认绑定,React中需…...
【git】main|REBASE 2/6
很久没合并代码合并出现冲突,自动进入了 main|REBASE 2/6 的提示: 【git】main|REBASE 2/6 It looks like you’ve encountered several merge conflicts after a git pull operation while a rebase is in progress. Here’s how you can resolve these conflict…...

51单片机的水质检测系统【proteus仿真+程序+报告+原理图+演示视频】
1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块温度传感器ph传感器浑浊度传感器蓝牙继电器LED、按键和蜂鸣器等模块构成。适用于水质监测系统,含检测和调整水温、浑浊度、ph等相似项目。 可实现功能: 1、LCD1602实时显示水温、水体ph和浑浊度 2、温…...
【python面试宝典7】线程池,模块和包
目录标 题目37:解释一下线程池的工作原理。题目38:举例说明什么情况下会出现KeyError、TypeError、ValueError。题目39:说出下面代码的运行结果。题目40:如何读取大文件,例如内存只有4G,如何读取一个大小为…...

Android input系统原理二
1.inputmanager启动源码分析 在SystemServer.java中构造了 inputmanagerservice的对象,在其构造函数中,最重要的是这个nativeInit函数。 下面是核心代码 inputManager new InputManagerService(context);public InputManagerService(Context context)…...

Oracle登录报错-ORA-01017: invalid username/password;logon denied
接上文:Oracle创建用户报错-ORA-65096: invalid common user or role name 我以为 按照上文在PDB里创建了用户,我以为就可以用PLSQL远程连接了,远程服务器上也安装了对应版本的Oracle客户端,但是我想多了,客户只是新建…...

JavaScript 获取浏览器本地数据的4种方式
JavaScript 获取浏览器本地数据的方式 我们在做Web开发中,客户端存储机制对于在浏览器中持久化数据至关重要。这些机制允许开发者存储用户偏好设置、应用状态以及其他关键信息,从而增强用户体验。本文将介绍几种常用的JavaScript获取浏览器本地数据的方…...

77寸OLED透明触摸屏有哪些应用场景
说到77寸OLED透明触摸屏,那可真是市场营销中的一大亮点,应用场景多到数不清!我这就给你细数几个热门的: 商业展示:这可是77寸OLED透明触摸屏的拿手好戏!在高端零售店铺里,它可以作为陈列窗口&am…...
二分解题的奇技淫巧都有哪些,你还不会吗?
先说一下我为什么要写这篇文章。 “二分“ 查找 or ”二分“ 答案的思想大家想必都知道吧(如果不懂,可以看一下我之前写的一篇文章)。 二分求解 可是呢?思想都会,做题的时候,就懵圈了。 这个题竟然考的是…...

LeetCode-871 最低加油次数
重启力扣每日一题系列! 因为过去两个月里掉粉掉的好严重,我想大抵是因为更新的频率不如上半年了,如果我重启了每日一题系列那岂不是至少是每日一更☝🤓? 也不是每天都更,我有两不更,特难的就不…...
OpenCV-OCR
文章目录 一、OCR技术的基本原理二、OpenCV在OCR识别中的应用1.图像预处理2.文字区域检测3.OCR识别:4.后处理: 三、OCR识别示例代码四、注意事项 OpenCV-OCR主要涉及使用OpenCV库进行光学字符识别(OCR)的技术。OCR技术可以识别图像…...
Linux卸载mysql
一、查看当前安装mysql情况,查找以前是否装有mysql rpm -qa|grep -i mysql二、停止MySQL服务 三、删除mysql库和文件 查找MySQL库 # 查找命令 find / -name mysql# 显示结果 /var/lib/mysql/var/lib/mysql/mysql/usr/lib64/mysql删除对应的mysql目录 rm -rf /v…...

【大语言模型-论文精读】用于医疗领域摘要任务的大型语言模型评估综述
【大语言模型-论文精读】用于医疗领域摘要任务的大型语言模型评估综述 论文信息: 用于医疗领域摘要任务的大型语言模型评估:一篇叙述性综述, 文章是由 Emma Croxford , Yanjun Gao 博士 , Nicholas Pellegrino , Karen K. Wong 等人近期合作…...

图吧工具箱
图吧工具箱202309绿色版自动解压程序R2.exe,永久有效 链接:https://pan.baidu.com/s/1M6TI7Git8bXOzZX_qZ3LJw?pwdzked 提取码:zked...
vue2 + View design 使用inputNumber设置默认值为undefined但展示数据为1且表单校验不通过的原因
文章目录 一、背景二、操作步骤1.复现前的准备工作(1)vue版本和view design 版本(2)创建一个组件(组件中根据类型渲染不同的组件)(3)在list.vue页面中引入组件,传入配置&…...

【SpringSecurity】基本流程
【中文文档: Spring Security 中文文档 :: Spring Security Reference】 【英文文档:Spring Security】 以下内容只是记录springsecurity最简单的一种验证流程,所有配置基本都是默认的配置。 引入依赖 <dependency><groupId>org.springf…...
算法-汉诺塔问题(Hanoi tower)
介绍 汉诺塔是源于印度的一个古老传说的小游戏,简单来说就是有三根柱子,开始的时候,第一根柱子上圆盘由大到小,自下往上排列。这个小游戏要实现的目的呢,就是要把第一根柱子上的圆盘移到第三根的柱子上去;…...

HarmonyOS鸿蒙 Next 实现协调布局效果
HarmonyOS鸿蒙 Next 实现协调布局效果 假期愉快! 最近大A 的涨势实在是红的让人晕头转向,不知道各位收益如何,这会是在路上,还是已经到目的地了? 言归正传,最近有些忙,关于鸿蒙的实践系列有些脱节了,…...

【自然语言处理】(1) --语言转换方法
文章目录 语言转换方法一、统计语言模型1. 词向量转换2. 统计模型问题 二、神经语言模型1. 词向量化2. 维度灾难3. 解决维度灾难4. embedding词嵌入5. Word2Vec技术5.1 连续词袋模型(CBOW)5.2 跳字模型(Skip-gram) 总结 语言转换方…...

叉车防撞系统方案,引领安全作业新时代
在现代工业的舞台上,叉车如同忙碌的“搬运工”,在仓储和制造环境中发挥着不可或缺的作用。然而,随着叉车使用频率的不断攀升,安全事故也如影随形,给企业带来经济损失的同时,更严重威胁着操作人员的生命安全…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...

如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...