uniapp:实现手机端APP登录强制更新,从本地服务器下载新的apk更新,并使用WebSocket,实时强制在线用户更新
实现登录即更新,或实时监听更新
本文介绍的是在App打开启动的时候调用更新,点击下方链接,查看使用WebSocket实现实时通知在线用户更新。
uniapp:全局消息是推送,实现app在线更新,WebSocket,apk上传:
登录更新流程
- 1.在app每次启动的时候请求java后端,
- 2.后端接口获取最新的版本:
- 3.打开更新页面
- 4.后端下载接口去指定目录下载apk
- 背景:内部手持机app开发功能,需要更新的到车间各个手持机上。
- 最初的方案:开发人员开发完后,去现成给每台手持机安装更新
- 设想:实现在线发布,手持机检测版本后更新。
实现手持机更新
1.发布到应用商店
2.uiniapp自带版本更新
3.自己开发功能,检测需要更新后从自己的服务器上下载下来更新
这里我们选择自己开发,毕竟不需要证书,和依托于其他平台
app更新更新我们需要解决哪些问题?
1app什么时候知道自己需要更新?
2检测到需要更新后从哪里获取文件?
3如果app一直在线运行,如何实时通知它需要更新?
下面我们逐一解决:
1app什么时候知道自己需要更新?
这里我们使用的是在app每次打开的时候去请求我们后台的接口,拿到最新的app版本(自己定义的),和当前app的版本进行比较。
前提是,你在自己的服务器上上传了apk之后并且记录了在自己的业务表里面。这样你才能比较是否需要更新。(意思就是最好你维护一张表,每次上传插入一条记录)
实现:
1.在app每次启动的时候请求java后端,
因此要卸载App.vue里面
<script>function requestToJavaBackend() {uni.request({url: 'http://*.*.*.*:8080/app/getNewestVersion', // 替换成你的后端 Java 服务的API地址method: 'GET', // 或 'POST',根据你的需求选择请求方法success: (res) => {if(res.data.code === 200){console.log(res.data.data);console.log();console.log(uni.getSystemInfoSync().appVersion+"111111111");console.log();console.log(uni.getSystemInfoSync().appVersionCode+"222222");console.log(platform+"33333333333333333333")const newVersionName = res.data.data.newVersionName //线上最新版本名const newVersionCode = res.data.data.newVersionCode; //线上最新版本号// const selfVersionCode = Number(uni.getSystemInfoSync().appVersion) //当前App版本号 const selfVersionCode = Number(uni.getSystemInfoSync().appVersionCode) //当前App版本号const platform = uni.getSystemInfoSync().platform //手机平台//线上版本号高于当前,进行在线升级if (selfVersionCode < newVersionCode) {//安卓手机弹窗升级 platform === 'android' || windows// uni.navigateTo({// url: '/pages/index/upgrade'// })if (platform === 'android') {uni.navigateTo({url: '/pages/index/upgrade'})} else {uni.showModal({title: '发现新版本 ' + newVersionName,content: '请到App store进行升级',showCancel: false})}}}else{uni.showModal({title: '版本校验错误',content: '版本校验错误,联系管理员',showCancel: false})}},fail: (err) => {uni.showModal({title: '版本校验错误',content: '版本校验错误,联系管理员',showCancel: false})// 在这里处理请求失败后的逻辑},});}export default {onLaunch() {// 加载系统信息this.$store.dispatch('SystemInfo');// 在应用启动时执行一次任务requestToJavaBackend()// 每隔一段时间执行一次任务// setInterval(() => {// requestToJavaBackend()// }, 5000); // 30秒},onShow() {},onHide() {},methods: {},}
</script><style lang="scss">@import "@/uni_modules/uview-ui/index.scss";@import "@/static/style.scss";
</style>
2.后端接口获取最新的版本:
@GetMapping("/getNewestVersion")public AjaxResult getNewestVersion(){HashMap<String, Object> map = new HashMap<>();map.put("newVersionName", "v");map.put("newVersionCode", 2);//你的最新版本,建议每次开发完上传之后放在表里,然后去表里拿最新的记录,的版本号return AjaxResult.success(map);}
这里检测到2>1之后,就要打开更新页面强制更新(当然你可以不更新,看业务需求)
3.打开更新页面
注意从自己的服务器下载,当前版本小于服务器版本,跳转下载。
自定义下载地址:this.downloadUrl = ‘http://...:8080/app/download’; //下载链接
目录结构
upgrade.vue 更新弹窗
<template><view class="upgrade-popup"><image class="header-bg" src="" mode="widthFix"></image><view class="main"><view class="version">发现新版本{{versionName}}</view><view class="content"><text class="title">更新内容</text><view class="desc" v-html="versionDesc"></view></view><!--下载状态-进度条显示 --><view class="footer" v-if="isStartDownload"><view class="progress-view" :class="{'active':!hasProgress}" @click="handleInstallApp"><!-- 进度条 --><view v-if="hasProgress" style="height: 100%;"><view class="txt">{{percentText}}</view><view class="progress" :style="setProStyle"></view></view><view v-else><view class="btn upgrade force">{{ isDownloadFinish ? '立即安装' :'下载中...'}}</view></view></view></view><!-- 强制更新 --><view class="footer" ><view class="btn upgrade force" @click="handleUpgrade">立即更新</view></view><!-- 可选择更新 --><!-- <view class="footer" v-else><view class="btn close" @click="handleClose">以后再说</view><view class="btn upgrade" @click="handleUpgrade">立即更新</view></view> --></view></view>
</template><script>import {downloadApp,installApp} from './upgrade.js'export default {data() {return {isForceUpdate: false, //是否强制更新versionName: '', //版本名称versionDesc: '', //更新说明downloadUrl: '', //APP下载链接isDownloadFinish: false, //是否下载完成hasProgress: false, //是否能显示进度条currentPercent: 0, //当前下载百分比isStartDownload: false, //是否开始下载fileName: '', //下载后app本地路径名称}},computed: {//设置进度条样式,实时更新进度位置setProStyle() {return {width: (510 * this.currentPercent / 100) + 'rpx' //510:按钮进度条宽度}},//百分比文字percentText() {let percent = this.currentPercent;if (typeof percent !== 'number' || isNaN(percent)) return '下载中...'if (percent < 100) return `下载中${percent}%`return '立即安装'}},onLoad() {this.init()},onBackPress(options) {// 禁用返回if (options.from == 'backbutton') {return true;}},methods: {//初始化获取最新APP版本信息init() {//模拟接口获取setTimeout(() => {//演示数据请根据实际修改this.versionName = 'V1.2.0'; //版本名称this.versionDesc = "修复若干bug"; //更新说明this.downloadUrl = 'http://*.*.*.*:8080/app/download'; //下载链接this.isForceUpdate = false; //是否强制更新}, 200)},//更新handleUpgrade() {if (this.downloadUrl) {this.isStartDownload = true//开始下载AppdownloadApp(this.downloadUrl, current => {//下载进度监听this.hasProgress = truethis.currentPercent = current}).then(fileName => {//下载完成this.isDownloadFinish = truethis.fileName = fileNameif (fileName) {//自动安装Appthis.handleInstallApp()}}).catch(e => {console.log(e, 'e')})} else {uni.showToast({title: '下载链接不存在',icon: 'none'})}},//安装apphandleInstallApp() {//下载完成才能安装,防止下载过程中点击if (this.isDownloadFinish && this.fileName) {installApp(this.fileName, () => {//安装成功,关闭升级弹窗uni.navigateBack()})}},//关闭返回handleClose() {uni.navigateBack()},}}
</script><style>page {background: rgba(0, 0, 0, 0.5);/**设置窗口背景半透明*/}
</style>
<style lang="scss" scoped>.upgrade-popup {width: 580rpx;height: auto;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);background: #fff;border-radius: 20rpx;box-sizing: border-box;border: 1px solid #eee;}.header-bg {width: 100%;margin-top: -112rpx;}.main {padding: 10rpx 30rpx 30rpx;box-sizing: border-box;.version {font-size: 36rpx;color: #026DF7;font-weight: 700;width: 100%;text-align: center;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;letter-spacing: 1px;}.content {margin-top: 60rpx;.title {font-size: 28rpx;font-weight: 700;color: #000000;}.desc {box-sizing: border-box;margin-top: 20rpx;font-size: 28rpx;color: #6A6A6A;max-height: 80vh;overflow-y: auto;}}.footer {width: 100%;display: flex;justify-content: center;align-items: center;position: relative;flex-shrink: 0;margin-top: 100rpx;.btn {width: 246rpx;display: flex;justify-content: center;align-items: center;position: relative;z-index: 999;height: 96rpx;box-sizing: border-box;font-size: 32rpx;border-radius: 10rpx;letter-spacing: 2rpx;&.force {width: 500rpx;}&.close {border: 1px solid #E0E0E0;margin-right: 25rpx;color: #000;}&.upgrade {background-color: #026DF7;color: white;}}.progress-view {width: 510rpx;height: 90rpx;display: flex;position: relative;align-items: center;border-radius: 6rpx;background-color: #dcdcdc;display: flex;justify-content: flex-start;padding: 0px;box-sizing: border-box;border: none;overflow: hidden;&.active {background-color: #026DF7;}.progress {height: 100%;background-color: #026DF7;padding: 0px;box-sizing: border-box;border: none;border-top-left-radius: 10rpx;border-bottom-left-radius: 10rpx;}.txt {font-size: 28rpx;position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);color: #fff;}}}}
</style>
upgrade.js
/*** @description H5+下载App* @param downloadUrl:App下载链接* @param progressCallBack:下载进度回调*/
export const downloadApp = (downloadUrl, progressCallBack = () => {}, ) => {return new Promise((resolve, reject) => {//创建下载任务const downloadTask = plus.downloader.createDownload(downloadUrl, {method: "GET"}, (task, status) => {console.log(status,'status')if (status == 200) { //下载成功resolve(task.filename)} else {reject('fail')uni.showToast({title: '下载失败',duration: 1500,icon: "none"});}})//监听下载过程downloadTask.addEventListener("statechanged", (task, status) => {switch (task.state) {case 1: // 开始 break;case 2: //已连接到服务器 break;case 3: // 已接收到数据 let hasProgress = task.totalSize && task.totalSize > 0 //是否能获取到App大小if (hasProgress) {let current = parseInt(100 * task.downloadedSize / task.totalSize); //获取下载进度百分比progressCallBack(current)}break;case 4: // 下载完成 break;}});//开始执行下载downloadTask.start();})}
/*** @description H5+安装APP* @param fileName:app文件名* @param callBack:安装成功回调*/
export const installApp = (fileName, callBack = () => {}) => {//注册广播监听app安装情况onInstallListening(callBack);//开始安装plus.runtime.install(plus.io.convertLocalFileSystemURL(fileName), {}, () => {//成功跳转到安装界面}, function(error) {uni.showToast({title: '安装失败',duration: 1500,icon: "none"});})}
/*** @description 注册广播监听APP是否安装成功* @param callBack:安装成功回调函数*/
const onInstallListening = (callBack = () => {}) => {let mainActivity = plus.android.runtimeMainActivity(); //获取activity//生成广播接收器let receiver = plus.android.implements('io.dcloud.android.content.BroadcastReceiver', {onReceive: (context, intent) => { //接收广播回调 plus.android.importClass(intent);mainActivity.unregisterReceiver(receiver); //取消监听callBack()}});let IntentFilter = plus.android.importClass('android.content.IntentFilter');let Intent = plus.android.importClass('android.content.Intent');let filter = new IntentFilter();filter.addAction(Intent.ACTION_PACKAGE_ADDED); //监听APP安装 filter.addDataScheme("package");mainActivity.registerReceiver(receiver, filter); //注册广播}
4.后端下载接口去指定目录下载apk
@GetMapping("/download")public void download(String path, HttpServletResponse response) {try {//拿到最新的版本//SysAppVersion 是我自己表的实体,我每次上传后会在这个表里插入一条记录//下载的时候拿最新的SysAppVersion newestVersion = sysAppVersionService.getNewestVersion();File file = new File("d://app//"+newestVersion.getFileName());String filename = file.getName();String ext = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();FileInputStream fileInputStream = new FileInputStream(file);InputStream fis = new BufferedInputStream(fileInputStream);byte[] buffer = new byte[fis.available()];fis.read(buffer);fis.close();response.reset();// 设置response的Headerresponse.setCharacterEncoding("UTF-8");//Content-Disposition的作用:告知浏览器以何种方式显示响应返回的文件,用浏览器打开还是以附件的形式下载到本地保存//attachment表示以附件方式下载 inline表示在线打开 "Content-Disposition: inline; filename=文件名.mp3"// filename表示文件的默认名称,因为网络传输只支持URL编码的相关支付,因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));// 告知浏览器文件的大小response.addHeader("Content-Length", "" + file.length());OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());response.setContentType("application/octet-stream");outputStream.write(buffer);outputStream.flush();} catch (IOException ex) {ex.printStackTrace();}}
结束,非常简单,以上代码cv即用。
相关文章:
uniapp:实现手机端APP登录强制更新,从本地服务器下载新的apk更新,并使用WebSocket,实时强制在线用户更新
实现登录即更新,或实时监听更新 本文介绍的是在App打开启动的时候调用更新,点击下方链接,查看使用WebSocket实现实时通知在线用户更新。 uniapp:全局消息是推送,实现app在线更新,WebSocket,ap…...
设计循环队列——oj题622
. 个人主页:晓风飞 专栏:LeetCode刷题|数据结构|Linux 路漫漫其修远兮,吾将上下而求索 文章目录 题目要求:应该支持如下操作:示例:提示: 结构体定义队列的创建基本操作判断队列是否为空…...
阿里后端实习一面面经
阿里后端实习一面面经 项目中使用到了es,es的作用? elasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容 es中的重要概念? 群集:一个或多个节点…...
element-ui组件DatePicker日期选择器移动端兼容
element-ui组件DatePicker日期选择器移动端兼容 css /** 移动端展示 **/ media screen and (max-width: 500px) {.el-picker-panel__sidebar {width: 100%;}.el-picker-panel {width: 400px!important;}.el-picker-panel__content {width: 100%;}.el-picker-panel__body{marg…...
burpsuite 爆破
靶场搭建:phpstudy的安装与靶场搭建 - junlin623 - 博客园 (cnblogs.com) 账号字典:XXTK: 一些弱口令、fuzz字典 (gitee.com) 网盘链接:https://pan.baidu.com/s/1v5pAwaTwoeCnJgkUXf3iLQ?pwd=mllm 提取码:mllm --来自百度网盘超级会员V2的分享 一、暴力破解 - 基于…...
SparkSQL基础解析(三)
1、 Spark SQL概述 1.1什么是Spark SQL Spark SQL是Spark用来处理结构化数据的一个模块,它提供了2个编程抽象:DataFrame和 DataSet,并且作为分布式SQL查询引擎的作用。 我们已经学习了Hive,它是将Hive SQL转换成MapReduce然后提…...
gz-hamonic 安装提示缺少许多依赖无法安装
在软件更新源中增加gz-hamonic的软件源, 点击添加,在输入框中填入如下语句: deb http://packages.osrfoundation.org/ubuntu jammy main 如图所示: 然后执行 sudo apt -get install gz-hamonic即可安装。 如下图 在终端中输入…...
新版Edge卸载
新版Edge卸载:步骤与注意事项 随着Windows 10的发布,微软推出了新版Edge浏览器。虽然新版Edge浏览器具有许多优秀的新功能和改进,但有时您可能希望卸载它并使用其他浏览器。在本文中,我们将向您介绍如何卸载新版Edge浏览器&#…...
Ansibe自动化基础
目录 一.Ansibe自动化概述 1.特点 2.工作特性 3.应用场合 二.ansibe安装即相关文件说明 1.安装 2.相关文件 3.主配置文件内容详解 4.ansibe运行机制 三.ansibe管理节点命令 1.Ansibe 四.主机组配置 1.基本配置 第一种: 第二种: 2.设置SSH…...
2023 年中国高校大数据挑战赛赛题B DNA 存储中的序列聚类与比对-解析与参考代码
题目背景:目前往往需要对测序后的序列进行聚类与比对。其中聚类指的是将测序序列聚类以判断原始序列有多少条,聚类后相同类的序列定义为一个簇。比对则是指在聚类基础上对一个簇内的序列进行比对进而输出一条最有 可能的正确序列。通过聚类与比对将会极大…...
决策树--分类决策树
1、介绍 ① 定义 分类决策树通过树形结构来模拟决策过程,决策树由结点和有向边组成。结点有两种类型:内部结 点和叶结点。内部结点表示一个特征或属性,叶子节点表示一个类。 ② 生成过程 用决策树分类,从根结点开始ÿ…...
【2024/1/5】
2024/1/5周报 本周开展工作下周工作计划 本周开展工作 首先的话就是跟大家汇报一下上一个项目的进度,那因为一些我这边的不可控的因素暂时进行搁置,随后的话还是需要在进行做的。 因此我们最近在做一个web端的项目,这个项目的具体的就不汇报…...
CNN——VGG
1.VGG简介 论文下载地址:https://arxiv.org/pdf/1409.1556.pdf VGGNet 是由牛津大学视觉几何小组(Visual Geometry Group, VGG)提出的一种深层卷积网络结构,他们以 7.32% 的错误率赢得了 2014 年 ILSVRC 分类任务的亚军ÿ…...
深入理解Java中的多线程编程与并发控制
当谈论到 Java 编程语言时,多线程编程和并发控制是其中最重要的话题之一。Java 在多线程领域有着强大的支持和丰富的工具集,允许开发人员利用并发性来提高程序性能和效率。本文将深入探讨 Java 中的多线程编程和并发控制,包括线程的创建、同步…...
提供10个mysql的实例和思路
学生信息管理系统 学生表(id, name, gender, age, class_id)班级表(id, name)思路:通过学生表和班级表进行关联,可以实现学生信息的查询、添加、修改、删除等操作。 订单管理系统 订单表(id, us…...
FPGA项目(14)——基于FPGA的数字秒表设计
1.功能设计 设计内容及要求: 1.秒表最大计时范围为99分59. 99秒 2.6位数码管显示,分辨率为0.01秒 3.具有清零、启动计时、暂停及继续计时等功能 4.控制操作按键不超过二个。 2.设计思路 所采用的时钟为50M,先对时钟进行分频,得到100HZ频率…...
浅谈指数移动平均(ema)
经常在各种代码中看到指数移动平均(比如我专注的网络传输领域),但却不曾想到它就是诠释世界的方法,我们每个人都在被这种方式 “平均”… 今天说说指数移动平均(或移动指数平均,Exponential Moving Average)。 能查到的资料都侧重于其数学形…...
1-并发编程线程基础
什么是线程 在讨论什么是线程前有必要先说下什么是进程,因为线程是进程中的一个实体,线程本身是不会独立存在的。 进程是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,线程则是进程的一个执行路径&#…...
vue中动态出来返回的时间秒数,在多少范围显示多少秒,多少范围显示分,小时等等
在Vue中,你可以使用计算属性(computed property)或过滤器(filter)来根据动态返回的时间秒数来显示不同的时间单位,比如秒、分、小时等等。 下面是一个使用计算属性的示例: <template>&l…...
English: go through customs
文章目录 常见单词机场指示登机和中转降落以及公共服务签证篇出/入境卡篇入境英语会话篇 常见单词 customs: 海关 (kʌstəmz)cash: 现金 (kʃ)passport: 护照 (pspɔːt)luggage/baggage: 行李 (lʌɡɪdʒ/ˈbɡɪdʒ)Exchange: 换钱 (ɪks’tʃeɪndʒ)airport: 飞机场 (ɛ…...
Nginx 多端口部署多站点
目录 1.进行nginx.conf 2.复制粘贴 3.修改端口及站点根目录 4. 网站上传 1.进行nginx.conf 在 nginx 主要配置文件 nginx.conf 中,server 是负责一个网站配置的,我们想要多个端口访问的话,可以复制多个 server 先进入到 nginx.conf 中 …...
从零开始配置kali2023环境:配置jupyter的多内核环境
在kali2023上面尝试用anaconda3,anaconda2安装实现配置jupyter的多内核环境时出现各种问题,现在可以通过镜像方式解决 1. 搜索镜像 ┌──(holyeyes㉿kali2023)-[~] └─$ sudo docker search anaconda ┌──(holyeyes㉿kali2023)-[~] └─$ sudo …...
Dart调用JS对10000条定位数据滤波
使用Dart调用JS,还是为了练习跨语言调用; 一、编写对应的JS代码 平时在开发时不推荐将算法放在JS里,我这里是简单的做一下数据过滤; 首先生成一些随机定位数据,在实际开发中可以使用真实数据; // 随机定…...
大模型应用实践:AIGC探索之旅
随着OpenAI推出ChatGPT,AIGC迎来了前所未有的发展机遇。大模型技术已经不仅仅是技术趋势,而是深刻地塑造着我们交流、工作和思考的方式。 本文介绍了笔者理解的大模型和AIGC的密切联系,从历史沿革到实际应用案例,再到面临的技术挑…...
【.NET Core】异步编程模式
【.NET Core】异步编程模式 文章目录 【.NET Core】异步编程模式一、概述二、基于任务的异步模式(TAP)2.1 TAP模式命名、参数和返回类型2.2 TAP初始化异步操2.3 TAP如何编译2.4 手动生成TAP方法2.5 混合方法实现TAP2.6 TAP中Await挂起执行2.7 TAP中使用Y…...
macOS通过外置驱动器备份数据
通过外置驱动器备份数据(谨慎操作) 1.将外置驱动器连接到您的 Mac。驱动器容量应等于或大于您当前的启动磁盘。驱动器还应该是您可以抹掉的。 2.使用 macOS 恢复功能 抹掉外置驱动器,然后将 macOS 安装 到外置驱动器上。确保您选择的外置驱动…...
rtsp解析视频流
这里先说一下 播放rtsp 视频流,尽量让后端转换一下其他格式的流进行播放。因为rtsp的流需要flash支持,现在很多浏览器不支持flash。 先说一下这里我没有用video-player插件,因为它需要用flash ,在一个是我下载flash后,还是无法播放…...
【物联网】手把手完整实现STM32+ESP8266+MQTT+阿里云+APP应用——第3节-云产品流转配置
🌟博主领域:嵌入式领域&人工智能&软件开发 本节目标:本节目标是进行云产品流转配置为后面实际的手机APP的接入做铺垫。云产品流转配置的目的是为了后面能够让后面实际做出来的手机APP可以控制STM32/MCU,STM32/MCU可以将数…...
Spring Cloud Config相关问题及答案(2024)
1、什么是 Spring Cloud Config,它解决了哪些问题? Spring Cloud Config 是一个为微服务架构提供集中化外部配置支持的项目。它是构建在 Spring Cloud 生态系统之上,利用 Spring Boot 的开发便利性,简化了分布式系统中的配置管理…...
【Azure 架构师学习笔记】- Azure Databricks (4) - 使用Azure Key Vault 管理ADB Secret
本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Databricks】系列。 接上文 【Azure 架构师学习笔记】- Azure Databricks (3) - 再次认识DataBricks 前言 Azure Databricks有access token,是具有ADB内部最高权限的token。在云环境中这些高级别权限的sec…...
python一句做网站/外贸推广方式都有哪些
集群流控 我们已经知道如何为应用接入限流了,但是到目前为止,这些还只是在单机应用中生效。也就是说,假如你的应用有多个实例,那么你设置了限流的规则之后,每一台应用的实例都会生效相同的流控规则,如下图…...
中国建设银行培训网站/网络推广软件免费
文章目录1、新建xcs格式文本2、打开xshell,导入配置文件3、配色方案效果图1、新建xcs格式文本 [skycolor] text00ff80 cyan(bold)00ffff text(bold)e9e9e9 magentac000c0 green80ff00 green(bold)3c5a38 background042028 cyan00c0c0 red(bold)ff0000 yellowc0c000…...
陕西手机网站建站/网站seo方案
国庆期间闲来无事,写了一个简单的小程序,小程序名称叫做 IT藏经楼。目的是分享这些年自己积累的一些学习材料,方面大家查找使用,包括电子书、案例项目、学习视频、面试题和一些PPT模板。里面所有材料都免费分享。目前小程序中只发…...
辽阳市城市建设档案馆网站/seo零基础视频教程
转载于:https://www.cnblogs.com/wang715100018066/p/10368812.html...
wordpress修改教程视频/cba目前排行
最近一个月比较累,十月居然没有写任何的文章。一方面是家事比较多,另一方面是工作比较忙,也在方法积累期。现在就结合这段时间的工作总结一下经验。前面学习的软件架构等等,都是属于纯粹的技术设计。这段时间的工作很多是属于前期…...
wordpress文章关键词插件/免费友情链接平台
#include<iostream> using namespace std;//对""运算符重载,实现两个复数的相加 class Complex {public:Complex() //定义无参构造函数 {real0;imag0;}Complex(double r,double i):real(r),imag(i){}; //定义有参构造函数(构造函数重载&…...