乾坤微服务的使用

前言:

        在这里整理下用乾坤来开发微服务的一些资料。

使用好处:

        使用乾坤可以实现什么效果呢?众所周知,前端的框架五花八门,react/vue/angular等各领风骚,那么如果我们有需要把不同技术栈的项目整合起来,应该怎么去做呢?如果统一技术栈进行开发,工作量太大,成本也高,那还能怎么做呢?没错,这就是我们乾坤技术出来的由来,可以通过他把不同的项目进行一个融会贯通,让他们可以实现亲密的联系,又能各自发展。

乾坤的官网地址:点我

乾坤的逻辑流程:

如何去使用:

1、安装
yarn add qiankun
npm i qiankun -S 
2、主应用的main.js
// (1)导入乾坤框架
import { registerMicroApps, start } from "qiankun";
// (2)注册乾坤子应用
registerMicroApps([{name:"sub-application01", //子应用名称entry:"//localhost:8001", //子应用入库地址container:"#container", //主应用容器activeRule:"/sub-application01", //主应用路由匹配规则props:{token:"sub-application-001"} //主应用传递参数},// {//   name:"sub-application02",//   entry:"//localhost:8002",//   container:"#container",//   activeRule:"/sub-application02",//   props:{//     token:"sub-application-002"//   }// }
]);//(3)开启乾坤
start();
3、主应用的配置  initGlobalState(state)
  • 参数
  • state - Record<string, any> - 必选
  • 用法定义全局状态,并返回通信方法,建议在主应用使用,微应用通过 props 获取通信方法
import { initGlobalState } from 'qiankun';// 跨应用共享状态
const initialState = {hasCallPhone: false, // 是否拨打电话outsidePhone: '', // 外部电话号码isLocal: true, // 是否是本地号码channelId: '', // 渠道leadsId: '',hasSendMsg: false, // 是否发送短信maSend: {}, // MA的leadsId,channelIdhasSendEmail: false, // 是否发送邮件contactHistory: false, // 是否展示联系历史customerId: '', // 联系历史需要的id,newDict: false, // 是否新增字典addDictId: '', // 传入字典idcallDetails: false, // 是否展示通话详情channelSessionId: '', // 通话详情需要的idurgentObj: null, // 获取紧急程度socketCallback: null,taskList: [],isCustomerEdit: false, // 是否可以编辑客户trendsLayout: [], // 客户表单dynamicFields: [], // 动态字段fixedFieldsComponent: [], // 固定字段operateType: '', // 操作方式,是新增还是编辑callerName: '', // 主叫号人员名称calledName: '', // 被叫号人员名称roomNumber: '', // csp呼叫房间softPhone: {curOperate: '', // 呼叫状态hasSipConnected: false, // 电话连接状态mediaAvailabled: false, // 音频媒体webrtcConfig: {}, // 初始化连接webrtc配置},imPageNoticeInfo: {}, // 内部聊天页面通知相关数据iqcPageNoticeInfo: {}, // 内部支持页面通知相关数据reconnectCallback: null, // 内部支持断网重连回调reconnectImCallback: null, // IMcallVoiceCallback: null,callVoiceInfo: {},goConversation: false, // 通讯录跳转
};
const actions = initGlobalState(initialState);export default actions;
4、主应用中手动加载微应用的方式:
import { loadMicroApp } from 'qiankun';
let leftMicroApp = null;方法内部:
leftMicroApp = loadMicroApp({name: 'crm_core',entry: '//localhost:9011',container: '#wrapper__right',props: {path: 'customerTabs',},
});//组件销毁,调用子应用的 unmount方法
destroyed() {leftMicroApp.unmount()
},
5、子应用中
1、新建文件:public-path.ts/ public-path. js
/* eslint-disable camelcase */
if (window.__POWERED_BY_QIANKUN__) {__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
2、main.ts/main.js
import './core/public-path'// vue3中写法
const __qiankun__ = window.__POWERED_BY_QIANKUN__
__qiankun__ || render()// vue2中写法
//创建子应用渲染函数
function render(props = {}) {const { container } = props;router = new VueRouter({base: window.__POWERED_BY_QIANKUN__ ? '/app-vue/' : '/',mode: 'history',routes,});instance = new Vue({router,render: (h) => h(App),}).$mount(container ? container.querySelector('#app') : '#app');
};// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {render();
};
3、打包配置,vue.config.js
configureWebpack: {output: {library: `${name}-[name]`,libraryTarget: 'umd', // 把微应用打包成 umd 库格式jsonpFunction: `webpackJsonp_${name}`, filename: 'static/js/[hash:8].bundle.js'},},
6、微应用不需要额外安装任何其他依赖即可接入 qiankun 主应用。

微应用需要在自己的入口 js (通常就是你配置的 webpack 的 entry js) 导出 bootstrap、mount、unmount 三个生命周期钩子,以供主应用在适当的时机调用。

生命周期钩子封装

/*** bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。* 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。*/
export async function bootstrap() {console.log('react app bootstraped');
}
/*** 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法*/
export async function mount(props) {}/*** 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例*/
export async function unmount(props) {}/*** 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效*/
export async function update(props) {console.log('update props', props);
}

个人项目中用法:

main.ts

import './core/public-path'
import { lifeCycle, render } from './core/life-cycle'const { bootstrap, mount, unmount } = lifeCycle()
export { bootstrap, mount, unmount }const __qiankun__ = window.__POWERED_BY_QIANKUN__
__qiankun__ || render()

life-cycle.ts

...
/*** 微应用生命周期*/
const lifeCycle = (): { [key: string]: (props?: qkProps) => Promise<void> } => {return {async bootstrap(props) {console.log(`bootstrap props: ${props}`);},async mount(props) {console.log(`mount props: ${props}`);if (props) {// 生成动态路由const availRoutes = assyAvailRoutes(props.menuLists, 1, "", APP_NAME);// 扁平化菜单树const flatMenus = flatMenuTree(props.menuLists);// 将菜单树、动态路由、扁平菜单树存入全局状态中store.commit("user/SET_MENUS", { menuLists: props.menuLists, availRoutes, flatMenus });// 将角色列表存入全局状态中store.commit("user/SET_ROLES", props.roles);store.commit("user/SET_USERINFO", props.userInfo);const routes = selfRoutes.concat(availRoutes);props.routes = routes;store.commit("chat/SET_SINGLE_CONFIG_EVO", []);// 如果开启内部聊天语音通话时获取有没有语音聊天权限if (matchFuncConfig("INTERNALCHAT_SOFTPHONE_ACTIVE") && store.state.chat.singleConfigEvo.length === 0) {getSingleMyConfigs();}// props.functions.sendOrder({//   message: {//     type: 'typing',//     sendUserId: '',//     groupType: ''//   }// });actions.setActions(props);actions.setGlobalState({socketCallback: (data: any, extraParams: any) => {store.commit("chat/SET_SOCKET_MAINAPP_PARAMS", extraParams);const { namespace } = extraParams;// 接收到父应用分发的消息,进行处理if (namespace === "im") {if (data.type === spm.ON_PING) {imDispatchMessage({ messageType: cmd.SOCKET_PING });} else {imDispatchMessage({messageType: enumMsg[data.messageType],message: data.message,});}}if (namespace === "iqc") {if (data.type === spm.ON_PING) {iqcDispatchMessage({ messageType: cmd.SOCKET_PING });} else {iqcDispatchMessage({messageType: enumMsg[data.messageType],message: data.message,});}}},// 断网重连回调reconnectCallback: () => {store.commit("internal/SET_RECONNECTED_COUNT");},// 断网重连回调reconnectImCallback: (networkStatus:string) => {utilHelper.handleDisconnectOrOnreconnected(networkStatus)console.log('##################执行reconnectImCallback',networkStatus);},});}await render(props);},async unmount() {// 关闭所有的页面通知实例const { pageNoticeInstances = {} } = store.state.chat;const instanceKeys = Object.keys(pageNoticeInstances);forEach(instanceKeys, (key) => {const notifyInstance = pageNoticeInstances[key];notifyInstance.close();});console.log("unmount props");instance.unmount();instance = null;router = null;},async update(props) {console.log(`update props: ${props}`);},};
};async function render(props?: qkProps): Promise<void> {let basePath = "";// 如果是生产环境if (process.env.NODE_DEV === "production") {// 如果是子应用,使用二级域名前缀,反之使用带internalPortal三级域名basePath = __qiankun__ ? `/${APP_NAME}` : `/internalPortal/${APP_KEY}/`;} else {// 如果非生产环境,并且不是子应用,basePath = __qiankun__ ? `/${APP_NAME}` : "/";}// 初始化固定路由let routes = selfRoutes;if (__qiankun__) {// 如果是微应用,则使用主应用传递的路由集合if (props?.routes) routes = props?.routes;} else if (store.state.user.accessToken) {// 如果没有授权令牌// 请求菜单树,非子应用时不控制权限const response: AxiosResponse = await axiosSingle(getCompleteTree(), false);if (response.data.length > 0) {// 获取当前子应用相关的菜单let menuLists = response.data[0].children.filter((item: IMenu) =>includes(["conversation", "organization"], item.i18n));// 递归生成菜单menuLists = recurseTree(menuLists, "");if (menuLists.length) {// 生成动态路由const availRoutes = assyAvailRoutes(menuLists, 1, "", APP_NAME);// 扁平化菜单树const flatMenus = flatMenuTree(menuLists);// 将菜单树、动态路由、扁平菜单树存入全局状态中store.commit("user/SET_MENUS", { menuLists, availRoutes, flatMenus });// 叠加固定路由和动态路由// routes = selfRoutes.concat(availRoutes)selfRoutes[0].children = availRoutes;routes = selfRoutes;}}}router = createRouter({history: createMemoryHistory(basePath),routes,});instance = createApp(App).use(router).use(store).use(i18n).use(plugin, { imports: [] });// 全局注册El组件components.forEach((item) => {if (item) instance.use(item);});// 全量导入El图标for (const key in Icons) {if (Reflect.has(Icons, key)) {instance.component(key, Icons[key]);}}// 注册按钮授权指令instance.use(authDirective);// 注册按钮授权全局方法instance.config.globalProperties.$vAuth = function (key: any) {return directiveAuth(this, key);};instance.use(draggable);instance.mount(props?.container ? props.container.querySelector("#appInternalChat") : "#appInternalChat");// instance.use(VueVirtualScroller);// instance.component('DynamicScroller', VueVirtualScroller.DynamicScroller)// 前置路由守卫router.beforeEach(async (to: any, from: any) => {if (!__qiankun__) {// 1 如果不是子应用if (store.state.user.accessToken) {if (!store.state.user.userInfo) {const infoConfig = configRequest(`${GlobalConfig.API_HRMS_URL}/employee/current`, httpMethod.GET);const response1 = await axiosSingle(infoConfig);const userInfo = response1.data;store.commit("user/SET_USERINFO", userInfo);// 1.1 如果有授权令牌if (to.path === "/login") {// 1.1.1 如果访问页面为登录页,则跳转到首页return "/";} else if (to.matched.length) {// 1.1.2 如果有匹配的路由,则进行跳转return true;} else {// 1.1.3 如果找不到匹配路由,则跳转到未授权报错页面// next({ path: '/403', replace: true })return false;}}} else if (to.path === "/login" && to.query.code) {// 1.2 如果没有令牌并跳转到登录页,并有授权码return true;} else {// 如果没有令牌并且没有授权码,则跳转到sso进行登录signIn();}} else if (to.matched.length) {// 2 如果是子应用,并且有匹配的路由,则进行跳转return true;} else {// 3 如果没有匹配路由,则跳转到未授权报错页面// next({ path: '/403', replace: true })return false;}});
}export { lifeCycle, render };

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/362841.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue3学习笔记<->创建第一个vue项目

新建一个项目目录 找一个盘新建一个目录&#xff0c;我这里在D盘创建一个vuedemo目录作为项目存放的目录。使用idea打开目录。   单击ieda底部的按钮“Terminal”&#xff0c;打开命令行窗口&#xff0c;如果命令行窗口当前目录不是“vuedemo”&#xff0c;就切换到“vuedem…

文本分类-RNN-LSTM

1.前言 本节介绍RNN和LSTM&#xff0c;并采用它们在电影评论数据集上实现文本分类&#xff0c;会涉及以下几个知识点。 1. 词表构建&#xff1a;包括数据清洗&#xff0c;词频统计&#xff0c;词频截断&#xff0c;词表构建。 2. 预训练词向量应用&#xff1a;下载并加载Glove的…

Vue2 - 首页登录实现随机验证码组件的封装与实现详解(详细的注释及常见问题汇总)

在网站首页等登录时,随机验证码在现代网络应用中扮演着重要的安全角色。为了帮助开发者轻松集成和使用随机验证码功能,本文将介绍如何利用 Vue.js 2 封装一个简单而功能强大的随机验证码组件。让你能够快速理解并应用这一组件到你的项目中。 一、解决方案 本文提供了完美便捷…

上海计算机考研避雷,25考研慎报

上大计算机一直很热 408考研er重来没有让我失望过&#xff0c;现在上大的专业课是11408&#xff0c;按理说&#xff0c;这个专业课的难度是很高的&#xff0c;但是408er给卷出了新高度&#xff0c;大家可以去上大官网看看今年最新的数据&#xff0c;我也帮大家统计了24年最新的…

Redis集群(Clustering in Redis)工作机制详解

Redis集群工作机制详解 Redis 集群是用于提高 Redis 可扩展性和高可用性的解决方案。 维基百科&#xff1a;Scalability is the property of a system to handle a growing amount of work by adding resources to the system. 可扩展性是系统的一种允许通过增加系统资源来处…

《Windows API每日一练》6.4 程序测试

前面我们讨论了鼠标的一些基础知识&#xff0c;本节我们将通过一些实例来讲解鼠标消息的不同处理方式。 本节必须掌握的知识点&#xff1a; 第36练&#xff1a;鼠标击中测试1 第37练&#xff1a;鼠标击中测试2—增加键盘接口 第38练&#xff1a;鼠标击中测试3—子窗口 第39练&…

Linux Static calls机制

文章目录 前言一、简介二、Background: indirect calls, Spectre, and retpolines2.1 Indirect calls2.2 Spectre (v2)2.3 RetpolinesConsequences 2.4 Static callsHow it works 三、其他参考资料 前言 Linux内核5.10内核版本引入新特性&#xff1a;Static calls。 Static c…

计算机毕业设计hadoop+spark+hive知识图谱医生推荐系统 医生数据分析可视化大屏 医生爬虫 医疗可视化 医生大数据 机器学习 大数据毕业设计

测试过程及结果 本次对于医生推荐系统测试通过手动测试的方式共进行了两轮测试。 &#xff08;1&#xff09;第一轮测试中执行了个20个测试用例&#xff0c;通过16个&#xff0c;失败4个&#xff0c;其中属于严重缺陷的1个&#xff0c;属于一般缺陷的3个。 &#xff08;2&am…

Spark SQL 的总体工作流程

Spark SQL 是 Apache Spark 的一个模块,它提供了处理结构化和半结构化数据的能力。通过 Spark SQL,用户可以使用 SQL 语言或 DataFrame API 来执行数据查询和分析。这个模块允许开发者将 SQL 查询与 Spark 的数据处理能力结合起来,实现高效、优化的数据处理。下面是 Spark S…

Spring Boot中实现定时任务最常用的方法 @Scheduled 注解和 TaskScheduler 接口【包含详情代码】

Spring Boot中实现定时任务最常用的方法 Scheduled 注解和 TaskScheduler 接口【包含详情代码】 学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把手教你开发炫酷的vbs脚本制作(完善中………

CogMG:用大模型解决知识图谱覆盖不足的问题

CogMG&#xff1a;用大模型解决知识图谱覆盖不足的问题 提出背景知识图谱的作用知识覆盖不完整知识更新不对齐 显式分解知识三元组和补全检索增强生成&#xff08;RAG&#xff09;和知识更新 框架设计1. 查询知识图谱2. 处理结果3. 知识图谱演化 CogMG 实现3.1 模型和组件问题分…

.NET 漏洞分析 | 某ERP系统存在SQL注入

01阅读须知 此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失&#xf…

c++智能指针shared_ptr

文章目录 概念1.shared_ptr1.基本使用2.如何获取原始指针3. 指定删除器 2 使用shared_ptr要注意的问题2.1不要用一个原始指针初始化多个shared_ptr2.2. 避免循环引用 小结 概念 C程序设计中使用堆内存是非常频繁的操作&#xff0c;堆内存的申请和释放都由程序员自己管理。内存…

安装 Docker 环境(通过云平台创建一个实例实现)

目录 1. 删除原有 yum 2. 手动配置 yum 源 3. 删除防火墙规则 4. 保存防火墙配置 5. 修改系统内核。打开内核转发功能。 6. 安装 Docker 7. 设置本地镜像仓库 8.重启服务 1. 删除原有 yum rm -rfv /etc/yum.repos.d/* 2. 手动配置 yum 源 使用 centos7-1511.iso 和 Xi…

Python 语法基础二

7.常用内置函数 执行这个命令可以查看所有内置函数和内置对象&#xff08;两个下划线&#xff09; >>>dir(__builtins__) [__class__, __contains__, __delattr__, __delitem__, __dir__, __doc__, __eq__, __format__, __ge__, __getattribute__, __getitem__, __gt…

深入剖析 Android 网络开源库 Retrofit 的源码详解

文章目录 概述一、Retrofit 简介Android主流网络请求库 二、Retrofit 源码剖析1. Retrofit 网络请求过程2. Retrofit 实例构建2.1 Retrofit.java2.2 Retrofit.Builder()2.2.1 Platform.get()2.2.2 Android 平台 2.3 Retrofit.Builder().baseUrl()2.4 Retrofit.Builder.client()…

OpenAI穿着「皇帝的新衣」;扒了数万条帖子汇总100种AIGC玩法;北美出海的财务避坑指南;我创业「如」有CTO | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; 1. 我扒了 Reddit 论坛数万条帖子&#xff0c;汇总了 GenAI 的 100 种玩法 ChatGPT 已经问世一年半了。这期间诞生了很多大语言模型和生成式人工智能…

备份和还原

stai和dnta snat&#xff1a;源地址转换 内网---外网 内网ip转换成可以访问外网的ip 内网的多个主机可以使用一个有效的公网ip地址访问外部网络 DNAT&#xff1a;目的地址转发 外部用户&#xff0c;可以通过一个公网地址访问服务内部的私网服务。 私网的ip和公网ip做一个…

【JavaEE进阶】Spring AOP使用篇

目录 1.AOP概述 2.SpringAOP快速入门 2.1 引入AOP依赖 2.2 编写AOP程序 3. Spring AOP详解 3.1 Spring AOP 核心概念 3.1.1切点(Pointcut) 3.1.2 连接点 (Join Point) 3.1.3 通知(Advice) 3.1.4 切面(Aspect) 3.2 通知类型 3.3PointCut 3.4 切面优先级 3.5 切点表…

「51媒体」政企活动媒体宣发如何做?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体宣传加速季&#xff0c;100万补贴享不停&#xff0c;一手媒体资源&#xff0c;全国100城线下落地执行。详情请联系胡老师。 政企活动媒体宣发是一个系统性的过程&#xff0c;需要明确…