[前后端系统开发教程]第四节-前端多平台部署的终极解决方案

[前后端系统开发教程]第四节-前端多平台部署的终极解决方案

在上一节中我们已经制作了一个简单的用户管理后端系统,我们这节就来尝试制作一个对应的前端系统。那么,我们是要使用安卓开发者工具制作一个安卓app,或者部署为微信小程序,亦或部署为传统的html网页?

答案是我全都要!通过DCloud生态,我们可以实现一份代码,多端部署。

第一部分:什么是DCloud生态?

众将士多端露难色,新面孔竟生好胆识

注:本节开始,教程的节奏会适当加快,希望各位可以跟上。

简单来说,DCloud生态的核心功能是,通过将项目按照不同的目标部署平台,二次编译为对应平台的代码,以实现“一份代码,多端部署”,以提高开发效率。详细介绍请参考uniapp官方文档:简介 - HBuilderX 文档。DCloud还提供云函数、云对象等工具,我们将在教程的后面去学习。

在这节教程中我们先学习如何在HBuilderX中调用上节中后端系统的API(即后端服务接口),编写一份前端代码,再将其打包为微信小程序、html网页和安卓app。

第二部分:怎么调用后端API接口?

接口表叫那前端瞧,服务器知晓谁来还

我们先回顾一下上节教程中的接口类,将其整理为一份API接口说明文件:

用户管理接口文档 1 获取所有用户 URL GET /users 描述 获取系统中所有用户的列表 响应示例 [ { "userId": 1, "userName": "张三", "password": "123456" }, { "userId": 2, "userName": "李四", "password": "abcdef" } ] 2 根据ID获取用户 URL GET /users/{id} 描述 根据用户ID获取特定用户的信息 参数 id 用户的唯一标识符 响应示例 { "userId": 1, "userName": "张三", "password": "123456" } 3 添加用户 URL POST /users 描述 创建一个新的用户 请求体 { "userName": "王五", "password": "qwerty" } 响应示例 { "userId": 3, "userName": "王五", "password": "qwerty" } 4 更新用户 URL PUT /users/{id} 描述 更新指定ID的用户信息 参数 id 要更新的用户的唯一标识符 请求体 { "userName": "王五", "password": "newpassword" } 响应示例 { "userId": 3, "userName": "王五", "password": "newpassword" } 5 删除用户 URL DELETE /users/{id} 描述 删除指定ID的用户 参数 id 要删除的用户的唯一标识符 响应示例 无内容 6 初始化测试数据 URL POST /users/init 描述 为系统添加一些初始测试用户数据 响应示例 { "message": "测试数据已成功添加" }

我们在编写前端功能时,就参考这个接口文档,将前端的请求发送给对应的接口,后端就会发相应的json格式响应体返回给前端。

在HBuilderX安装完成后,新建一个uniapp项目。此过程就和操作vs code等IDE大同小异,这里不再赘述,如有问题请参考DCloud的相关文档。

接下来我们要熟悉一下uniapp的项目架构:

我们从上往下介绍:

1.pages目录:各前端页面的vue文件。

2.static目录:放置css样式库、背景图片、icon等静态资源。

3.app.vue:uni-app 项目的根组件文件,类似于 Vue.js 中的根实例。它定义了整个应用的生命周期钩子函数。用于全局逻辑控制,例如初始化数据、监听应用状态变化等。

4.index.html:uni-app 项目的入口 HTML 文件,负责加载主应用脚本并渲染页面。

5.main.js:是 uni-app 项目的核心启动文件,根据不同的 Vue 版本(Vue 2 或 Vue 3)执行相应的初始化逻辑。

6.manifest.json:用于不同平台的图标、发布信息等等发布相关参数的配置。

7.pages.json:配置前端页面的页面路由。

8.uni.promisify.adaptor.js:简化异步调用,提升代码可读性和维护性,尤其适用于需要大量异步操作的场景。

