基于Vue 3与Vite的现代化中后台前端解决方案:fast-soy-admin深度解析

news2026/5/10 3:34:31
1. 项目概述一个为现代Web应用提速的“脚手架”最近在折腾一个内部管理系统的重构前端技术栈选型时一个绕不开的话题就是“脚手架”。对于有一定规模的团队来说从零开始配置Webpack、Vite、集成路由、状态管理、UI库、权限、Mock……这套流程下来少说也得花上几天时间而且每次新项目都得重复一遍效率低下不说还容易因为配置差异导致后期维护成本剧增。正是在这种背景下我注意到了GitHub上一个名为“fast-soy-admin”的开源项目。这个项目标题直译过来是“快速大豆管理后台”听起来有点趣味性但它的核心定位非常明确一个基于Vue 3 Vite TypeScript的现代化、开箱即用的中后台前端解决方案旨在像“速溶豆浆粉”一样让开发者能快速“冲泡”出一个功能完备、性能优异的管理后台基础框架。“Soy”大豆在这里更像一个有趣的代号寓意着“基础营养”和“快速成型”。这个项目并非要解决某个具体的业务逻辑而是专注于解决前端工程化和开发体验的痛点。它集成了当前Vue生态中最主流、最前沿的技术栈并预设了中后台系统常见的功能模块如布局、路由、权限、状态管理、组件库、工具函数等。开发者克隆项目后无需进行繁琐的基础配置可以直接进入业务开发阶段从而将精力聚焦于产品逻辑本身极大地提升了开发效率和项目的可维护性。它适合谁呢首先是那些需要快速搭建企业内部管理系统、运营后台、数据看板的中小型团队或个人开发者。其次对于希望学习现代Vue 3全家桶最佳实践、了解一个成熟前端项目如何组织代码和工程配置的初中级开发者来说这是一个非常好的学习和参考案例。最后对于有自己技术栈偏好但需要一个高质量起点进行二次定制和扩展的资深开发者它也是一个优秀的“地基”。2. 技术栈深度解析为什么是这套组合拳一个优秀的脚手架其价值很大程度上取决于其技术选型的先进性与合理性。fast-soy-admin的选型清晰地反映了当前Vue生态的前沿趋势和工程化最佳实践。我们来逐一拆解其核心依赖背后的设计逻辑。2.1 构建基石Vite 与 Vue 3项目摒弃了传统的Webpack选择了Vite作为构建工具。这并非简单的跟风而是基于深刻的性能考量。对于中后台项目虽然最终打包体积很重要但开发阶段的热更新HMR速度直接决定了开发者的幸福指数。Webpack基于打包器Bundler的工作方式在项目规模增长时启动和热更新会越来越慢。Vite则利用了现代浏览器原生支持ES模块的特性在开发环境下采用“按需编译”的策略。当你启动一个Vite项目时它并不会先打包整个应用而是启动一个服务器当浏览器请求某个模块时Vite再对该模块进行实时编译并返回。这意味着无论项目多大启动速度都几乎是瞬间完成的热更新也仅需更新变动的模块速度极快。注意Vite在生产构建时会使用Rollup进行打包因此你无需担心生产环境的打包优化问题。它完美兼顾了开发体验和构建质量。框架层面坚定地选择了Vue 3及其组合式API。Vue 3带来的不仅仅是性能提升更小的包体积、更快的渲染速度其组合式APIComposition API彻底改变了代码的组织方式。对于管理后台这种通常包含大量复杂交互逻辑的页面选项式APIOptions API会导致逻辑关注点分散在各个选项data, methods, computed, watch中尤其是使用mixins时代码可读性和可维护性会急剧下降。组合式API允许我们将同一个功能相关的所有逻辑状态、计算属性、方法、生命周期聚合在一个函数中通常是一个useXxx的hook使得代码像搭积木一样可以灵活复用和组合。fast-soy-admin中对于权限、全局状态、网络请求的封装都深度运用了这一特性。2.2 状态与路由Pinia 与 Vue Router 4状态管理选择了Pinia而不是更早的Vuex。Pinia可以看作是Vuex 5的提案实现它被官方推荐为下一代Vue状态管理工具。其优势非常明显更简洁的API、完美的TypeScript支持、去除了冗长的mutations概念。在Pinia中你直接定义state、getters和actionsactions既可以包含异步逻辑也可以同步修改state这更符合直觉。对于TypeScript项目Pinia能提供出色的类型推断几乎不需要手动定义类型。在管理后台中用户信息、菜单权限、全局主题配置等数据非常适合用Pinia来管理提供了清晰的数据流和模块化能力。路由则使用了Vue Router 4这是专为Vue 3设计的版本。它支持组合式API可以与script setup语法糖完美配合。fast-soy-admin通常会在此基础上封装一层动态路由和权限路由的逻辑。即根据用户角色或权限列表从后端接口获取可访问的路由配置然后通过router.addRoute()动态添加到路由实例中。这是实现前端页面级权限控制的核心理念。3. 核心功能模块拆解与实现一个管理后台脚手架除了基础技术栈更重要的是它预置了哪些“开箱即用”的功能。这些功能决定了开发者能节省多少时间。3.1 布局系统灵活可配的页面骨架管理后台的布局通常包含顶部导航栏、侧边菜单栏、内容区域、页脚等部分。fast-soy-admin一般会提供几种经典布局如上下布局、侧边布局、混合布局并通过一个统一的布局组件进行管理。其关键在于将布局与路由进行关联。通常的做法是在路由元信息meta中定义一个layout字段。// 路由配置示例 { path: /dashboard, component: () import(/views/dashboard/index.vue), meta: { title: 控制台, layout: DefaultLayout // 指定使用的布局组件 } }然后在主入口文件如App.vue或一个高级路由守卫中根据当前匹配的路由的meta.layout动态地渲染对应的布局组件并将router-view作为内容区域插入。这种设计使得不同页面如登录页、错误页、主工作台可以使用完全不同的布局非常灵活。3.2 权限管理前端路由与按钮级控制权限管理是后台系统的核心。fast-soy-admin的实现通常遵循“前端控制页面后端控制数据”的原则将权限分为路由权限和功能权限。路由权限页面访问权用户登录后后端返回该用户可访问的菜单/路由列表通常是一个树形结构。前端将这份列表转换为Vue Router需要的路由配置格式并通过router.addRoute()动态添加到路由实例中。同时这份列表也用于生成侧边菜单栏。配置全局路由守卫。在每次路由跳转前router.beforeEach判断目标路由是否存在于当前用户的可访问路由表中。如果不存在则跳转到403无权限或404页面。对于不在路由表中的路径访问如直接输入URL也会被路由守卫拦截。功能权限按钮/操作权 这通常通过自定义指令如v-permission或一个权限判断工具函数来实现。后端会返回一个权限码code列表。template button v-permissionuser:add新增用户/button !-- 或者 -- button v-ifhasPermission(user:delete)删除用户/button /template自定义指令v-permission或函数hasPermission的内部逻辑就是检查传入的权限码是否存在于用户拥有的权限码列表中。实操心得权限码的设计最好与后端协商一致遵循一定的命名规范如模块:操作:user:add,order:view。前端不应硬编码这些码值而应全部来自后端接口。这样当权限规则变化时只需后端调整数据前端无需重新发布。3.3 网络请求封装Axios与统一错误处理几乎100%的管理后台都需要与后端API交互。fast-soy-admin会对Axios进行深度封装目的是实现统一管理、降低重复代码、增强可维护性。封装通常包括创建实例配置基础URL、超时时间、请求/响应拦截器。请求拦截器通常用于自动添加Authorization令牌Token到请求头。响应拦截器这是重点。在这里统一处理网络错误/超时弹出友好提示。业务逻辑错误后端返回的特定错误码如10001代表未登录。拦截器识别后可能自动跳转到登录页。成功响应通常直接返回response.data.data让业务组件直接拿到核心数据。封装请求函数将GET、POST等方法封装成更易用的函数并集成TypeScript类型提示。// 封装示例 - request.ts import axios from ‘axios‘; const service axios.create({ baseURL: ‘/api‘, timeout: 10000 }); service.interceptors.request.use((config) { const token localStorage.getItem(‘token‘); if (token) config.headers.Authorization Bearer ${token}; return config; }); service.interceptors.response.use( (response) { const res response.data; // 假设后端统一格式为 { code: 200, data: any, message: string } if (res.code 200) { return res.data; // 直接返回业务数据 } else { // 处理业务错误 ElMessage.error(res.message || ‘Error‘); return Promise.reject(new Error(res.message || ‘Error‘)); } }, (error) { // 处理HTTP错误 ElMessage.error(error.message || ‘Network Error‘); return Promise.reject(error); } ); export default service; // 使用示例 - user.ts import request from ‘/utils/request‘; export function getUserList(params) { return request({ url: ‘/user/list‘, method: ‘get‘, params }); }3.4 样式与主题CSS架构与暗色模式现代项目离不开良好的CSS架构。fast-soy-admin很可能采用了以下方案CSS预处理器如Sass/Scss或Less提供变量、嵌套、混合等高级功能。CSS方案可能采用UnoCSS或Tailwind CSS这类原子化CSS框架以实现极高的样式复用性和开发效率也可能采用CSS Modules或Scoped CSS来保证组件样式隔离。UI组件库通常会集成Element Plus、Ant Design Vue或Naive UI等成熟组件库并对其进行二次封装以统一风格和添加项目特定逻辑。主题切换实现暗色/亮色模式切换是当前标配。其核心原理是通过CSS变量Custom Properties定义主题颜色。在根元素:root上定义一套亮色变量在html.dark类名下定义一套暗色变量。所有组件的颜色都引用这些CSS变量。切换主题时只需通过JavaScript动态在html标签上添加或移除.dark类名所有颜色就会自动切换。组件库通常也支持基于CSS变量的主题定制可以很好地与这套机制融合。4. 工程化配置与开发提效一个优秀的脚手架其工程化配置的细节决定了团队协作的效率和项目的长期健康度。4.1 代码规范与质量保障ESLint Prettier Husky为了保证代码风格统一和质量项目会集成以下工具链ESLint用于检查JavaScript/TypeScript代码中的语法错误和潜在问题。配置会继承vue/eslint-config-typescript等官方推荐规则并可能根据团队习惯进行微调如强制使用分号、限制单行最大长度等。Prettier代码格式化工具。虽然ESLint也能修复一些格式问题但Prettier在代码格式化上更专业、更固执。通常配置.prettierrc文件定义缩进、引号、尾随逗号等规则。整合与自动化为了避免ESLint和Prettier的规则冲突会使用eslint-config-prettier来关闭ESLint中与Prettier冲突的规则。更重要的是通过Husky和lint-staged实现Git提交前的自动化检查。Husky在项目的.git/hooks中安装钩子。lint-staged配置在package.json中指定对暂存区staged的特定类型文件执行的任务。// package.json lint-staged: { *.{js,ts,vue}: [ eslint --fix, prettier --write ] }这样当开发者执行git commit时会自动对本次提交的代码进行校验和格式化将问题拦截在本地避免有问题的代码进入仓库。4.2 提交规范Commitizen 与 Commitlint统一的提交信息格式有助于生成清晰的变更日志CHANGELOG。项目可能会集成Commitizen通过git cz命令替代git commit引导开发者选择提交类型feat, fix, docs等、填写影响范围、提交描述。同时使用commitlint配合Husky的commit-msg钩子对提交信息格式进行强制校验不符合规范如遵循Angular提交规范的提交会被拒绝。4.3 环境变量与多环境配置管理后台需要对接开发、测试、生产等不同环境的API地址。Vite使用import.meta.env对象来暴露环境变量。项目根目录下会有.env所有环境的默认值。.env.development开发环境变量。.env.production生产环境变量。 变量必须以VITE_开头例如VITE_API_BASE_URL。在代码中可以通过import.meta.env.VITE_API_BASE_URL访问。在封装Axios实例时就可以使用这个变量来设置baseURL从而实现不同环境无缝切换。4.4 性能优化与打包分析Vite的生产构建已经做了很多优化但脚手架通常会进一步配置依赖分包ManualChunks在vite.config.ts中配置build.rollupOptions.output.manualChunks将vue、vue-router、element-plus等几乎不变的第三方依赖打包到单独的vendor文件中利用浏览器缓存避免业务代码更新时用户重复下载这些大库。代码压缩使用vite-plugin-compression生成.gz或.br压缩文件服务端配置后可以显著减少传输体积。打包分析使用rollup-plugin-visualizer在构建后生成一个HTML分析报告直观展示每个模块的体积占比帮助开发者发现和优化过大的依赖。5. 从克隆到部署完整开发流实操假设我们现在要使用fast-soy-admin启动一个新项目“产品运营后台”。5.1 初始化与结构熟悉# 1. 克隆项目 git clone https://github.com/sleep1223/fast-soy-admin.git my-product-admin cd my-product-admin # 2. 安装依赖 (推荐使用pnpm速度更快) pnpm install # 3. 启动开发服务器 pnpm dev项目启动后浏览器打开http://localhost:5173你应该能看到一个完整的后台框架包含登录页、主布局、示例页面等。接下来花些时间浏览项目目录结构这是高效使用脚手架的前提src/ ├── api/ # 所有网络请求接口按模块组织 ├── assets/ # 静态资源图片、字体等 ├── components/ # 全局公共组件 ├── composables/ # Vue 3组合式函数 (hooks) ├── directives/ # 自定义指令如 v-permission ├── layout/ # 布局组件 ├── router/ # 路由配置包含静态路由和动态路由逻辑 ├── stores/ # Pinia状态管理模块 ├── styles/ # 全局样式、变量、主题定义 ├── utils/ # 工具函数请求封装、权限判断等 ├── views/ # 页面级组件 ├── App.vue └── main.ts5.2 开发一个新功能模块用户管理我们以添加一个“用户管理”模块为例包含列表查看、搜索、新增、编辑、删除功能。第一步创建路由和页面在src/views/下新建user文件夹并创建index.vue列表页和detail.vue详情/编辑页。在src/router/routes.ts或类似文件的静态路由中添加一个“用户管理”的父路由和其子路由。注意这里添加的通常是框架路由真正的动态路由由后端返回。// 这是一个常驻框架路由用于挂载布局 { path: ‘/user‘, component: Layout, // 你的布局组件 redirect: ‘/user/list‘, meta: { title: ‘用户管理‘, icon: ‘User‘ }, children: [ { path: ‘list‘, component: () import(‘/views/user/index.vue‘), meta: { title: ‘用户列表‘ } }, { path: ‘detail/:id?‘, // 支持新增和编辑 component: () import(‘/views/user/detail.vue‘), meta: { title: ‘用户详情‘, hidden: true } // hidden: true 表示不在菜单显示 } ] }第二步创建API接口在src/api/下创建user.ts文件使用封装好的request函数定义所有用户相关的接口。import request from ‘/utils/request‘; import type { UserListParams, UserItem } from ‘./types/user‘; // 定义好TS类型 export function getUserList(params: UserListParams) { return requestUserItem[]({ url: ‘/user/list‘, method: ‘get‘, params }); } export function addUser(data: PartialUserItem) { return request({ url: ‘/user‘, method: ‘post‘, data }); } // ... 其他接口第三步创建Pinia Store可选如果用户列表数据需要在多个组件间共享或需要复杂的业务逻辑可以创建src/stores/user.ts。import { defineStore } from ‘pinia‘; import { getUserList } from ‘/api/user‘; import type { UserListParams, UserItem } from ‘/api/types/user‘; export const useUserStore defineStore(‘user‘, { state: () ({ userList: [] as UserItem[], total: 0, queryParams: {} as UserListParams }), actions: { async fetchUserList(params?: UserListParams) { const res await getUserList({ ...this.queryParams, ...params }); this.userList res.list; this.total res.total; return res; }, // ... 其他actions } });第四步构建页面组件在src/views/user/index.vue中使用组合式API编写逻辑。template div class“user-container“ !-- 搜索区域 -- el-form :model“queryParams“ inline el-form-item label“用户名“ el-input v-model“queryParams.username“ placeholder“请输入“ / /el-form-item el-form-item el-button type“primary“ click“handleSearch“搜索/el-button /el-form-item /el-form !-- 操作按钮 -- div class“mb-4“ el-button type“primary“ click“handleAdd“ v-permission“‘user:add‘“新增用户/el-button /div !-- 表格 -- el-table :data“userList“ el-table-column prop“username“ label“用户名“ / el-table-column prop“role“ label“角色“ / el-table-column label“操作“ template #default“{ row }“ el-button link click“handleEdit(row)“ v-permission“‘user:edit‘“编辑/el-button el-button link type“danger“ click“handleDelete(row)“ v-permission“‘user:delete‘“删除/el-button /template /el-table-column /el-table !-- 分页 -- el-pagination v-model:current-page“queryParams.page“ v-model:page-size“queryParams.pageSize“ :total“total“ current-change“fetchData“ layout“total, sizes, prev, pager, next, jumper“ / /div /template script setup lang“ts“ import { ref, onMounted } from ‘vue‘; import { useRouter } from ‘vue-router‘; import { ElMessage, ElMessageBox } from ‘element-plus‘; import { getUserList, deleteUser } from ‘/api/user‘; // 或使用Pinia: import { useUserStore } from ‘/stores/user‘; const router useRouter(); // const userStore useUserStore(); const userList ref([]); const total ref(0); const queryParams ref({ page: 1, pageSize: 10, username: ‘‘ }); const fetchData async () { try { const res await getUserList(queryParams.value); userList.value res.list; total.value res.total; // 如果使用Pinia: await userStore.fetchUserList(queryParams.value); } catch (error) { console.error(‘获取用户列表失败:‘, error); } }; const handleSearch () { queryParams.value.page 1; // 搜索时回到第一页 fetchData(); }; const handleAdd () { router.push(‘/user/detail‘); }; const handleEdit (row) { router.push(/user/detail/${row.id}); }; const handleDelete async (row) { try { await ElMessageBox.confirm(确认删除用户“${row.username}”, ‘提示‘, { type: ‘warning‘ }); await deleteUser(row.id); ElMessage.success(‘删除成功‘); fetchData(); // 刷新列表 } catch (error) { if (error ! ‘cancel‘) { ElMessage.error(‘删除失败‘); } } }; onMounted(() { fetchData(); }); /script5.3 构建与部署开发完成后需要构建生产环境产物。# 构建 pnpm build构建完成后会在项目根目录生成dist文件夹里面是优化、压缩、哈希处理后的静态文件HTML, JS, CSS, 图片等。部署时只需将这个dist目录下的所有文件放到任何静态文件服务器Web Server上即可例如Nginx将dist文件夹内容上传到服务器配置Nginx的root指向该目录并设置try_files来处理Vue Router的history模式。server { listen 80; server_name your-domain.com; root /path/to/your/dist; index index.html; location / { try_files $uri $uri/ /index.html; } }对象存储 CDN将dist内容上传到阿里云OSS、腾讯云COS等对象存储并开启静态网站托管和CDN加速获得更好的访问性能和成本效益。Docker容器化可以编写Dockerfile基于Nginx镜像将构建产物打包成容器镜像便于在云原生环境中部署和扩展。6. 常见问题与排查技巧实录在实际使用这类脚手架进行开发时你可能会遇到一些典型问题。以下是我在多个项目中总结的经验。6.1 动态路由与菜单刷新后丢失问题描述用户登录后动态路由和菜单加载正常。但刷新页面后侧边菜单栏变空或页面跳转到404。根因分析动态路由是通过router.addRoute()在运行时添加的它们存在于内存中的路由实例里但不会持久化。刷新页面后Vue应用重新初始化路由实例恢复到只有静态路由的状态而动态添加的路由消失了。同时生成菜单的数据通常从Pinia store或Vuex读取在刷新后也重置了。解决方案持久化用户权限信息用户登录成功后不仅要将token存入localStorage或Cookie还要将后端返回的菜单/路由列表数据也存储起来例如存入localStorage或Pinia并配合pinia-plugin-persistedstate持久化。应用初始化时恢复在应用入口如main.ts或路由守卫的全局前置钩子中判断用户是否已登录检查token。已登录则恢复状态如果已登录则从持久化存储中读取菜单/路由数据并调用router.addRoute()重新添加动态路由。同时将这些数据重新存入Pinia store以便菜单组件能正确渲染。实操心得这个恢复逻辑最好放在路由守卫的beforeEach最开头或者一个单独的初始化函数中并确保在router.isReady()之后执行以避免路由匹配的竞态条件。6.2 组件库按需引入与样式丢失问题描述为了减小打包体积我们配置了Element Plus等组件库的按需自动导入如使用unplugin-vue-components。但在某些情况下组件的样式没有正确加载导致组件功能正常但样式错乱。排查步骤检查插件配置确认vite.config.ts中Components插件是否正确配置了resolvers并指定了组件库的解析器如ElementPlusResolver()。检查导入语句确保在代码中没有再使用import { ElButton } from ‘element-plus‘这种全量导入方式。按需导入插件会自动识别模板中使用的组件并引入手动导入会干扰此过程可能导致样式重复或丢失。应该只写el-button不写import。检查样式导入在main.ts或入口文件中必须导入组件库的基准样式文件。对于Element Plus通常是import ‘element-plus/dist/index.css‘; // 或者如果你使用了暗黑模式可能需要导入主题变量文件 import ‘element-plus/theme-chalk/dark/css-vars.css‘;检查浏览器控制台查看Network面板确认对应的CSS文件是否被成功加载。如果没有可能是构建配置问题。6.3 打包后文件过大或首屏加载慢问题描述执行pnpm build后发现dist/assets目录下的入口JS文件如index-xxx.js体积巨大超过1MB导致应用首屏加载缓慢。优化策略分析包体积使用rollup-plugin-visualizer生成分析报告查看是哪些依赖占据了主要体积。可能是某个大型库如xlsx、pdfjs-dist或未正确拆包的组件库。配置手动分包ManualChunks在vite.config.ts中优化build.rollupOptions.output.manualChunks。build: { rollupOptions: { output: { manualChunks: { // 将vue相关库打包到一个chunk ‘vue-vendor‘: [‘vue‘, ‘vue-router‘, ‘pinia‘], // 将UI组件库打包到一个chunk ‘element-ui‘: [‘element-plus‘], // 将其他大型库单独打包 ‘echarts‘: [‘echarts‘], } } } }路由懒加载确保所有路由组件都使用动态导入() import(‘…’)这样每个路由对应的代码会被分割成独立的chunk按需加载。压缩图片等静态资源确保图片经过压缩可使用vite-plugin-imagemin在构建时自动压缩。开启Gzip/Brotli压缩在服务器层面Nginx或使用vite-plugin-compression在构建时生成预压缩文件能减少约70%的传输体积。6.4 跨域问题开发环境问题描述在开发时pnpm dev前端运行在localhost:5173请求后端API如api.yourcompany.com时浏览器报跨域错误。解决方案Vite提供了内置的代理功能在vite.config.ts中配置server.proxy。server: { proxy: { ‘/api‘: { target: ‘http://api.yourcompany.com‘, // 你的后端地址 changeOrigin: true, // 修改请求头中的Origin为目标地址解决CORS rewrite: (path) path.replace(/^\/api/, ‘‘) // 可选的路径重写 } } }配置后前端请求/api/user/list会被代理到http://api.yourcompany.com/user/list从而绕过浏览器的同源策略限制。此配置仅用于开发环境生产环境需要通过Nginx等服务器配置反向代理或后端配置CORS头来解决。6.5 TypeScript类型报错问题描述在集成第三方库或编写复杂逻辑时遇到TS类型错误尤其是any类型或模块找不到声明文件。处理技巧安装类型声明包对于常用的JS库社区通常有对应的类型包types/库名。使用pnpm add -D types/库名安装。Vite的客户端类型如果使用Vite的环境变量import.meta.env需要在env.d.ts文件中进行类型声明。/// reference types“vite/client“ / interface ImportMetaEnv { readonly VITE_API_BASE_URL: string // 更多环境变量... } interface ImportMeta { readonly env: ImportMetaEnv }善用类型断言和泛型在明确知道类型的地方使用as进行类型断言。在封装通用函数如请求函数时使用泛型来提供类型安全。// 请求函数泛型示例 export function requestT any(config: AxiosRequestConfig): PromiseT { return service(config).then(res res as T); } // 使用时 interface UserData { id: number; name: string; } const userData await requestUserData({ url: ‘/user/1‘ }); // userData 的类型就是 UserData逐步推进对于遗留代码或快速原型可以在文件顶部或特定行使用// ts-ignore暂时忽略错误但应记录并后续解决。使用fast-soy-admin这类现代化脚手架最大的价值在于它提供了一个经过验证的、最佳实践的起点让你能跳过繁琐的基建直接奔向业务价值的创造。然而它并非银弹理解其背后的设计原理和实现细节能让你在遇到问题时快速定位也能根据自己团队的特定需求进行有效的定制和扩展。从“会用”到“懂为什么这么用”是每一个开发者在使用这类工具时的必修课。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…