(以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点)

刘丽红

随着社会的进步与发展,科技手段的推陈出新,餐饮行业也在寻求新的突破与变革,手机扫描二维码点餐系统已经成为餐饮行业的未来趋势,发展空间巨大;扫码点餐,是“互联网+餐饮”潮流的产物,可以有效地为餐厅节省人力成本,提高顾客点餐用餐效率,节省顾客时间,提高餐厅翻台率。

但是,一些老年人也在面对扫码点餐时犯了难;还有些消费者不愿意使用扫码点餐,是担心个人信息泄露等安全问题。

如此,我们设计了一款分布式菜单应用,不需要个人去关注公众号或下载小程序,服务员会提供几个点单的平板,连接店铺网络,局域网内通信,这样大家点单、查看订单详情等都不受网络限制。先上效果:

润和 HiSpark Taurus AI Camera(Hi3516d)

润和大禹系列 HH-SCDAYU200 开发板

如上动图:可由一人拉起点单平板上的点单应用,大家可同时点单,点击菜品图片进入菜品详情页面,选择口味后确认,就是一次点单完成,并自动返回到菜单首页;此时可看到下方购物车数量和总额的变化,点击下方"点好了" 可进入订单详细,并通过分布式数据库让其他人也查看订单详情,从订单详情返回到点单页后,可再进行叠加点单。

下面是 Demo 的开发说明。

一、开发说明

基于 OpenAtom OpenHarmony(以下简称“OpenHarmony”) 3.1 beta 版本,并结合方舟开发框架(ArkUI)、分布式组网、分布式数据库等特性,使用 eTS 语言开发的一款分布式菜单应用;主要体现了 OpenHarmony 分布式数据库特性,根据设计师提供的 UX ,首先就要考虑分布式数据库应该要怎么设计,需要包含哪些元素;其次 demo 是没有后台服务端,结合 ArkUI 框架,需要思考多个页面间数据怎么传递。

Demo 主要包含菜单首页、菜单详情页和订单详情页,以及加入菜单分布式数据库和结算订单分布式数据库。三个页面都需要订单列表数据,因为目前 ArkUI 框架在 app.ets 定义数据,其他页面不能直接引用,所以通过 router.push 的方法,带上 param 的参数,将数据在页面间进行传递。

两个分布式数据库,一个是订单列表数据,订单列表需要根据 UX 提供的设计图,来确认数据库中的元素,本 Demo 中的订单页面数据信息其他包括菜品的信息(图片、名称、份数、辣度等)以及点单人的信息(图片、名称和点单的数量);另一个是将下单成功通知所有人。

Demo 也还有很多待完善的点,比如:点击加/减的图标进行菜单的加减、一键清空订单、以及 Demo 是否有更好的方案来达到更好的点单体验等等,期待更多的读者们来完善。

代码结构如下图:

├─entry
│ └─src
│ └─main
│ │ config.json // 应用配置文件
│ │
│ ├─ets
│ │ └─MainAbility
│ │ │ app.ets // 应用程序主入口
│ │ │
│ │ ├─model
│ │ │ CommonLog.ets // 日志类
│ │ │ MenuData.ets // 初始化菜单数据类
│ │ │ MenuListDistributedData.ets // 加入菜单分布式数据库
│ │ │ RemoteDeviceManager.ets // 分布式拉起设备管理类
│ │ │ SubmitData.ets // 结算订单分布式数据库
│ │ │
│ │ └─pages
│ │ detailedPage.ets // 菜品详细页面
│ │ index.ets // 首页
│ │ menuAccount.ets // 订单详情页面
│ │
│ └─resources
│ ├─base
│ │ ├─element
│ │ │ string.json
│ │ │
│ │ ├─graphic
│ │ ├─layout
│ │ ├─media // 存放媒体资源
│ │ │ icon.png
│ │ │ icon_add.png
│ │ │ icon_back.png
│ │ │ icon_cart.png

二、页面编写

2.1 点单首页

效果图如上,可以分为四部分:

1)顶部页标签

@Component
struct PageInfo {
build() {
Flex() {
Text('点单页')
.fontSize('36lpx')
}
.padding({ left: '48lpx', top: '28lpx' })
.width('100%')
.height('10%')
.backgroundColor('#FFFFFF')
}
}