9.uni.scss:一个pro版的css样式库,可以理解为“super css”。

接下来,我们按照接口文档编写功能代码:

我们就像写普通的vue一样搭建一个简单的标签页:

<template> <view> <view> <text>用户管理</text> <button @click="fetchUsers">刷新</button> <button @click="initTestData">初始化测试数据</button> </view> <view> <view v-for="user in users" :key="user.userId"> <text>{{ user.userName }}</text> <view> <button @click="editUser(user)">编辑</button> <button @click="deleteUser(user.userId)">删除</button> </view> </view> </view> <view> <input v-model="newUser.userName" placeholder="用户名" /> <input v-model="newUser.password" placeholder="密码" type="password" /> <button @click="addUser">添加用户</button> </view> <!-- 编辑用户弹窗 --> <view v-if="editingUser"> <view> <input v-model="editingUser.userName" placeholder="用户名" /> <input v-model="editingUser.password" placeholder="密码" type="password" /> <button @click="updateUser">保存</button> <button @click="cancelEdit">取消</button> </view> </view> </view> </template>

接着是click事件触发的功能函数:

<script> // 引入Vue 3的ref函数用于创建响应式数据 import { ref } from 'vue' export default { setup() { // 响应式数据定义 const users = ref([]) // 存储用户列表数据 const newUser = ref({ userName: '', // 新用户用户名 password: '' // 新用户密码 }) const editingUser = ref(null) // 当前正在编辑的用户数据 // 获取所有用户列表的异步函数 const fetchUsers = async () => { try { // 发送GET请求获取用户列表 const res = await uni.request({ url: 'http://localhost:8080/api/users', method: 'GET' }) // 请求成功,更新用户列表数据 if (res.statusCode === 200) { users.value = res.data } } catch (error) { // 请求失败,打印错误信息并显示提示 console.error('获取用户列表失败:', error) uni.showToast({ title: '获取用户列表失败', icon: 'none' }) } } // 添加新用户的异步函数 const addUser = async () => { // 验证输入数据完整性 if (!newUser.value.userName || !newUser.value.password) { uni.showToast({ title: '请输入完整信息', icon: 'none' }) return } try { // 发送POST请求添加新用户 const res = await uni.request({ url: 'http://localhost:8080/api/users', method: 'POST', data: newUser.value // 发送用户输入的数据 }) // 请求成功,显示成功提示并刷新列表 if (res.statusCode === 200) { uni.showToast({ title: '添加成功', icon: 'success' }) // 清空输入框 newUser.value = { userName: '', password: '' } // 重新获取用户列表 fetchUsers() } } catch (error) { // 请求失败,显示错误提示 console.error('添加用户失败:', error) uni.showToast({ title: '添加用户失败', icon: 'none' }) } } // 编辑用户函数,设置当前编辑的用户数据 const editUser = (user) => { editingUser.value = { ...user } // 使用展开运算符创建副本,避免直接修改原数据 } // 更新用户信息的异步函数 const updateUser = async () => { try { // 发送PUT请求更新用户信息 const res = await uni.request({ url: `http://localhost:8080/api/users/${editingUser.value.userId}`, method: 'PUT', data: { userName: editingUser.value.userName, password: editingUser.value.password } }) // 请求成功,显示提示并刷新数据 if (res.statusCode === 200) { uni.showToast({ title: '更新成功', icon: 'success' }) cancelEdit() // 关闭编辑弹窗 fetchUsers() // 刷新用户列表 } } catch (error) { // 请求失败,显示错误提示 console.error('更新用户失败:', error) uni.showToast({ title: '更新用户失败', icon: 'none' }) } } // 取消编辑函数,清空编辑状态 const cancelEdit = () => { editingUser.value = null } // 删除用户的异步函数 const deleteUser = async (userId) => { // 显示确认对话框 uni.showModal({ title: '确认删除', content: '确定要删除这个用户吗?', success: async (res) => { // 用户确认删除 if (res.confirm) { try { // 发送DELETE请求删除用户 const response = await uni.request({ url: `http://localhost:8080/api/users/${userId}`, method: 'DELETE' }) // 请求成功,显示提示并刷新列表 if (response.statusCode === 200) { uni.showToast({ title: '删除成功', icon: 'success' }) fetchUsers() } } catch (error) { // 请求失败,显示错误提示 console.error('删除用户失败:', error) uni.showToast({ title: '删除用户失败', icon: 'none' }) } } } }) } // 初始化测试数据的异步函数 const initTestData = async () => { try { // 发送POST请求初始化测试数据 const res = await uni.request({ url: 'http://localhost:8080/api/users/init', method: 'POST' }) // 请求成功,显示提示并刷新列表 if (res.statusCode === 200) { uni.showToast({ title: '测试数据初始化成功', icon: 'success' }) fetchUsers() } } catch (error) { // 请求失败,显示错误提示 console.error('初始化测试数据失败:', error) uni.showToast({ title: '初始化测试数据失败', icon: 'none' }) } } // 页面加载时自动获取用户列表 fetchUsers() // 返回需要在模板中使用的数据和方法 return { users, newUser, editingUser, fetchUsers, addUser, editUser, updateUser, cancelEdit, deleteUser, initTestData } } } </script> 

