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

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

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

iterm2-snazzy主题自定义教程:如何根据个人喜好调整终端色彩

iterm2-snazzy主题自定义教程:如何根据个人喜好调整终端色彩 【免费下载链接】iterm2-snazzyElegant iTerm2 theme with bright colors 项目地址: https://gitcode.com/gh_mirrors/it/iterm2-snazzy iterm2-snazzy是一款拥有明亮色彩的优雅iTerm2主题,能让你的终端界面更加美观舒适。本教程将带你了解如何安装该主题并根据个人喜好调整终端色彩,打造专属于你的个性化终端体验。 一、快速安装iterm2-snazzy主题 1.1 克隆项目仓库 首先,打开终端,执行以下命令克隆项目仓库: git clone https://gitcode.com/gh_mirrors/it/iterm2-snazzy 1.2 导入主题文件 进入克隆好的项目目录,找到Snazzy.itermcolors文件。打开iTerm2,依次点击iTerm2->Preferences->Profiles-&

Flutter 三方库 bones_ui 的鸿蒙化适配指南 - 打造直观、响应式的 Web 风格 UI 交互体验

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 bones_ui 的鸿蒙化适配指南 - 打造直观、响应式的 Web 风格 UI 交互体验 Flutter for OpenHarmony 开发者在构建具有 Web 质感的跨平台应用时,UI 框架的选择至关重要。本文将带大家深度调研 Dart 三方库 bones_ui 在鸿蒙系统上的适配方案,探索如何利用其直观的组件架构,加速鸿蒙桌面级应用的开发效率。 前言 在移动端和桌面端融合的今天,开发者往往希望一套代码能同时适配多种屏幕形态。bones_ui 原生为 Dart Web 打造,但在 Flutter for OpenHarmony 的大前端生态中,其简洁的 UI 组件设计思想对我们构建鸿蒙跨平台应用具有极大的参考价值。

【沧海拾昧】绿联NAS配置WebDAV公网访问并使用RaiDrive挂载到本地

【沧海拾昧】绿联NAS配置WebDAV公网访问并使用RaiDrive挂载到本地

#C0601 沧海茫茫千钟粟,且拾吾昧一微尘 ——《沧海拾昧集》@CuPhoenix 【阅前敬告】沧海拾昧集仅做个人学习笔记之用,所述内容不专业不严谨不成体系【如有问题必是本集记录有谬,切勿深究】 目录 * 前言 * 一、配置步骤 * 1、确认网络设备支持 IPv6 * 2、购买域名 * 3、配置访问凭证 * 2、NAS 配置 WebDAV 服务 * 3、NAS 配置 DDNS 支持 * 4、配置反向代理 * 5、在 RaiDrive 中挂载 * 6、设置防火墙 * 二、最终结果 前言 将 NAS 的磁盘空间通过 RaiDrive 等软件挂载到本地使用是一种十分便捷的方法,但是 RaiDrive 中只有针对群晖(

vLLM+Open-WebUI部署通义千问2.5-7B完整教程

vLLM + Open-WebUI 部署通义千问2.5-7B完整教程 1. 引言 1.1 学习目标 本文将详细介绍如何使用 vLLM 和 Open-WebUI 联合部署阿里云发布的开源大模型——通义千问2.5-7B-Instruct。通过本教程,你将掌握: * 如何在本地或服务器环境中部署 Qwen2.5-7B 模型 * 利用 vLLM 实现高性能推理(支持 Tensor Parallelism、PagedAttention) * 使用 Open-WebUI 提供类 ChatGPT 的可视化交互界面 * 完整的环境配置、服务启动与访问流程 * 常见问题排查与性能优化建议 最终实现:通过浏览器访问 http://localhost:7860,即可与通义千问进行流畅对话。 1.2 前置知识 为顺利执行本教程,请确保具备以下基础: * 熟悉 Linux