当前位置: 首页 > news >正文

react ts

一、项目搭建

1、创建项目

  • 使用vite生成项目

npx create-react-app react-ts-project --template typescript
  • 启动项目

yarn start
  • 删除无用组件

2、设计目录结构

资源说明
http网络请求
assets公共资源
components组件
router路由配置
utils工具模块
store状态机
App.tsx应用根组件
index.tsx入口ts文件

3、配置sass环境

  • 安装sass包

yarn add sass
  • 创建全局样式文件

4、craco插件配置

如果要修改CRA的默认配置,有以下几种方案

  • 通过第三方库来修改,比如@craco/craco

  • 通过执行yarn eject命令,释放react-scripts中的所有配置到项目中

实现步骤

  • 安装修改CRA的配置的包

yarn add -D @craco/craco
  • 在项目的根目录中创建craco的配置文件(craco.config.js),并在配置中配置别名

const path=require('path')
module.exports={webpack:{alias:{'@':path.resolve(__dirname,'src')}}
}
  • 修改packge.json中的脚本命令

"scripts": {"start": "craco start","build": "craco build","test": "craco test","eject": "react-scripts eject"}
  • 在代码中,就可以通过@来表示src目录的绝对路径

  • 重启项目,让配置生效

@别名路径提示

  • 在项目根目录创建tsconfig.json配置文件

  • 在配置文件中添加如下配置

{"compilerOptions": {"baseUrl": "./","paths": {"@/*": ["src/*"]}}}

5、配置路由

  • 安装路由

yarn add react-router-dom
yarn add react-loadable
yarn add @types/react-loadable

下载react-loadable依赖包进行路由懒加载,如果你是typescript,你还需要额外安装@types/react-loadable这个依赖包

  • 建立一个loadable.ts,放在src/utils/loadable.ts