写好代码后,我们就可以测试运行了,一定要先运行后端,再运行前端。

注:在浏览器上运行时,可能会遇到跨域问题,这需要在后端增加一个配置文件Webconfig.java:

package springdemo.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://localhost:5173") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*") .allowCredentials(true); } }

第三部分:如何实现一份代码,多端部署?

打包机妙计讨人爱,前后端直呼甚奇巧

在“运行”中我们看见:

各位按需要在相应平台上运行即可,在小程序模拟器上运行会打开微信小程序开发工具,在第一次使用时可能需要先注册账号;在模拟器上运行则需要下载模拟器,各位见招拆招即可。

这里仅展示网页端效果:

第四部分:对于使用HBuilder开发流的其他建议

执神器终有难题现,知底层方才解桎梏

需要注意的是,由于HBuilderX是在微信小程序开发、安卓开发、IOS开发、web开发之上的又一层套娃,使用HBuilderX会遇到比常规开发工具更加层出不穷的平台兼容性问题(例如上文提及的跨域问题),这需要各位开发者具备很强的错误排查能力。

这里我将针对本节教程,将各位可能会遇到的问题简要整理如下:

1.跨越问题:spring后端可能会因CORS阻挡访问,需要重写一个配置文件允许来自local的跨域请求访问端口的文件,代码已在上文给出。

2.web运行正常,但安卓app运行白屏且无报错:这是导入了安卓app环境下无法解析的库,需要更换相应的库。

3.无法在微信小程序开发工具上运行:可能是manifest.json中的微信小程序appid配置错误,建议参考微信小程序开发者官方文档进行进一步排查。

4.预览功能中某些请求响应异常:预览功能是按需编译的,发送请求时可能会发生各种稀奇古怪的BUG,建议预览功能仅供调试样式时使用。

Read more

Vivado使用教程:图解说明管脚分配全过程

Vivado管脚分配实战指南:从原理到避坑全解析 你有没有遇到过这样的情况?逻辑代码写得完美无缺,仿真波形也完全正确,结果下载到FPGA板子上——灯不亮、通信失败、甚至芯片发热异常。排查半天,最后发现是某个引脚接错了电压标准? 别笑,这在FPGA开发中太常见了。 尤其是在初学阶段,很多人把注意力都放在Verilog或VHDL的语法和状态机设计上,却忽略了 一个比代码更底层、更关键的环节:管脚分配 。 今天我们就来彻底拆解这个“隐形杀手”——用最贴近工程实践的方式,带你一步步搞懂 Vivado中的管脚分配全过程 ,不只是点几下鼠标那么简单,而是理解背后的电气规则、约束机制与系统级影响。 为什么管脚分配不是“随便连一下”? FPGA不像MCU那样有固定的外设映射。它的每个IO引脚都是可编程的,这意味着你可以自由定义哪个引脚做时钟输入、哪个输出控制LED。但自由的背后是责任: 每一个引脚配置都必须符合物理世界的电气法则 。 举个真实案例: 某工程师将一个来自3.3V系统的复位信号接入Bank 14(VCCO=1.8V),没有加电平转换。虽然一开始功能似乎正常,但在高温环境下

