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

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

在上一节中我们已经制作了一个简单的用户管理后端系统,我们这节就来尝试制作一个对应的前端系统。那么,我们是要使用安卓开发者工具制作一个安卓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

【机器人】机器人方向的顶会--自用

机器人领域的顶会主要分为 “跨领域旗舰顶会”(覆盖机器人全方向,含金量最高)和 “细分方向顶会”(聚焦感知、决策、控制、人机交互等子领域),均为 CCF A 类或领域内公认的顶级会议,适合跟踪前沿研究、投稿交流。结合你之前关注的 “视觉算法、SLAM、强化学习、具身智能、移动 / 机械臂控制” 等方向,整理如下: 一、机器人领域旗舰顶会(必关注,全方向覆盖) 这两个是机器人领域的 “双子星”,跨感知、决策、控制、硬件、应用等所有方向,是行业内最权威的会议,投稿范围广、影响力最大。 1. ICRA(IEEE International Conference on Robotics and Automation) 定位:机器人领域

FPGA光通信2——Aurora 64B/66B的开发使用

FPGA光通信2——Aurora 64B/66B的开发使用

可参考GZH:小蘇的FPGA         FPGA光通信的开发过程中,最简便的方式为Aurora 64B66B,开发人员无需关注2bit同步头,加解扰等过程,开放给开发人员的主要是AXI-Stream用户数据接口。         Aurora是一款可扩展的轻量级、高数据速率链路层高速串行通信协议,支持全双工或单工,支持64B/66B,8B/10B编码。 一、Aurora 64B/66B使用介绍         该核的使用架构主要如下:借助xilinx 核,开发人员可根据用户接口实现多通道间的光通信。最大支持16lane。 1.1 、IP核的介绍         参考PG074, 该核的内部结构如下:         其中,Lane logic:每个GT收发器由一个lane逻辑模块实例驱动,初始化每个收发器,处理控制字符的编解码,并执行错误检测。         Global logic: 全局逻辑模块执行通道绑定以进行通道初始化。在运行过程中,该通道跟踪Aurora 64B/66B协议定义的Not Ready空闲字符,并监控所有通道逻辑模块的错误。

海尔智能家居接入HomeAssistant:终极完整指南

海尔智能家居接入HomeAssistant:终极完整指南 【免费下载链接】haier 项目地址: https://gitcode.com/gh_mirrors/ha/haier 想要实现全屋智能设备的统一控制吗?海尔智能家居接入HomeAssistant插件正是你需要的解决方案。这款开源集成工具能够将海尔智家生态中的空调、热水器、传感器等各类智能设备无缝整合到HomeAssistant平台,让你轻松打破品牌壁垒,享受真正的全屋智能体验。 🏠 准备工作与环境检查 在开始安装前,请确保你的智能家居系统满足以下基本条件: 系统兼容性清单: * HomeAssistant版本2023.1.0或更高 * 海尔智家APP中设备运行正常 * 稳定的网络连接环境 * 有效的海尔智家账号 验证操作步骤: 1. 登录HomeAssistant后台确认系统版本 2. 在海尔智家APP中检查设备在线状态 3. 确保网络连接质量可靠 📦 三种安装方法对比选择 HACS可视化安装(新手首选) 如果你已经安装了HACS组件,这是最快捷的安装方式: 1. 打开HACS管

【机器人】复现 StreamVLN 具身导航 | 流式VLN | 连续导航

【机器人】复现 StreamVLN 具身导航 | 流式VLN | 连续导航

StreamVLN 通过在线、多轮对话的方式,输入连续视频,输出动作序列。 通过结合语言指令、视觉观测和空间位姿信息,驱动模型生成导航动作(前进、左转、右转、停止)。 论文地址:StreamVLN: Streaming Vision-and-Language Navigation via SlowFast Context Modeling 代码地址:https://github.com/OpenRobotLab/StreamVLN 本文分享StreamVLN 复现和模型推理的过程~ 下面是示例效果: 1、创建Conda环境 首先创建一个Conda环境,名字为streamvln,python版本为3.9; 然后进入streamvln环境,执行下面命令: conda create -n streamvln python=3.9 conda activate streamvln 2、 安装habitat仿真环境