import Loadable from 'react-loadable';
export default function withLoadable(comp:any) {return Loadable({//懒加载组件页面loader: comp,loading: () => null})
}
  • 在src下创建router目录,在该目录的index.tsx编写路由配置文件

import loadable from '@/utils/loadable'
import {RouteObject} from 'react-router-dom'
const Login=loadable(()=>import('@/views/Login'))
const Home=loadable(()=>import('@/views/Home'))
const Main=loadable(()=>import('@/views/Main'))
const Product=loadable(()=>import('@/views/Product'))
const Category=loadable(()=>import('@/views/Category'))
const routes:Array<RouteObject>=[{path:'/login',element:<Login/>},{path:'/',element:<Home/>,children:[{index:true,element:<Main></Main>},{path:'product/list',element:<Product></Product>}, {path:'product/category',element:<Category></Category>}]}
]
export default routes
  • 在App.tsx中通过useRoutes钩子函数来进行集中式配置

import React,{Suspense} from 'react'
import {useRoutes} from 'react-router-dom'
import routes from '@/router'
export default function App() {return (<Suspense fallback={<>loading</>}>{useRoutes(routes)}</Suspense>)
}
  • 在项目根目录下的index.tsx中使用<BrowserRouter>包裹<App>

root.render(<BrowserRouter><App/></BrowserRouter>
)
  • 在src/Home.tsx组件中配置二级路由出口

import React from 'react'
import {Outlet} from 'react-router-dom'
export default function Home() {return (<div>Home<Outlet></Outlet></div>)
}

6、安装AntD

  • 安装AntD组件库

yarn add antd

二、用户登录

1、登录静态页面实现

  • 首先在utils目录下创建type.ts文件,这个文件里主要编写接口

export interface IUser{account:string,password:string}
  • 在views目录下的Login.tsx文件中编写登录的静态页面

import {Button,Form,Input,message} from 'antd'
import api from '@/api'
import {useNavigate} from 'react-router-dom'export default ()=>{const nav=useNavigate()const onFinish=async(values:any)=>{console.log(values)}return (<Form onFinish={onFinish} style={{ maxWidth: 600 }}><Form.Item label='用户名' name="username"><Input/></Form.Item><Form.Item label='密码' name="password"><Input.Password/></Form.Item><Form.Item><Button type="primary" htmlType='submit'>登录</Button></Form.Item></Form>)
}

2、axios的二次封装

import axios,{ InternalAxiosRequestConfig,AxiosResponse,AxiosError} from "axios";
import {message} from 'antd'
//设置根路径
axios.defaults.baseURL="http://www.zhaijizhe.cn:3005"
//设置请求拦截器
axios.interceptors.request.use((config: InternalAxiosRequestConfig)=>{const token=localStorage.getItem('token')if(token){config.headers.Authorization=token}return config
})
//设置响应拦截器
axios.interceptors.response.use((response:AxiosResponse)=>{return response.data
},(error:AxiosError)=>{switch(error.response?.status){case 500:message.error('服务端出现500错误')breakcase 401:message.error('服务端出现400错误')break;case 404:message.error("没有找到服务端相应资源");break;}return Promise.reject(error)
})
export default axios

3、登录功能的实现

  • 在src/types文件夹下编写接口

export default interface IUser{username:stringpassword:string
}
  • 编写登录的后端请求API

import request from '@/utils/request'
import IUser from '@/types/IUser'export default{login:(user:IUser)=>request.post('/users/login',user)
}
  • 将用户模块汇总到api.tsx中

import users from "./modules/users"
export default{users
}
  • 在登录组件中调用登录API,完成登录功能

import {Button,Form,Input,message} from 'antd'
import api from '@/api'
import {useNavigate} from 'react-router-dom'export default ()=>{const nav=useNavigate()const onFinish=async(values:any)=>{const result=await api.users.login(values)if(result.data.code){localStorage.setItem('token',result.data.token)nav('/')}else{message.warning('登录失败')}}return (<Form onFinish={onFinish} style={{ maxWidth: 600 }}><Form.Item label='用户名' name="username"><Input/></Form.Item><Form.Item label='密码' name="password"><Input.Password/></Form.Item><Form.Item><Button type="primary" htmlType='submit'>登录</Button></Form.Item></Form>)
}

三、路由权限

1、静态菜单

import {Outlet,NavLink,useNavigate} from 'react-router-dom'
import React,{useState,useEffect} from 'react'
import '@/assets/css/home.scss'
import {Layout,Menu} from 'antd'
import {WindowsOutlined,TrademarkCircleOutlined,UserOutlined} from '@ant-design/icons'
const {Header,Sider,Content,Footer}=Layout
export default ()=>{const[menuList,setMenuList]=useState<any>([])const nav=useNavigate()useEffect(()=>{const list=[{key:'sub1',label:'日常业务',icon:<WindowsOutlined />,children:[{label:'学员管理',key:'/students'},{label:'班级管理',key:'/classes'}]},{key:'sub2',label:'校区管理',icon:<TrademarkCircleOutlined />,children:[{label:'教师管理',key:'/teachers'},{label:'班主任管理',key:'/directors'},{label:'专业管理',key:'/subjects'}]},{key:'sub3',label:'系统管理',icon:<UserOutlined />,children:[{key:'/users',label:'用户管理'}]}]setMenuList(list)},[])const go=(item:any)=>{nav(item.key)}return (<><Layout><Header><div>蜗牛BOSS管理系统</div></Header>  <Layout style={{height:'750px'}}><Sider><Menu items={menuList} onClick={go}mode="inline"theme="dark"defaultOpenKeys={['sub1','sub2']}defaultSelectedKeys={['/home/students']}></Menu></Sider><Content>{/* 设置子路由出口 */}<Outlet></Outlet></Content></Layout><Footer style={{ textAlign: 'center'}}>Ant Design ©2023 Created by Ant UED</Footer></Layout> </>)
}

2、动态菜单

  • 在api/modules/users下编写获取权限菜单的接口

import request from '@/utils/request'
export default{getAuthMenus:()=>request.get('/menus/getAuthMenus')
}
  • 在Home.tsx中中调用getAuthMenus接口来完成权限菜单数据的获取

 useEffect(() => {getAuthMenus()}, [])const getAuthMenus = async () => {const result = await api.users.getAuthMenus()console.log(result.data.data)const rList = transformDataToMenus(result.data.data)setMenuList(rList)}
  • 将后台的权限菜单数据转成antd格式的菜单数据

/*** 将后台的权限菜单数据转成antd格式的菜单数据*/interface IMenuData {title: stringpath: stringicon: stringchildren?: Array<IMenuData>}interface IMenu {label: stringkey: stringicon: ReactElementchildren?: Array<IMenu>}const transformDataToMenus = (list: Array<IMenuData>) => {return list.map((item: IMenuData) => {let name = item.icon as stringlet iis: any = icons[name as keyof typeof icons]let menuItem: IMenu = { label: item.title, key: item.path, icon: React.createElement(iis) }if (item.children) {menuItem.children = transformDataToMenus(item.children)}return menuItem})}
  • 渲染导航列表

<Menuitems={menuList}mode="inline"theme="dark"onClick={goNav}></Menu>

3、动态添加路由表

1、安装和配置RTX

在终端执行

yarn add redux
yarn add react-redux
yarn add @reduxjs/toolkit

在src目录下创建store文件夹,目录结构如下

src|-store|-moudles|-xx.tsx|-yy.tsx|-index
2、创建slice模块

在src/store/reducers目录下创建routeReducer.tsx

import {createSlice,PayloadAction,Dispatch} from '@reduxjs/toolkit'
import {RouteObject} from 'react-router-dom'
import api from '@/api'
import {withLoadable} from '@/utils/loadable'
interface IAuthMenu{rows:Array<any>
}
const initialState:IAuthMenu={rows:[]
}
export const routesSlice=createSlice({name:'getAuthMenu',initialState,reducers:{setAuthRoutes(state,{payload}:PayloadAction<any[]>){state.rows=payload}}
})
export const getAuthRoutesAsync=(routes:any)=>{return async(dispath:Dispatch)=>{console.log('----网络请求-----------');let result=await api.users.getAuthMenus()console.log('aaaa',result.data.data)result.data.data.forEach((item:RouteObject)=>{if(item.children){item.children.forEach((subItem:RouteObject)=>{console.log('ss',subItem)const Module=withLoadable(()=>import(`@/views${subItem.path}`))routes[1].children.push({path:subItem.path,element:<Module/>})})}})dispath(setAuthRoutes(routes))}
}
export const {setAuthRoutes}=routesSlice.actions
export default routesSlice.reducer
3、创建store对象
import {configureStore} from '@reduxjs/toolkit'import menuReducer from './reducers/menus'
const store=configureStore({reducer:{menuReducer}
})
export default store
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
4、创建hooks文件
​
在src/store目录下新建hooks文件import { useDispatch, useSelector } from 'react-redux'
import type { TypedUseSelectorHook } from 'react-redux'
import type { RootState, AppDispatch } from './index'// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
Usage With TypeScript | Redux 中文官网​
5、全局注册store
import ReactDOM from 'react-dom/client';
import App from '@/App'
import {BrowserRouter} from 'react-router-dom'
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement
);
root.render(<BrowserRouter><App /></BrowserRouter>
);
6、在组件中使用
import { Outlet, NavLink } from 'react-router-dom'
import '@/assets/css/home.scss'
import { Layout,Menu } from 'antd'
import React,{ useEffect, useState } from 'react'
import {WindowsOutlined,TrademarkCircleOutlined,UserOutlined} from '@ant-design/icons'
//导入api
import api from '@/api'
//导入接口
import IMenuData from '@/types/IMenuData'
import IMenu from '@/types/IMenu'
import IMenuFun from '@/types/IMenuFun'
//导入图标
import * as icons from '@ant-design/icons'
//导入useSelector和useDispatch
// import {useSelector,useDispatch} from 'react-redux'
//使用ts的话,hooks使用的是useAppSelector来代替useSelector,使用useAppDispatch来替换useDispatch
import {useAppSelector,useAppDispatch} from '@/store/hooks'
//导入通知对象
import {getRoutesAsync} from '@/store/modules/routesReducer'
//导入routes
import routes from '@/router'import {useNavigate} from 'react-router-dom'const { Header, Sider, Content, Footer } = Layout
export default () => {const[menuList,setMenuList]=useState<Array<any>>([])useEffect(()=>{getAuthMenus()},[])const dispatch=useAppDispatch()const nav=useNavigate()/*** 通过token向后端服务端获取权限数据*/const getAuthMenus=async()=>{const result=await api.users.getAuthMenus()//进行转换const list:Array<IMenu>=transformDataToMenu(result.data.data)setMenuList(list)//向状态机发送通知操作路由表,关键代码dispatch(getRoutesAsync(routes))}//代码略const transformDataToMenu:IMenuFun=(list:Array<IMenuData>)=>{}//进行路由跳转的方法const go=(values:any)=>{nav(values.key)}return (<Layout><Header style={{ color: '#fff' }}>蜗牛BOSS系统</Header><Layout style={{ height: '750px' }}><Sider><MenuonClick={go}items={menuList}theme="dark"mode="inline"></Menu></Sider><Content><Outlet></Outlet></Content></Layout><Footer>&copy;版权前端10期班所有</Footer></Layout>)
}
7、App.tsx
import {useRoutes} from 'react-router-dom'
import routes from '@/router'
import {useAppSelector} from '@/store/hooks'
import {useEffect,useState} from 'react'
export default ()=>{const rows=useAppSelector((state)=>{return state.routesReducer.rows})const[rout,setRout]=useState(routes)useEffect(()=>{console.log('********')console.log('rows',rows)setRout(rows)},[rows])return (<>{useRoutes(rows.length==0?routes:rout)}</>)
}

相关文章:

react ts

一、项目搭建 1、创建项目 使用vite生成项目 npx create-react-app react-ts-project --template typescript 启动项目 yarn start 删除无用组件 2、设计目录结构 资源说明http网络请求assets公共资源components组件router路由配置utils工具模块store状态机App.tsx应用…...

配置MySQL

配置MySQL_5.7.16 一级目录2.1.1 安装包准备2.1.2 安装MySQL2.1.3 配置MySQL 一级目录 2.1.1 安装包准备 1&#xff09;将安装包和JDBC驱动上传到/opt/software&#xff0c;共计6个 01_mysql-community-common-5.7.16-1.el7.x86_64.rpm 02_mysql-community-libs-5.7.16-1.el…...

GFPGAN 集成Flask 接口化改造

GFPGAN是一款腾讯开源的人脸高清修复模型&#xff0c;基于github上提供的demo&#xff0c;可以简单的集成Flask以实现功能接口化。 GFPGAN的安装&#xff0c;Flask的安装请参见其他文章。 如若使用POSTMAN进行测试&#xff0c;需使用POST方式&#xff0c;form-data的请求体&am…...

vue数字输入框

目录 1.emitter.JS function broadcast (componentName, eventName, params) {this.$children.forEach(child > {var name child.$options.componentNameif (name componentName) {child.$emit.apply(child, [eventName].concat(params))} else {broadcast.apply(child, …...

JavaScript—BOM

BOM是什么&#xff1f; Browser Object Model是浏览器对象模型 官方&#xff1a;浏览器对象模型提供了独立于内容的、可以与浏览器窗口进行互动的对象结构&#xff0c;BOM由多个对象构成&#xff0c;其中代表浏览器窗口的window对象是BOM的顶层对象&#xff0c;其他对象都是该…...

C# SocketException(0x2746) asp.net一个现有的连接被远程主机强行关闭

问题原因 如果网页能正常访问&#xff0c;那就是TLS版本支持的问题。 我遇到的问题是&#xff1a; 项目用的是NET Framework 4.6.1&#xff0c;但是 learn.microsoft.com 提到 NET Framework 4.6及更早版本 不支持 TLS 1.1 和 TLS 1.2。 NET Framework 4.6.2 及更高版本 支持 …...

博客系统后端(项目系列2)

目录 前言 &#xff1a; 1.准备工作 1.1创建项目 1.2引入依赖 1.3创建必要的目录 2.数据库设计 2.1博客数据 2.2用户数据 3.封装数据库 3.1封装数据库的连接操作 3.2创建两个表对应的实体类 3.3封装一些必要的增删改查操作 4.前后端交互逻辑的实现 4.1博客列表页 …...

随机化快速排序(Java 实例代码)

随机化快速排序 一、概念及其介绍 快速排序由 C. A. R. Hoare 在 1960 年提出。 随机化快速排序基本思想&#xff1a;通过一趟排序将要排序的数据分割成独立的两部分&#xff0c;其中一部分的所有数据都比另外一部分的所有数据都要小&#xff0c;然后再按此方法对这两部分数…...

JVM 垃圾收集

垃圾收集 分代理论Java 堆的内存分区不同分代收集垃圾收集算法 分代理论 弱分代假说&#xff1a;绝大多数对象都是朝生夕灭&#xff0c;即绝大多数对象都是用完很快需要销毁的。强分代假说&#xff1a;熬过多次垃圾收集过程的对象就越难以消亡&#xff0c;即如果对象经过多次垃…...

kubesphere中部署grafana实现dashboard以PDF方式导出

1&#xff0c;部署grafana-image-renderer 2&#xff0c;部署grafana GF_RENDERING_SERVER_URL http://ip:30323/render #grafana-image-renderer地址 GF_RENDERING_CALLBACK_URL http://ip:32403/ #grafana地址 GF_LOG_FILTERS rend…...

【环境配置】Android-Studio-OpenCV-JNI以及常见错误 ( 持续更新 )

最近一个项目要编译深度学习的库&#xff0c;需要用到 opencv 和 JNI&#xff0c;本文档用于记录环境配置中遇到的常见错误以及解决方案 Invalid Gradle JDK configuration found failed Invalid Gradle JDK configuration foundInvalid Gradle JDK configuration found. Open…...

js 正则表达式 验证 :页面中一个输入框,可输入1个或多个vid/pid,使用英文逗号隔开...

就是意思一个输入框里面&#xff0c;按VID/PID格式输入,VID和PID最大长度是4,最多50组 1、页面代码 <el-form ref"ruleForm" :model"tempSet" :rules"rules" label-position"right"> <!-- 最多 50组&#xff0c;每组9个字符…...

【算法与数据结构】112、LeetCode路径总和

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题通过计算根节点到叶子节点路径上节点的值之和&#xff0c;然后再对比目标值。利用文章【算法和数据…...

②matlab桌面和编辑器

目录 matlab编辑器练习 运行脚本 matlab编辑器练习 您可以通过点击灰色代码框在脚本中输入命令。 准备就绪后&#xff0c;您可以通过点击蓝色的提交按钮提交代码。 任务 在脚本中输入命令 r 3。 2.任务 在脚本中添加命令 x pi*r^2。 附加练习 当您在实时编辑器中完成…...

高亮img、pdf重点部分(html2canvas、pdfjs-dist、react-pdf)

可用业务场景 报销单据审批中&#xff0c;高亮发票部分 需求 后台返回一张图片或者pdf、返回一组坐标&#xff0c;坐标类型[number,number,number,number]&#xff0c;分别代表了x、y、width、height。需要根据坐标在图片上高亮出来坐标位置。如下图 高亮的坐标是&#xff1…...

18.神奇导航菜单指示器

效果 源码 <!DOCTYPE html> <html> <head> <title>Magic Menu Indicator | 03</title> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body><div class="navig…...

WPF+Prism+WebApi 学习总结

一、基本概念 WPF:WPF&#xff08;Windows Presentation Foundation&#xff09;是&#xff08;微软推出的&#xff09;基于Windows的用户界面框架&#xff0c;提供了统一的编程模型&#xff0c;语言和框架&#xff0c;做到了分离界面设计人员与开发人员的工作&#xff1b;WPF…...

uniapp热更新

首先热更新需要wgt包&#xff1b; 其次先了解这两个组件 下载的方法 安装的组件 场景&#xff1a; 当你项目的js文件或者页面文件或者静态图片文件css文件更新的时候可以走热更新&#xff1b; 而当你安装新的组件插件或者开启新的权限等功能的时候就无法通过热更新进行更新了…...

AUTOSAR从入门到精通-【应用篇】基于CAN协议的汽车尾气后处理诊断系统的软件开发(续)

目录 尾气后处理诊断程序的开发 5.1 数据库的解析 5.1.1 寻找XML文件 5.1.2 读取XML文件...

mybatis plus新版代码生成器,类型转换处理器ITypeConvertHandler使用

目录 引言关键代码源码分析记录一坑类型转换的第二种方式完整源码地址 引言 当默认生成的数据类型不满足时&#xff0c;就需要自定义指定要生成的类型 关键代码 FastAutoGenerator.create(url, username, password).dataSourceConfig(builder -> {builder.typeConvertHandl…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

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

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...