2)用户信息

• 主要用到 Flex 容器 Image 和 Text 组件;

• 用户名称和头像图标,根据设备序列号不同,可展示不同的名称和图标;

• 点击右上角分享的小图标,可分布式拉起局域网内的另一台设备。

@Component
struct MemberInfo {
@Consume userImg: Resource
@Consume userName: string aboutToAppear() {
// 根据设备序列号不同,展示不同的名称和图标
CommonLog.info('==serial===' + deviceInfo.serial);
if (deviceInfo.serial == '150100384754463452061bba4c3d670b') {
this.userImg = $r("app.media.icon_user")
this.userName = 'Sunny'
}
else {
this.userImg = $r("app.media.icon_user_another")
this.userName = 'Jenny'
}
} build() {
Flex({ direction: FlexDirection.Column }) {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
Image(this.userImg)
.width('96lpx')
.height('96lpx')
.margin({ right: '18lpx' })
Text(this.userName)
.fontSize('36lpx')
.fontWeight(FontWeight.Bold)
.flexGrow(1)
Image($r("app.media.icon_share"))
.width('64lpx')
.height('64lpx')
}
// 打开分布式设备列表
.onClick(() => {
this.DeviceDialog.open()
})
.layoutWeight(1)
.padding({ left: '48lpx', right: '48lpx' }) Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
Column() {
Text('124')
.fontSize('40lpx')
.margin({ bottom: '24lpx' })
Text('积分')
.fontSize('22lpx')
.opacity(0.4)
}
.flexGrow(1) Column() {
Text('0')
.fontSize('40lpx')
.margin({ bottom: '24lpx' })
Text('优惠劵')
.fontSize('22lpx')
.opacity(0.4)
}
.flexGrow(1) Column() {
Image($r("app.media.icon_member"))
.width('48lpx')
.height('48lpx')
.margin({ bottom: '24lpx' })
Text('会员码')
.fontSize('22lpx')
.fontColor('#000000')
.opacity(0.4)
}
.flexGrow(1)
}
.layoutWeight(1)
}
.width('93%')
.height('25%')
.borderRadius('16lpx')
.backgroundColor('#FFFFFF')
.margin({ top: '24lpx', bottom: '32lpx' })
}
}

3)列表展示

• 主要用到 Flex 容器和 Scroll 容器 Image 和 Text 组件;

• 从首页点击列表进入菜品详细页面,点菜成功后会自动返回首页,此时列表需要动态更新菜品的数量。

@Component
struct MenuHome {
private specialty: any[]
private winterNew: any[]
private classic: any[]
private soup: any[]
private menuItems: MenuData[]
private titleList = ['招牌菜', '冬季新品', '下饭菜', '汤品']
@State name: string = '招牌菜' build() {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start }) {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceAround }) {
ForEach(this.titleList, item => {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Start }) {
Text(item)
.fontSize('24lpx')
}
.padding({ left: '24lpx' })
.backgroundColor(this.name == item ? '#1A006A3A' : '#FFFFFF')
.height('160lpx')
.onClick(() => {
this.name = item
if (this.name == '招牌菜') {
this.menuItems = initializeOnStartup(this.specialty);
}
else if (this.name == '冬季新品') {
this.menuItems = initializeOnStartup(this.winterNew);
}
else if (this.name == '下饭菜') {
this.menuItems = initializeOnStartup(this.classic);
}
else if (this.name == '汤品') {
this.menuItems = initializeOnStartup(this.soup);
}
})
}, item => item)
}
.width('20%')
.backgroundColor('#FFFFFF') Flex({ direction: FlexDirection.Column }) {
Text(this.name)
.fontSize('32lpx')
.fontWeight(FontWeight.Bold)
.opacity(0.4)
.height('8%')
Scroll() {
Column() {
List() {
ForEach(this.menuItems, item => {
ListItem() {
MenuListItem({ menuItem: item })
}
}, item => item.id.toString())
}
}
}
.height('92%')
}
.margin({ left: '10lpx' })
.width('75%') }
.height('50%')
}
}