无人机遥感航拍巡检数据集 无人机遥感图像识别 无人机视角山区泥石流和滑坡图像识别数据集-数据集第10067期

无人机遥感航拍巡检数据集 无人机遥感图像识别 无人机视角山区泥石流和滑坡图像识别数据集-数据集第10067期

滑坡检测数据集核心信息介绍 ** 这个滑坡检测数据集主要用于目标检测任务,整体数据规模和细节都比较明确。从数量上看,数据集总共包含 1660 张图像, 往期热门主题 主题搜两字"关键词"直达 代码数据获取: 获取方式:***文章底部卡片扫码获取*** 覆盖了YOLO相关项目、OpenCV项目、CNN项目等所有类别, 覆盖各类项目场景(包括但不限于以下----欢迎咨询定制): 项目名称项目名称基于YOLO+deepseek 智慧农业作物长势监测系统基于YOLO+deepseek 人脸识别与管理系统基于YOLO+deepseek 无人机巡检电力线路系统基于YOLO+deepseek PCB板缺陷检测基于YOLO+deepseek 智慧铁路轨道异物检测系统基于YOLO+deepseek 102种犬类检测系统基于YOLO+deepseek 人脸面部活体检测基于YOLO+deepseek 无人机农田病虫害巡检系统基于YOLO+deepseek 水稻害虫检测识别基于YOLO+deepseek 安全帽检测系统基于YOLO+deepseek 智慧铁路接触网状态检测系统基于YOLO+

Trae x Vizro:低代码构建专业数据可视化仪表板的高效方案

Trae x Vizro:低代码构建专业数据可视化仪表板的高效方案

声明:文章为本人真实测评博客,非广告,并没有推广该平台 ,为用户体验文章 目录 * 前言 * 一.核心工具与优势解析 * 低代码高效开发 * 专业视觉设计 * 高度灵活可定制 * AI赋能创新 * 二.操作步骤:从安装到生成效果 * 第一步. 获取MCP配置代码 * 第二步:下载 * 第三步:在 Trae 中导入 MCP 配置并建立连接 * 三. 实战:用Vizro MCP快速构建仪表板 * 1. 提出需求 * 2.智能体生成代码 * 3.查看运行结果 * 4.优化与部署 * 四.Vizro MCP核心功能解析 * get_vizro_chart_or_dashboard_plan * get_model_json_

宇树 G1 机器人开发入门:有线 & 无线连接完整指南

宇树 G1 机器人开发入门:有线 & 无线连接完整指南

适用读者:机器人二次开发者、科研人员 开发环境:Ubuntu 20.04(推荐) 机器人型号:Unitree G1 EDU+ 前言 宇树 G1 是一款面向科研与商业应用的高性能人形机器人,支持丰富的二次开发接口。在正式进行算法调试与功能开发之前,首要任务是建立稳定的开发连接。本文将详细介绍两种主流连接方式:有线(网线直连) 与 无线(WiFi + SSH),并附上完整的配置流程,帮助开发者快速上手。 一、有线连接(推荐新手优先使用) 有线连接通过网线直接将开发电脑与 G1 机器人相连,具有延迟低、稳定性高、不依赖外部网络的优势,是新手入门和底层调试的首选方式。 1.1 前置条件 所需物品说明开发电脑推荐安装 Ubuntu 20.04,或在 Windows 上使用虚拟机宇树 G1 机器人确保已开机且处于正常状态网线(