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

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

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

35道常见的前端vue面试题,零基础入门到精通,收藏这篇就够了

35道常见的前端vue面试题,零基础入门到精通,收藏这篇就够了

来源 | https://segmentfault.com/a/1190000021936876 今天这篇文章给大家分享一些常见的前端vue面试题。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 对于前端来说,尽管css、html、js是主要的基础知识,但是随着技术的不断发展,出现了很多优秀的mv*框架以及小程序框架。因此,对于前端开发者而言,需要对一些前端框架进行熟练掌握。这篇文章我们一起来聊一聊VUE及全家桶的常见面试问题。 1、请讲述下VUE的MVVM的理解? MVVM 是 Model-View-ViewModel的缩写,即将数据模型与数据表现层通过数据驱动进行分离,从而只需要关系数据模型的开发,而不需要考虑页面的表现,具体说来如下: Model代表数据模型:主要用于定义数据和操作的业务逻辑。 View代表页面展示组件(即dom展现形式):负责将数据模型转化成UI 展现出来。 ViewModel为model和view之间的桥梁:监听模型数据的改变和控制视图行为、处理用户交互。通过双向数据绑定把 View 层和 Model 层连接了起来,而View

Java Web 编程训练系统系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】

Java Web 编程训练系统系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】

摘要 随着信息技术的快速发展,互联网应用逐渐渗透到各行各业,教育领域也迎来了数字化转型的浪潮。传统的编程训练方式通常依赖于本地开发环境或简单的在线评测系统,难以满足现代教育对灵活性、交互性和数据驱动的需求。尤其是在高校计算机专业教学中,学生编程能力的培养需要更加系统化、智能化的平台支持。基于此背景,设计并实现一个高效、易用的Java Web编程训练系统具有重要意义。该系统旨在为学生提供在线编程练习、自动评测、学习进度跟踪等功能,同时为教师提供题目管理、成绩分析等教学辅助工具。关键词:Java Web、编程训练、在线评测、教学辅助、SpringBoot2。 本系统采用前后端分离架构,后端基于SpringBoot2框架搭建,结合MyBatis-Plus实现高效数据操作,MySQL8.0作为数据库存储系统数据。前端采用Vue3框架,利用其响应式特性和组件化开发优势,提升用户体验。系统核心功能包括用户权限管理、编程题目发布与提交、自动代码评测、学习数据统计分析等。通过集成第三方代码运行环境,系统能够支持多种编程语言的在线编译与执行。此外,系统还提供详细的错误反馈和性能分析报告,帮助学生快速

低延迟直播终极方案:WebRTC + MediaMTX,延迟<500ms!

低延迟直播终极方案:WebRTC + MediaMTX,延迟<500ms!

低延迟直播终极方案:WebRTC + MediaMTX,延迟<500ms! 在直播场景中,延迟往往是用户体验的关键。传统的HLS或RTMP直播延迟通常在3-10秒,这对于互动连麦、远程驾驶、在线教育等场景来说远远不够。那么有没有一种方案可以实现端到端延迟低于500ms,且无需安装插件,直接用浏览器就能观看?答案是肯定的,今天我们就来介绍一套强大的组合:WebRTC + MediaMTX。 为什么是WebRTC? WebRTC(Web Real-Time Communication)是一种支持浏览器之间实时音视频通信的技术,其核心优势就是超低延迟(通常可达200-400ms)。它基于UDP传输,配合P2P或通过TURN中继,天然适合实时流媒体场景。 但WebRTC本身是一个点对点协议,如果我们要做一对多的直播,就需要一个媒体服务器来分发流。市面上有很多选择,如Janus、Licode、SRS等,而今天的主角MediaMTX(原名rtsp-simple-server)则因其轻量、易用、原生支持WebRTC输出而备受青睐。 MediaMTX 简介 MediaMTX 是一个开源

WebPShop插件完整指南:让Photoshop完美支持WebP图像格式

WebPShop插件完整指南:让Photoshop完美支持WebP图像格式 【免费下载链接】WebPShopPhotoshop plug-in for opening and saving WebP images 项目地址: https://gitcode.com/gh_mirrors/we/WebPShop 作为现代图像格式的领军者,WebP以其卓越的压缩效率和动画支持能力,正在逐步改变数字图像的处理方式。然而,专业设计师在使用Photoshop时常常面临一个尴尬的现实:原生不支持WebP格式。WebPShop插件应运而生,为Photoshop用户提供了完整的WebP格式解决方案。 🤔 为什么需要WebPShop插件? 痛点问题分析 * Photoshop原生无法打开.webp文件,导致工作流程中断 * 无法直接保存为WebP格式,必须依赖第三方转换工具 * 缺乏专业的压缩参数控制,无法优化图像质量与文件大小 * 动态WebP动画处理能力缺失,影响创意表达 解决方案概述 WebPShop插件通过开源方式,为Photoshop添加了完整的WebP格式支持。无论是