4)底部总额

• 主要用到 Flex 容器和 Stack 容器 Image 和 Text 组件;

• 从首页点击列表进入菜品详细页面,点菜成功后会自动返回首页,更新订单数量和总额;

• 点击底部总额框,将订单列表加入分布式数据库,@entry 模拟监听数据库变化,拉起订单列表详情页面。

@Component
struct TotalInfo {
@Consume TotalMenu: any[];
private total: number = 0;
private amount: number = 0;
private remoteData: MenuListData aboutToAppear() {
for (var index = 0; index < this.TotalMenu.length; index++) {
this.total = this.total + this.TotalMenu[index].price * this.TotalMenu[index].quantity
this.amount = this.amount + this.TotalMenu[index].quantity
}
} build() {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
Stack({ alignContent: Alignment.Center }) {
Image($r("app.media.icon_cart"))
.width('96lpx')
.height('96lpx')
.margin({ left: '22lpx' })
Text(this.amount.toString())
.backgroundColor('#F84747')
.borderRadius('30plx')
.fontSize('24plx')
.textAlign(TextAlign.Center)
.fontColor('#FFFFFF')
.width('50lpx')
.height('50lpx')
.margin({ left: '100lpx', bottom: '85lpx' })
}
.width('150lpx')
.height('150lpx') Text('¥')
.fontSize('22lpx')
.fontColor('#006A3A')
.margin({ left: '22lpx' })
Text(this.total.toString())
.fontSize('40lpx')
.fontColor('#006A3A')
.flexGrow(1)
Text('点好了')
.height('100%')
.width('35%')
.fontColor('#FFFFFF')
.backgroundColor('#F84747')
.textAlign(TextAlign.Center)
}
// 将总的订单数据,加入分布式数据库
.onClick(() => {
this.remoteData.putData("menu_list", this.TotalMenu)
})
.width('100%')
.height('10%')
.backgroundColor('#FFFFFF')
}
}

2.2 菜品详情页

效果图如上,可以分为三部分:

1)顶部页标签

@Component
struct PageInfo {
build() {
Flex() {
Text('点单页')
.fontSize('36lpx')
}
.padding({ left: '48lpx', top: '28lpx' })
.width('100%')
.height('10%')
.backgroundColor('#FFFFFF')
}
}

2)菜单详情

• 主要用到 Flex 容器 Image 和 Text 组件 Button 组件;

• 辣度可以选择。

@Component
struct detailInfo {
private menuItem
private spicyList = ['正常辣', '加辣', '少辣']
@State spicy: string = '正常辣'
private TotalMenu: any[]
private index = 0
private userName: string build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Start }) {
Flex({ direction: FlexDirection.Row }) {
Button()
.backgroundColor('#006A3A ')
.width('8lpx')
.height('48lpx')
.margin({ right: '12lpx' })
Text('辣度')
}
.margin({ left: '44lpx', top: '48lpx', bottom: '32lpx' }) Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceEvenly }) {
ForEach(this.spicyList, item => { Button(item)
.fontSize('28lpx')
.height('60lpx')
.width('156lpx')
.borderRadius('12lpx')
.backgroundColor(this.spicy == item ? '#006A3A' : '#0D000000')
.fontColor(this.spicy == item ? '#FFFFFF' : '#000000') .onClick(() => {
this.spicy = item
})
}, item => item)
}
}
.margin({ top: '56lpx' })
.width('92%')
.height('50%')
.borderRadius('16lpx')
.backgroundColor('#FFFFFF')
}
}
}

3)点击按钮

• 点击选好了,需要判断该菜品是否已经在总订单里面,并判断是哪一个用户添加,根据判断,做出相应的增加。

