• 基于react18+arco+zustand通用后台管理系统React18Admin


    React-Arco-Admin轻量级后台管理系统解决方案

    基于vite4构建react18后台项目ReactAdmin。使用了react+arco-design+zustand+bizcharts技术架构非凡后台管理框架。支持 dark/light主题、i18n国际化、动态路由鉴权、3种经典布局、tabs路由标签 等功能。

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    技术框架

    • 编辑器:Vscode
    • 使用技术:react18+vite4+react-router+zustand+axios
    • 组件库:arco-design (字节前端react组件库)
    • 路由管理:react-router-dom^6.16.0
    • 状态管理:zustand^4.4.1
    • 模拟数据:mockjs^1.1.0 + axios^1.5.1
    • 图表库:bizcharts^4.1.22
    • 编辑器组件:@wangeditor/editor-for-react^1.0.6
    • markdown组件:@uiw/react-md-editor^3.23.6
    • 请求进度插件:nprogress^0.2.0

    在这里插入图片描述
    在这里插入图片描述

    特点

    • 基于vite4.x搭建react18后台系统
    • 使用最新前端技术栈react18、zustand、bizcharts、react-router
    • 搭配字节react组件库arco.design
    • 支持中英文/繁体国际化
    • 支持动态路由权限验证
    • 支持动态tabs标签栏菜单
    • 内置多种通用模板布局

    在这里插入图片描述
    在这里插入图片描述

    项目结构

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    App.jsx模板

    引入语言包,配置权限路由。

    /**
     * 入口模板
     * @author Hs
    */
    
    import { useEffect, useMemo } from 'react'
    import { HashRouter } from 'react-router-dom'
    // 通过 ConfigProvider 组件实现国际化
    import { ConfigProvider } from '@arco-design/web-react'
    // 引入语言包
    import enUS from '@arco-design/web-react/es/locale/en-US'
    import zhCN from '@arco-design/web-react/es/locale/zh-CN'
    import zhTW from '@arco-design/web-react/es/locale/zh-TW'
    
    import { AuthRouter } from '@/hooks/useRoutes'
    import { appStore } from '@/store/app'
    
    // 引入路由配置
    import Router from './routers'
    
    function App() {
    	const { lang, config: { mode, theme }, setMode, setTheme } = appStore()
    
    	const locale = useMemo(() => {
    		switch(lang) {
    			case 'en':
    				return enUS
    			case 'zh-CN':
    				return zhCN
    			case 'zh-TW':
    				return zhTW
    			default:
    				return zhCN
    		}
    	}, [lang])
    
    	useEffect(() => {
    		setMode(mode)
    		setTheme(theme)
    	}, [])
    
    	return (
    		<ConfigProvider locale={locale}>
    			<HashRouter>
    				<AuthRouter>
    					<Router />
    				</AuthRouter>
    			</HashRouter>
    		</ConfigProvider>
    	)
    }
    
    export default App
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    react-admin通用布局模板

    在这里插入图片描述

    支持分栏+垂直+水平布局样式。

    在这里插入图片描述

    /**
     * 主布局模板
     * @author Hs Q:282310962
    */
    
    import { useMemo } from 'react'
    import { appStore } from '@/store/app'
    
    import Columns from './template/columns'
    import Vertical from './template/vertical'
    import Transverse from './template/transverse'
    
    function Layout() {
        const { config: { skin, layout } } = appStore()
    
        // 布局模板
        const LayoutComponent = useMemo(() => {
            switch(layout) {
                case 'columns':
                    return Columns
                case 'vertical':
                    return Vertical
                case 'transverse':
                    return Transverse
                default:
                    return Columns
            }
        }, [layout])
        
        return (
            <div className="radmin__container">
                <LayoutComponent />
            </div>
        )
    }
    
    export default Layout
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    react-router-dom路由管理

    在这里插入图片描述

    /**
     * @title    react-router-dom v6路由配置管理
     * @author    andy
    */
    
    import { useRoutes, Navigate } from 'react-router-dom'
    
    import Error from '@views/error/404'
    
    // 批量导入modules路由
    const modules = import.meta.glob('./modules/*.jsx', { eager: true })
    const patchRoutes = Object.keys(modules).map(key => modules[key].default).flat()
    
    // useRoutes集中式路由配置
    export const routes = [
        {
            path: '/',
            element: <Navigate to="/home" replace={true} />,
            meta: {
                isWhite: true // 路由白名单
            }
        },
        ...patchRoutes,
        // 404模块 path="*"不能省略
        {
            path: '*',
            element: <Error />,
            meta: {
                isWhite: true
            }
        }
    ]
    
    const Router = () => useRoutes(routes)
    
    export default Router
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    lazyload.jsx懒加载

    import { Suspense } from 'react'
    import { Spin } from '@arco-design/web-react'
    import NprogressLoading from './nprogress'
    
    // 加载提示
    const SpinLoading = () => {
        return (
            <Spin
                tip='loading...'
                style={{
                    width: '100%'
                }}
            />
        )
    }
    
    // 延迟加载
    const lazyload = LazyComponent => {
        // React 16.6 新增了组件,懒加载的模式需要我们给他加上一层 Loading的提示加载组件
        // return }>
        return <Suspense fallback={<NprogressLoading />}><LazyComponent /></Suspense>
    }
    
    export default lazyload
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    nprogress.jsx加载进度条

    import { Component } from 'react'
    import NProgress from 'nprogress'
    import 'nprogress/nprogress.css'
    
    export default class NprogressLoading extends Component {
        constructor(props) {
            super(props)
            NProgress.set(.4)
            NProgress.start()
        }
    
        componentDidMount() {
            NProgress.done()
        }
    
        render() {
            return <div />
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    /**
     * 主路由配置
     * @author Hs
    */
    
    import { lazy } from 'react'
    import {
        IconHome, IconDashboard, IconLink, IconCommand, IconUserGroup, IconLock,
        IconMenu, IconSafe, IconBug, IconHighlight, IconUnorderedList, IconStop
    } from '@arco-design/web-react/icon'
    import Layout from '@/layouts'
    import Blank from '@/layouts/blank'
    import lazyload from '../lazyload'
    
    export default [
        /*首页模块*/
        {
            path: '/home',
            key: '/home', // 用于Menu组件跳转路由地址
            element: <Layout />,
            meta: {
                // icon: 've-icon-home', // 菜单图标
                icon: <IconHome />,
                name: 'layout__main-menu__home', // i18n国际化标题
                title: '主页',
                isAuth: true, // 需要鉴权
                isHidden: false, // 是否隐藏菜单
                isAffix: true // 固定tabview标签栏(不可关闭)
            },
            children: [
                {
                    key: '/home',
                    index: true,
                    element: lazyload(lazy(() => import('@views/home'))),
                    meta: {
                        // icon: 've-icon-home',
                        icon: <IconHome />,
                        name: 'layout__main-menu__home-index',
                        title: '首页',
                        isAuth: true
                    }
                },
                // 工作台
                {
                    path: 'dashboard',
                    key: '/home/dashboard',
                    element: lazyload(lazy(() => import('@views/home/dashboard'))),
                    meta: {
                        // icon: 've-icon-computer',
                        icon: <IconDashboard />,
                        name: 'layout__main-menu__home-workplace',
                        title: '工作台',
                        isAuth: true
                    }
                },
                // 外部链接
                {
                    path: 'https://react.dev/',
                    key: 'https://react.dev/',
                    meta: {
                        // icon: 've-icon-clip',
                        icon: <IconLink />,
                        name: 'layout__main-menu__home-apidocs',
                        title: 'react.js官方文档',
                        rootRoute: '/home'
                    }
                }
            ]
        },
    
        /*组件模块*/
        {
            ...
        },
    
        /*用户管理模块*/
        {
            ...
        },
    
        /*权限模块*/
        {
            ...
        },
    
        /*错误模块*/
        {
            ...
        }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    路由配置参数:

    /**
     * @description 路由参数说明
     * @param path ==> 路由地址标识
     * @param key ==> 用于Menu组件跳转路由地址
     * @param redirect ==> 重定向地址
     * @param element ==> 视图页面路径
     * 菜单信息(meta)
     *         @param meta.icon ==> 菜单图标
     *         @param meta.title ==> 菜单标题
     *         @param meta.name ==> i18n国际化标题
     *         @param meta.roles ==> 页面权限 ['admin', 'dev', 'test']
     *         @param meta.isAuth ==> 是否需要验证
     *         @param meta.isHidden ==> 是否隐藏页面
     *         @param meta.isAffix ==> 是否固定标签(tabs标签栏不能关闭)
     * */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    react18路由菜单RouterMenu

    在这里插入图片描述
    如上图:react-admin提供了三种不同menu风格样式。

    <RouteMenu rootRouteEnable={false} />
    
    <RouteMenu rootRouteEnable />
    
    <RouteMenu rootRouteEnable mode="horizontal" />
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Menu.jsx路由模板

    /**
     * 路由菜单模板
    */
    
    import './index.scss'
    import { useState, useMemo, useEffect } from 'react'
    import { useNavigate, useLocation } from 'react-router-dom'
    import { Menu } from '@arco-design/web-react'
    import Icon from '@components/Icon'
    import RouteSubMenu from './submenu'
    import { routes } from '@/routers'
    import { getCurrentRootRoute, findParentRoute } from '@/hooks/useRoutes'
    import Locales from '@/locales'
    
    export default function RouteMenu(props) {
        const {
            // 菜单类型(垂直vertical 水平菜单horizontal 弹出pop)
            mode = 'vertical',
            // 菜单风格('light' | 'dark')
            theme = 'light',
            // 是否开启一级路由菜单
            rootRouteEnable = false,
    
            style = {}
        } = props
    
        const navigate = useNavigate()
        const { pathname } = useLocation()
        const t = Locales()
        const [openKeys, setOpenKeys] = useState([])
        const rootRoute = getCurrentRootRoute()
        const filterRoutes = routes.filter(item => !item?.meta?.isWhite)
    
        const menuRoutes = useMemo(() => {
            if(rootRouteEnable) {
                return filterRoutes
            }
            // 过滤一级菜单
            return filterRoutes.find(item => item.path == rootRoute && item.children)?.children
        }, [pathname])
    
        useEffect(() => {
            setOpenKeys(getKeys(pathname))
        }, [pathname])
    
        // 获取选中菜单路由keys数组
        const getKeys = (key) => {
            return findParentRoute(menuRoutes, key)?.map(item => item?.key)
        }
    
        const handleNavigate = (key) => {
            const reg = /[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?/
            if(reg.test(key)) {
                window.open(key)
            }else {
                navigate(key)
            }
        }
    
        return (
            <Menu
                className="ra__menus"
                mode={mode}
                theme={theme}
                selectedKeys={[pathname]}
                openKeys={openKeys}
                levelIndent={28}
                style={{ ...style }}
                onClickMenuItem={handleNavigate}
                onClickSubMenu={(_, openKeys) => {
                    setOpenKeys(openKeys)
                }}
            >
                { menuRoutes.map(item => {
                    if(item?.children) {
                        return RouteSubMenu(item, t)
                    }
                    return (
                        !item?.meta?.isHidden &&
                        <Menu.Item className="ra__menuItem" key={item.redirect || item.key}>
                            { item?.meta?.icon && <Icon name={item.meta.icon} size={18} style={{marginRight: 10}} /> }
                            { item?.meta?.name && <span>{t[item.meta.name]}</span> }
                        </Menu.Item>
                    )
                })}
            </Menu>
        )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    Zustand:基于react新状态管理库

    在这里插入图片描述

    /**
     * react18状态管理库Zustand4,中间件persist本地持久化存储
    */
    import { create } from 'zustand'
    import { persist, createJSONStorage } from 'zustand/middleware'
    import { generate, getRgbStr } from '@arco-design/color'
    
    export const appStore = create(
        persist(
            (set, get) => ({
                // 语言(中文zh-CN 英文en 繁体字zh-TW)
                lang: 'zh-CN',
                // 角色类型 roles: ['admin'] / roles: ['admin', 'dev'] / roles: ['dev', test']
                roles: ["dev"],
                // 配置信息
                config: {
                    // 布局(分栏columns 纵向vertical 横向transverse)
                    layout: 'columns',
                    // 模式(亮色light - 暗黑dark)
                    mode: 'light',
                    // 主题色
                    theme: '#3491FA',
                    // 是否折叠菜单
                    collapsed: false,
                    // 开启面包屑导航
                    breadcrumb: true,
                    // 开启标签栏
                    tabsview: true,
                    tabRoutes: [],
                    // 显示搜索
                    showSearch: true,
                    // 显示全屏
                    showFullscreen: true,
                    // 显示语言
                    showLang: true,
                    // 显示公告
                    showNotice: true,
                    // 显示底部
                    showFooter: false
                },
                
                // 更新配置
                updateConfig: (key, value) => set({
                    config: { ...get().config, [key]: value }
                }),
                // 设置角色
                setRoles: (roles) => set({roles}),
                // 设置多语言
                setLang: (lang) => set({lang}),
                // 设置主题模式
                setMode: (mode) => {
                    if(mode == 'dark') {
                        // 设置为暗黑主题
                        document.body.setAttribute('arco-theme', 'dark')
                    }else {
                        // 恢复亮色主题
                        document.body.removeAttribute('arco-theme')
                    }
                    get().updateConfig('mode', mode)
                },
                // 设置主题样式
                setTheme: (theme) => {
                    const colors = generate(theme, { list: true })
                    colors.map((item, index) => {
                        const rgbStr = getRgbStr(item)
                        document.body.style.setProperty(`--arcoblue-${index + 1}`, rgbStr)
                    })
                    get().updateConfig('theme', theme)
                }
            }),
            {
                name: 'appState',
                // name: 'app-store', // name of the item in the storage (must be unique)
                // storage: createJSONStorage(() => sessionStorage), // by default, 'localStorage'
            }
        )
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    react多语言配置i18n

    在这里插入图片描述

    在这里插入图片描述

    /**
     * 国际化配置
     * @author YXY
     */
    
    import { appStore } from '@/store/app'
    
    // 引入语言配置
    import enUS from './en-US'
    import zhCN from './zh-CN'
    import zhTW from './zh-TW'
    
    export const locales = {
        'en': enUS,
        'zh-CN': zhCN,
        'zh-TW': zhTW
    }
    
    export default (locale) => {
        const appState = appStore()
        const lang = appState.lang || 'zh-CN'
    
        return (locale || locales)[lang] || {}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    lang.jsx语言配置

    import { Dropdown, Menu, Button } from '@arco-design/web-react'
    import Icon from '@components/Icon'
    import { appStore } from '@/store/app'
    
    export default function Lang() {
        const { lang, setLang } = appStore()
    
        const handleLang = val => {
            setLang(val)
        }
    
        return (
            <Dropdown
                position="bottom"
                droplist={
                    <Menu className="radmin__dropdownLang" defaultSelectedKeys={[lang]} onClickMenuItem={handleLang}>
                        <Menu.Item key='zh-CN'>简体中文 <span>zh-CN</span></Menu.Item>
                        <Menu.Item key="zh-TW">繁体字 <span>zh-TW</span></Menu.Item>
                        <Menu.Item key="en">英文 <span>en</span></Menu.Item>
                    </Menu>
                }
            >
                <Button
                    shape="circle"
                    size="small"
                    icon={<Icon name="ve-icon-lang" />}
                />
            </Dropdown>
        )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    Tabs路由菜单栏

    在这里插入图片描述

    <Tabs
        activeTab={pathname}
        editable
        showAddButton={false}
        onDeleteTab={key => delTabs(key)}
    >
        { tabRoutes.map(item => (
            <Tabs.TabPane
                closable={!item?.meta?.isAffix}
                key={item?.redirect || item?.key}
                title={
                    <Dropdown
                        trigger='contextMenu'
                        position='bl'
                        droplist={
                            <Menu className="ra__dropdownContext" onClickMenuItem={(key, e) => handleClickMenuItem(key, e, item)}>
                                <Menu.Item key="close" disabled={item?.meta?.isAffix}><Icon name="ve-icon-close" />{t['tabview__contextmenu-close']}</Menu.Item>
                                <Menu.Item key="closeLeft" disabled={isFirstTab()}><Icon name="ve-icon-prev" />{t['tabview__contextmenu-closeleft']}</Menu.Item>
                                <Menu.Item key="closeRight" disabled={isLastTab()}><Icon name="ve-icon-next" />{t['tabview__contextmenu-closeright']}</Menu.Item>
                                <Menu.Item key="closeOther"><Icon name="ve-icon-reset" />{t['tabview__contextmenu-closeother']}</Menu.Item>
                                <Menu.Item key="closeAll"><Icon name="ve-icon-close-circle-o" />{t['tabview__contextmenu-closeall']}</Menu.Item>
                            </Menu>
                        }
                        onVisibleChange={visible=>handleOpenContextMenu(visible, item)}
                    >
                        <span className="ra__tabsview-title" onClick={() => navigate(item?.redirect || item?.key)}>
                            <TabIcon path={item?.key} />
                            { t[item?.meta?.name] }
                        </span>
                    </Dropdown>
                }
            />
        ))}
    </Tabs>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    好了,以上就是react18+vite4+arco构建后台系统模板的一些分享了。

    webchat-react基于react18+arco网页版聊天实例

    electron-chatgpt基于electron25+vite4仿制ChatGPT模板

    在这里插入图片描述

  • 相关阅读:
    远程连接服务器及可视化方法(Win和Linux)
    uniapp怎么进行页面的跳转
    独热编码和自然数编码
    实现日期间的运算——C++
    第三站:函数(第一幕)
    SpringBoot 入门 参数接收 必传参数 数组 集合 时间接收
    mysql数据库之必备知识
    (33)STM32——485实验笔记
    十二、bootstrap前端开发框架
    Docker 的数据管理与网络通信以及Docker镜像的创建
  • 原文地址:https://blog.csdn.net/yanxinyun1990/article/details/133880077