Button('选好了')
.fontSize('36lpx')
.width('80%')
.height('7%')
.backgroundColor('#F84747')
.onClick(() => {
for (this.index = 0; this.index < this.TotalMenu.length; this.index++) {
if (this.TotalMenu[this.index].name == this.menuItem.name && this.TotalMenu[this.index].spicy == this.spicy) {
this.TotalMenu[this.index].quantity = this.TotalMenu[this.index].quantity + 1;
if (this.userName == 'Sunny') {
this.TotalMenu[this.index].userNumber = this.TotalMenu[this.index].userNumber + 1;
} else if (this.userName == 'Jenny') {
this.TotalMenu[this.index].anotherUserNumber = this.TotalMenu[this.index].anotherUserNumber + 1;
}
break;
}
}
// 菜名不一样,辣度不一样,都需要重新push到列表里面
if (this.index == this.TotalMenu.length) {
this.menuItem.spicy = this.spicy;
this.menuItem.quantity = 1;
//根据不用的用户名称,
if (this.userName == 'Sunny') {
this.menuItem.userNumber = 1;
} else if (this.userName == 'Jenny') {
this.menuItem.anotherUserNumber = 1;
}
this.TotalMenu.push(this.menuItem);
}
router.push({
uri: 'pages/index',
params: { menuItem: this.menuItem, TotalMenu: this.TotalMenu }
})
})
.margin({ top: '10%' })

2.3 订单详情页

效果如上,可以分为三部分:

 1)订单列表

• 主要用到 Flex 容器 Image 和 Text 组件 Button 组件;

• 展示不同用户加入菜单数量。

@Component
struct TotalItem {
private totalMenu: MenuData build() {
Flex({ direction: FlexDirection.Column }) {
Flex({ direction: FlexDirection.Row, alignContent: FlexAlign.Start, justifyContent: FlexAlign.Start }) {
if (this.totalMenu.userNumber > 0) {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
Image(this.totalMenu.userImg)
.width('96lpx')
.height('96lpx')
Text(this.totalMenu.userName)
.fontSize('36lpx')
.fontWeight(FontWeight.Bold)
.margin({ left: '12lpx' })
.flexGrow(1)
Text(this.totalMenu.userNumber.toString())
.fontSize('32lpx')
.margin({ right: '11plx' }) }
.height('150lpx')
}
if (this.totalMenu.anotherUserNumber > 0) {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
Image(this.totalMenu.anotherUserImg)
.width('96lpx')
.height('96lpx')
Text(this.totalMenu.anotherUserName)
.fontSize('36lpx')
.fontWeight(FontWeight.Bold)
.margin({ left: '12lpx' })
.flexGrow(1)
Text(this.totalMenu.anotherUserNumber.toString())
.fontSize('32lpx')
.margin({ right: '11plx' }) }
.height('150lpx')
}
}
.margin({ top: '12lpx' })
.borderRadius('16lpx')
.padding({ left: '3%', right: '3%', top: '2%' })
.backgroundColor('#FFFFFF')
}
}

2)下单按钮

• 点击下单,将"submitOk" 加入分布式数据库,监听数据库变化后,弹出自定义对话框。

@Component
struct SubmitList {
private remoteData: SubmitData
private SubmitOK: any[] = [
{
submit: "submitOk"
}
]; build() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text('下单')
.fontSize('36lpx')
.fontColor('#FFFFFF')
}
.width('100%')
.height('10%')
.backgroundColor('#F84747')
.onClick(() => {
this.remoteData.putData("submit", this.SubmitOK)
})
.margin({ top: '5%' })
}
}

3)自定义弹框

• 通过 @CustomDialog 装饰器来创建自定义弹窗,使用方式可参考 自定义弹窗;

• 规则弹窗效果如下,弹窗组成由一个 Image 和两个 Text 竖向排列组成;

• 在 build()下使用 Flex 容器来包裹,组件代码如下:

@CustomDialog
struct SubmitDialog {
private controller: CustomDialogController build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
Flex({ justifyContent: FlexAlign.Center }) {
Image($r("app.media.icon_success"))
.width('100lpx')
.height('80lpx')
}
.flexGrow(1) Text('下单成功')
.fontSize('36lpx')
.fontColor('#000000')
.flexGrow(1)
Text('*温馨提示:菜品具体售卖情况请以店面实际情况为准哦~')
.fontSize('22lpx')
.opacity(0.6)
.fontColor('#000000')
.padding({ left: '10lpx', right: '10lpx' })
}
.height('300lpx')
.width('100%')
.padding({ top: '50lpx', bottom: '20lpx' }) }
}

• 在 @entry 模块创建 CustomDialogController 对象并传入弹窗所需参数,设置点击允许点击遮障层退出,通过 open() 方法,显示弹窗。

SubmitDialog: CustomDialogController = new CustomDialogController({
builder: SubmitDialog(),
autoCancel: true
})
aboutToAppear() { this.remoteData.createManager(() => {
let self = this
var data;
if (JSON.stringify(self.remoteData.dataItem).length > 0) {
data = self.remoteData.dataItem;
CommonLog.info("======submit==" + data[0].submit);
if (data[0].submit == "submitOk") {
this.SubmitDialog.open()
}
}
}, "com.distributed.order", "submit")
}

三、分布式数据管理

OpenHarmony 技术特性包括分布式数据管理、分布式任务调度等;分布式数据管理基于分布式软总线的能力,实现应用程序数据和用户数据的分布式管理。用户数据不再与单一物理设备绑定,业务逻辑与数据存储分离,跨设备的数据处理如同本地数据处理一样方便快捷,让开发者能够轻松实现全场景、多设备下的数据存储、共享和访问,为打造一致、流畅的用户体验创造了基础条件。

3.1 开发步骤

分布式数据管理要求两个或多个设备在同一网络。开发步骤:

1)导入模块

import distributedData from '@ohos.data.distributedData';

2)创建一个 KVManager 对象实例,用于管理数据库对象;注意 bundleName 需要修改为自己的包名。

let kvManager;
try {
const kvManagerConfig = {
bundleName : 'com.distributed.order',
userInfo : {
userId : '0',
userType : distributedData.UserType.SAME_USER_ID
}
}
distributedData.createKVManager(kvManagerConfig, function (err, manager) {
if (err) {
console.log("createKVManager err: " + JSON.stringify(err));
return;
}
console.log("createKVManager success")
kvManager = manager
});
} catch (e) {
console.log("An unexpected error occurred. Error:" + e);
}

3)通过指定 Options 和 storeId,创建并获取 KVStore 数据库,如下是参数说明;需要先通过 createKVManager 构建一个 KVManager 实例。

let kvStore;
let kvManager;
try {
const options = {
createIfMissing : true,
encrypt : false,
backup : false,
autoSync : true,
kvStoreType : distributedData.KVStoreType.SINGLE_VERSION,
securityLevel : distributedData.SecurityLevel.S2,
};
kvManager.getKVStore('storeId', options, function (err, store) {
if (err) {
console.log("getKVStore err: " + JSON.stringify(err));
return;
}
console.log("getKVStore success");
kvStore = store
});
} catch (e) {
console.log("An unexpected error occurred. Error:" + e);
}

4)KVStore 数据库实例, KVStore.put 提供增加数据的方法,如下是参数说明。

let kvStore;
try {
kvStore.put(key, value, function (err,data) {
if (err != undefined) {
console.log("put err: " + JSON.stringify(err))
return;
}
console.log("put success");
});
}catch (e) {
console.log("An unexpected error occurred. Error:" + e);
}

5) KVStore 数据库实例,KVStore.on 订阅指定类型的数据变更通知;一般监听远端设备变化,再进行相应操作达到分布式数据共享的效果。

let kvStore;
kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_LOCAL, function (data) {
console.log("dataChange callback call data: " + JSON.stringify(data));
});

6)具体开发请参考分布式数据管理:

https://gitee.com/openharmony/docs/blob/OpenHarmony-3.1-Beta/zh-cn/application-dev/reference/apis/js-apis-distributed-data.md

3.2 应用示例

本项目通过 storeId (数据库唯一标识符)值不同,创建了两个数据管理类,分别是 MenuListData 类和 SubmitData 类,即 Demo 中的 MenuListDistributedData.ets SubmitData.ets 文件。

1)MenuListData 是将完整订单添加到分布式数据库,当监听到数据库变化时,获取完整订单列表,并通过 router.push 接口将数据传递到订单详情页面展示。

• 创建一个 MenuListData 类

private remoteData: MenuListData = new MenuListData()

• 定义一个订单列表集合,集合中的元素包括菜单信息和点单用户信息;点菜后就根据菜品名称和辣度的不同,对订单数据集合进行修改或增加。

TotalMenu: any[] = [
{
"imgSrc": "", // 菜品图片
"name": "", // 菜品名称
"remarks": "", // 菜品备注
"price": 0, // 菜品价格
"quantity": 0, // 菜品数量
"spicy": "", //辣度
"userImg": ,
"userName": "",
"userNumber": 0,
"anotherUserImg": "",
"anotherUserName": "",
"anotherUserNumber": 0,
}];

• 将订单数据加入到分布式数据库

this.remoteData.putData("menu_list", this.TotalMenu)

• 监听数据库变化,获取数据,并将数据传递到 menuAccount 订单详情页面;

this.remoteData.createManager(() => {
let self = this
var data
if (JSON.stringify(self.remoteData.dataItem).length > 0) {
data = self.remoteData.dataItem
var list = []
for (var i = 0; i < data.length; i++) {
list[i] = data[i]
}
router.push({
uri: 'pages/menuAccount',
params: { TotalMenu: list }
})
}
})

2)SubmitData 在订单结算时点击下单,将 submitOK 集合添加到数据库,表示下单完成,监听到数据库变化,各设备弹出下单成功提示框;

• 创建一个 SubmitData 类

private remoteData: SubmitData = new SubmitData();

• 定义一个 SubmitOK 集合,这里用集合主要是为了处理数据方便

private SubmitOK: any[] = [
{
submit: "submitOk"
}
]

• 添加 SubmitOK 集合到数据库中

this.remoteData.putData("submit", this.SubmitOK)

• 监听到数据库变化,获取数据并比较是 submitOK 后,弹出提示框,告知所有人下单成功。

this.remoteData.createManager(() => {
let self = this
var data
if (JSON.stringify(self.remoteData.dataItem).length > 0) {
data = self.remoteData.dataItem
if (data[0].submit == "submitOk") {
this.SubmitDialog.open()
}
}
})

更完整的分布式数据库的使用,请参考 Demo。

四、项目下载和导入

项目地址:https://gitee.com/openharmony-sig/knowledge_demo_temp/tree/master/FA/Shopping/DistributedOrder

1)git 下载

git clone https://gitee.com/openharmony-sig/knowledge_demo_temp.git

2)项目导入

打开 DevEco Studio,点击 File->Open->下载路径/FA/Shopping/DistributedOrder

3)硬件约束

需要下载对应开发板镜像(https://gitee.com/openharmony/docs/blob/master/zh-cn/release-notes/OpenHarmony-v3.1-beta.md)进行烧录;如下图:

五、分享与共建

丰富多样的 OpenHarmony 开发样例离不开广大合作伙伴和开发者的贡献,如果你开发出了更好的 OpenHarmony 开发样例,并愿意分享给广大开发者学习,请 Fork 并 Pull Request 到如下仓库,共建 OpenHarmony 开发样例。

若您不清楚如何提交代码到仓库,请参考代码贡献教程,我们等着你的 Pull Request。(https://gitee.com/openharmony-sig/knowledge_demo_smart_home/blob/master/dev/docs/contribute/README.md)。

OpenHarmony 3.1 Beta 样例:使用分布式菜单创建点餐神器的更多相关文章

  1. OpenHarmony标准设备应用开发(三)——分布式数据管理

    (以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点) 邢碌 上一章,我们通过分布式音乐播放器.分布式炸弹.分布式购物车,带大家讲解了 OpenAtom OpenHarmon ...

  2. MarkDown+LaTex 数学内容编辑样例收集

    $\color{green}{MarkDown+LaTex 数学内容编辑样例收集}$ 1.大小标题的居中,大小,颜色 [例1] $\color{Blue}{一元二次方程根的分布}$ $\color{R ...

  3. 【Scala篇】--Scala中Trait、模式匹配、样例类、Actor模型

    一.前述 Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大. 模式匹配机制相当于java中的switch-case. 使用了case关键字的类定义就是样例类(case ...

  4. Kafka在Linux上安装部署及样例测试

    Kafka是一个分布式的.可分区的.可复制的消息系统.它提供了普通消息系统的功能,但具有自己独特的设计.这个独特的设计是什么样的呢 介绍 Kafka是一个分布式的.可分区的.可复制的消息系统.它提供了 ...

  5. Scala模式匹配和样例类

    Scala有一个十分强大的模式匹配机制,可以应用到很多场合:如switch语句.类型检查等.并且Scala还提供了样例类,对模式匹配进行了优化,可以快速进行匹配. 1.字符匹配     def mai ...

  6. zookeeper实战:SingleWorker代码样例

    我们需要一个“单点worker”系统,此系统来确保系统中定时任务在分布式环境中,任意时刻只有一个实例处于活跃:比如,生产环境中,有6台机器支撑一个应用,但是一个应用中有30个定时任务,这些任务有些必须 ...

  7. Scala基础:模式匹配和样例类

    模式匹配 package com.zy.scala import scala.util.Random /** * 模式匹配 */ object CaseDemo { def main(args: Ar ...

  8. tensorflow学习笔记----tensorflow在windows的安装及TensorBoard中mnist样例

    前言:                                                                                                 ...

  9. [b0007] windows 下 eclipse 开发 hdfs程序样例

    目的: 学习使用hdfs 的java命令操作 相关: 进化: [b0010] windows 下 eclipse 开发 hdfs程序样例 (二) [b0011] windows 下 eclipse 开 ...

随机推荐

  1. mycat的安装及使用 看这一篇就够了

    1.环境准备 ​ 本次使用的虚拟机环境是centos6.5 ​ 首先准备四台虚拟机,安装好mysql,方便后续做读写分离和主从复制. 192.168.85.111 node01 192.168.85. ...

  2. python爬虫 Selenium库学习

    一.自动化测试工具,支持多种浏览器,解决JS渲染问题 二.安装 pip3 install Selenium 三.操作介绍(因为是学习别人的课程为了尊重知识产权,部分代码就不显示了) 1驱动浏览器 br ...

  3. 什么是 Swagger?你用 Spring Boot 实现了它吗?

    Swagger 广泛用于可视化 API,使用 Swagger UI 为前端开发人员提供在线沙箱.Swagger 是用于生成 RESTful Web 服务的可视化表示的工具,规范和完整框架实现.它使文档 ...

  4. python 装饰器函数基础知识

    1.装饰器的本质--一个闭包函数 2.装饰器的功能--在不改变原函数及其调用方式情况下对原函数功能进行拓展 3.带参数和返回值的装饰器 def timer(func): @wraps(func) #使 ...

  5. 谈一谈 Kafka 的再均衡?

    在Kafka中,当有新消费者加入或者订阅的topic数发生变化时,会触发Rebalance(再均衡:在同一个消费者组当中,分区的所有权从一个消费者转移到另外一个消费者)机制,Rebalance顾名思义 ...

  6. django关闭DEBUG,无法加载静态文件

    环境是:Python3.7 Django2.2 出现的问题根本原因是:当我们在开发django应用时如果设置了 DEBUG = True,那么django便会自动帮我们对静态文件进行路由:但是当我们设 ...

  7. 如何监控 Elasticsearch 集群状态?

    Marvel 让你可以很简单的通过 Kibana 监控 Elasticsearch.你可以实时查看你 的集群健康状态和性能,也可以分析过去的集群.索引和节点指标.

  8. buuctf 荷兰带宽数据泄露

    荷兰带宽数据泄露 下载附件得一个conf.bin文件,这个文件是路由信息文件,题目并没有任何提示,我们先来测试一下最简单的,找username或password然后当作flag交上去,我们使用Rout ...

  9. 4.7 ROS分布式通信

    4.7 ROS分布式通信 ROS是一个分布式计算环境.一个运行中的ROS系统可以包含分布在多台计算机上多个节点.根据系统的配置方式,任何节点可能随时需要与任何其他节点进行通信. 因此,ROS对网络配置 ...

  10. 阿里云上安装 Ubuntu + MariaDB

    阿里云上安装 Ubuntu + MariaDB 任务 安装第二个磁盘 设置第二个磁盘为数据盘 安装 MariaDB 配置 MariaDB 的数据文件目录 配置 MariaDB 远程访问 安装第二个磁盘 ...