开发云函数调用云函数
开发云函数
新建项目和应用,开通云函数服务(AGC)
开通云函数服务
使用端云一体化模板创建应用 (DevEco Studio)
新建云函数(DevEcoStudio) 】
编写云函数代码(DevEco Studio)
部署云函数(DevEco Studio)
设置和测试(AGC)
端侧调用云函数
添加依赖
初始化AGConnect
ArkTS 界面开发
ArkTS 调用云函数
云函数,要在真机大概模拟器才气用
云函数开发细节
传参问题
端侧输入姓名,云测根据传来的参数,进行处理,告诉端侧显示不同的欢迎词
端侧
云测
我们要知道端侧传过来什么,就要知道event对象里有什么
查文档
为了步伐结实,我们可以把先判定有没有body,没有怎么处理,大概捕获异常
环境变量
如果我有一些设置项,那么他们容易改变,那我不应该把它写死在步伐代码之中,而是把这些设置项呢,给他以环境变量的方式提供
如许就能保证设置项将来改动了,代码不用动
env系统提供的和我们将来可以自界说环境变量
你可以点击这个新增变量来输入变量名变量值
一定要点击保存它才气生效啊
云函数如果它重新部署的话
那么这个上次设置的环境变量会被清空
所以呢我们先去改动一下云函数的代码,把它重新部署之后,然后咱们回过头来再去设置这个环境变量好
流量管理
负载均衡
云函数的一个利益就是它是按量计费,如果你对这个原函数啊并没有使用,那它是不收费的
云函数运行之前,它会把它部署到一个虚拟机实例上
我已经有一段时间没有去调用我的hello,他就把我谁人实例销毁了这个时间是不计费的
那将来我对这个原函数一旦要产生调用,它才会动态的创建一个实例,并且把原函数部署上去,这时间才会产生费用啊
如果这个并发量比较大,那云函数这边它是如何去分配,请求到这每个实例的
这就涉及到了负载均衡
重试
云函数的调用是有可能超时的
那么如果你不希望这个函数执行一次就失败,你还想救一下它
我们可以通过流量管理中有一个器重的功能,在函数超时失败之后呢,可以重新发起一次对云函数的调用,如果这次调用能成功,那我们就不用返回失败的信息,还是可以返回成功的信息啊
重试功能呢其实它也分了三种策略
第一种重策略叫做zero
它的意思呢就是说一旦函数发现了它调用失败,那我就立刻发起器重,它中间不会等待
第二种从事策略叫做constant
当你的函数调用失败了之后,他不会说立刻去发起这个重试,他要隔断两秒之后再发起重试
第三种从策略呢叫做jittered
它其实跟我们前面第二种啊比较像,
都是在每次重试之间会有一个时间隔断,不外它的时间隔断不像我们constant,它的时间隔断是一个常量的时间值,它是一个变化的时间值
每次这个时间隔断是以指数方式增长的啊
zero
constant
jittered
熔断
就跟我们一样平常生存中的保险丝的作用有点像,保险丝呢它在大电流来了以后,保险丝是不是就烧断了
流量管理中的熔断,它的目的也是类似的,比如说我的云函数,它的调用很多次都出错了,那我继续提供原函数服务已经没有意义了
这时间呢我就接纳熔断,熔断一旦发生,那么原函数呢就暂停对外的服务了,也就是这个原函数不可用了,
但是原函数不可用是避免了更大
比如说像雪崩事故的发生好
这是熔断的目的啊
它的设置项其实就这么三项
刚开始这个开关没有开的时间,那函数呢在任意时候都可以对外提供服务
如果我们把这个熔断开关打开,那它就会在满足了某些条件之后触发熔断,一旦函数熔断发生,那么这个函数就不能对外提供服务了
认证服务
开通认证服务
使用认证组件进行认证
第一步登录页面
第二步,登录成功后
至此整个登录流程跑通了
认证流程(1) -上报认证数据
认证凭据,根据你的认证方式不同而不同
比如说呢我们之前用的是手机认证
那手机验证的话,当我点击登录按钮之后,是不是让你输入手机号和验证码,那这个手机号和验证码
就是我们手机认证方式下它的认证凭据
那如果你接纳的是邮箱认证呢
那这个认证据就是你的邮件地址和
邮件里收到的认证码
第一次使用认证服务那服务器这边是不是应该还没有这个用户信息
服务器就创建你的服务信息
认证流程(2) -获取用户信息
自行实现登录需求操纵
- @Entry
- @Component
- struct MyLoginCustom {
- build() {
- Row() {
- Column({ space: 10 }) {
- Text('登录')
- .fontSize(40)
- .fontWeight(FontWeight.Bold)
- Divider()
- TextInput({ placeholder: '请输入手机号' })
- .width('80%')
- .type(InputType.Number)
- Row({ space: 10 }) {
- TextInput({ placeholder: '请输入验证码' })
- .width('55%')
- .type(InputType.Number)
- Button('获取验证码')
- }
- .width('80%')
- .justifyContent(FlexAlign.SpaceBetween)
- Button('登录')
- }
- .width('100%')
- }
- .height('100%')
- }
- }
复制代码 自行实现登录倒计时开端实现、
- @Entry
- @Component
- struct MyLoginCustom {
- @State countDown: number = 10
- intervalId: number = 0
- @State verifyCodeButtonText: string = '获取验证码'
- build() {
- Row() {
- Column({ space: 10 }) {
- Text('登录')
- .fontSize(40)
- .fontWeight(FontWeight.Bold)
- Divider()
- TextInput({ placeholder: '请输入手机号' })
- .width('80%')
- .type(InputType.Number)
- Row({ space: 10 }) {
- TextInput({ placeholder: '请输入验证码' })
- .width('55%')
- .type(InputType.Number)
- Button(this.verifyCodeButtonText)
- .onClick(()=> {
- this.intervalId = setInterval(() => {
- this.verifyCodeButtonText = `${this.countDown} s`
- if(this.countDown<0){
- clearInterval(this.intervalId)
- this.countDown = 10
- this.intervalId = 0
- this.verifyCodeButtonText = '获取验证码'
- return
- }
- this.countDown--
- },1000)
- })
- }
- .width('80%')
- .justifyContent(FlexAlign.SpaceBetween)
- Button('登录')
- }
- .width('100%')
- }
- .height('100%')
- }
- }
复制代码 自行实现登录倒计时细节调解
- @Entry
- @Component
- struct MyLoginCustom {
- @State countDown: number = 10
- intervalId: number = 0
- @State verifyCodeButtonText: string = '获取验证码'
- @State verifyCodeButtonEnable: boolean = true
- build() {
- Row() {
- Column({ space: 10 }) {
- Text('登录')
- .fontSize(40)
- .fontWeight(FontWeight.Bold)
- Divider()
- TextInput({ placeholder: '请输入手机号' })
- .width('80%')
- .type(InputType.Number)
- Row({ space: 10 }) {
- TextInput({ placeholder: '请输入验证码' })
- .width('55%')
- .type(InputType.Number)
- Button(this.verifyCodeButtonText)
- .enabled(this.verifyCodeButtonEnable) // 当点击了,之后按钮不可用
- .onClick(()=> {
- this.verifyCodeButtonText = `${this.countDown} s`
- this.countDown--
- this.verifyCodeButtonEnable = false
- this.intervalId = setInterval(() => {
- this.verifyCodeButtonText = `${this
- if(this.countDown<0){
- clearInterval(this.intervalId)
- this.countDown = 10
- this.intervalId = 0
- this.verifyCodeButtonText = '获取验证码'
- this.verifyCodeButtonEnable = true // 倒计时结束之后就可用了
- return
- }
- this.countDown--
- },1000)
- })
- }
- .width('80%')
- .justifyContent(FlexAlign.SpaceBetween)
- Button('登录')
- }
- .width('100%')
- }
- .height('100%')
- }
- }
复制代码 封装成函数
- @Entry
- @Component
- struct MyLoginCustom {
- @State countDown: number = 10
- intervalId: number = 0
- @State verifyCodeButtonText: string = '获取验证码'
- @State verifyCodeButtonEnable: boolean = true
- waiting() {
- this.verifyCodeButtonText = `${this.countDown} s`
- this.countDown--
- this.verifyCodeButtonEnable = false
- this.intervalId = setInterval(() => {
- this.verifyCodeButtonText = `${this
- if(this.countDown<0){
- clearInterval(this.intervalId)
- this.countDown = 10
- this.intervalId = 0
- this.verifyCodeButtonText = '获取验证码'
- this.verifyCodeButtonEnable = true // 倒计时结束之后就可用了
- return
- }
- this.countDown--
- },1000)
- }
- build() {
- Row() {
- Column({ space: 10 }) {
- Text('登录')
- .fontSize(40)
- .fontWeight(FontWeight.Bold)
- Divider()
- TextInput({ placeholder: '请输入手机号' })
- .width('80%')
- .type(InputType.Number)
- Row({ space: 10 }) {
- TextInput({ placeholder: '请输入验证码' })
- .width('55%')
- .type(InputType.Number)
- Button(this.verifyCodeButtonText)
- .enabled(this.verifyCodeButtonEnable) // 当点击了,之后按钮不可用
- .onClick(()=> {
- this.waiting()
- })
- }
- .width('80%')
- .justifyContent(FlexAlign.SpaceBetween)
- Button('登录')
- }
- .width('100%')
- }
- .height('100%')
- }
- }
复制代码 自行实现登录发送验证码
- import cloud, { VerifyCodeAction } from '@hw-agconnect/cloud'
- import hilog from '@ohos.hilog'
- import router from '@ohos.router'
- @Entry
- @Component
- struct MyLoginCustom {
- @State countDown: number = 10
- intervalId: number = 0
- @State verifyCodeButtonText: string = '获取验证码'
- @State verifyCodeButtonEnable: boolean = true
- @State phoneNumber: string = ''
- waiting() {
- this.verifyCodeButtonText = `${this.countDown} s`
- this.countDown--
- this.verifyCodeButtonEnable = false
- this.intervalId = setInterval(() => {
- this.verifyCodeButtonText = `${this
- if(this.countDown<0){
- clearInterval(this.intervalId)
- this.countDown = 10
- this.intervalId = 0
- this.verifyCodeButtonText = '获取验证码'
- this.verifyCodeButtonEnable = true // 倒计时结束之后就可用了
- return
- }
- this.countDown--
- },1000)
- }
- build() {
- Row() {
- Column({ space: 10 }) {
- Text('登录')
- .fontSize(40)
- .fontWeight(FontWeight.Bold)
- Divider()
- TextInput({ placeholder: '请输入手机号' })
- .width('80%')
- .type(InputType.Number)
- Row({ space: 10 }) {
- TextInput({ placeholder: '请输入验证码' })
- .width('55%')
- .type(InputType.Number)
- .onChange(value => {
- this.phoneNumber = value
- })
- Button(this.verifyCodeButtonText)
- .enabled(this.verifyCodeButtonEnable) // 当点击了,之后按钮不可用
- .onClick(async ()=> {
- this.waiting()
- try {
- await cloud.auth().requestVerifyCode({
- verifyCodeType: {
- kind: 'phone',
- phoneNumber: this.phoneNumber,
- countryCode: '86'
- },
- action: VerifyCodeAction.REGISTER_LOGIN,
- lang: 'zh_CN',
- sendInterval: 10
- })
- hilog.info(0, 'VerifyCode', 'Success')
- } catch (e) {
- // 弹窗提示错误
- AlertDialog.show({ title: '错误', message: '验证码发送失败' })
- hilog.error(0, 'VerifyCode', JSON.stringify(e))
- }
- })
- }
- .width('80%')
- .justifyContent(FlexAlign.SpaceBetween)
- Button('登录')
- }
- .width('100%')
- }
- .height('100%')
- }
- }
复制代码 自行实现登录登录
- import cloud, { VerifyCodeAction } from '@hw-agconnect/cloud'
- import hilog from '@ohos.hilog'
- import router from '@ohos.router'
- @Entry
- @Component
- struct MyLoginCustom {
- @State countDown: number = 10
- intervalId: number = 0
- @State verifyCodeButtonText: string = '获取验证码'
- @State verifyCodeButtonEnable: boolean = true
- @State phoneNumber: string = ''
- @State verifyCode: string = ''
- waiting() {
- this.verifyCodeButtonText = `${this.countDown} s`
- this.countDown--
- this.verifyCodeButtonEnable = false
- this.intervalId = setInterval(() => {
- this.verifyCodeButtonText = `${this
- if(this.countDown<0){
- clearInterval(this.intervalId)
- this.countDown = 10
- this.intervalId = 0
- this.verifyCodeButtonText = '获取验证码'
- this.verifyCodeButtonEnable = true // 倒计时结束之后就可用了
- return
- }
- this.countDown--
- },1000)
- }
- build() {
- Row() {
- Column({ space: 10 }) {
- Text('登录')
- .fontSize(40)
- .fontWeight(FontWeight.Bold)
- Divider()
- TextInput({ placeholder: '请输入手机号' })
- .width('80%')
- .type(InputType.Number)
- Row({ space: 10 }) {
- TextInput({ placeholder: '请输入验证码' })
- .width('55%')
- .type(InputType.Number)
- .onChange(value => {
- this.phoneNumber = value
- })
- Button(this.verifyCodeButtonText)
- .enabled(this.verifyCodeButtonEnable) // 当点击了,之后按钮不可用
- .onClick(async ()=> {
- this.waiting()
- try {
- await cloud.auth().requestVerifyCode({
- verifyCodeType: {
- kind: 'phone',
- phoneNumber: this.phoneNumber,
- countryCode: '86'
- },
- action: VerifyCodeAction.REGISTER_LOGIN,
- lang: 'zh_CN',
- sendInterval: 10
- })
- hilog.info(0, 'VerifyCode', 'Success')
- } catch (e) {
- // 弹窗提示错误
- AlertDialog.show({ title: '错误', message: '验证码发送失败' })
- hilog.error(0, 'VerifyCode', JSON.stringify(e))
- }
- })
- }
- .width('80%')
- .justifyContent(FlexAlign.SpaceBetween)
- Button('登录')
- .onClick(async ()=> {
- try {
- const result = await cloud.auth().signIn({
- credentialInfo: {
- kind: 'phone',
- countryCode: '86',
- phoneNumber: this.phoneNumber,
- verifyCode: this.verifyCode
- }
- })
- const user = result.getUser()
- hilog.info(0, 'Login', 'Success')
- router.replaceUrl({ url: 'pages/MyWelcome' }) // 跳转到登录页
- } catch (e) {
- // 弹窗提示错误
- AlertDialog.show({ title: '错误', message: '验证码发送失败' })
- hilog.error(0, 'VerifyCode', JSON.stringify(e))
- }
- })
- }
- .width('100%')
- }
- .height('100%')
- }
- }
复制代码 自行实现登录登录细节调解
检查用户输入的是否是手机号
- import cloud, { VerifyCodeAction } from '@hw-agconnect/cloud'
- import hilog from '@ohos.hilog'
- import router from '@ohos.router'
- @Entry
- @Component
- struct MyLoginCustom {
- @State countDown: number = 10
- intervalId: number = 0
- @State verifyCodeButtonText: string = '获取验证码'
- @State verifyCodeButtonEnable: boolean = true
- @State phoneNumber: string = ''
- @State verifyCode: string = ''
- waiting() {
- this.verifyCodeButtonText = `${this.countDown} s`
- this.countDown--
- this.verifyCodeButtonEnable = false
- this.intervalId = setInterval(() => {
- this.verifyCodeButtonText = `${this
- if(this.countDown<0){
- clearInterval(this.intervalId)
- this.countDown = 10
- this.intervalId = 0
- this.verifyCodeButtonText = '获取验证码'
- this.verifyCodeButtonEnable = true // 倒计时结束之后就可用了
- return
- }
- this.countDown--
- },1000)
- }
- async login() {
- try {
- const result = await cloud.auth().signIn({
- credentialInfo: {
- kind: 'phone',
- countryCode: '86',
- phoneNumber: this.phoneNumber,
- verifyCode: this.verifyCode
- }
- })
- const user = result.getUser()
- AppStorage.SetOrCreate('user', user) // 存
- hilog.info(0, 'Login', 'Success')
- router.replaceUrl({ url: this.mainPage })
- } catch (e) {
- hilog.error(0, 'Login', JSON.stringify(e))
- AlertDialog.show({ title: '错误', message: `登录失败 ${JSON.stringify(e)}` })
- }
- }
- async sending() {
- try {
- await cloud.auth().requestVerifyCode({
- verifyCodeType: {
- kind: 'phone',
- phoneNumber: this.phoneNumber,
- countryCode: '86'
- },
- action: VerifyCodeAction.REGISTER_LOGIN,
- lang: 'zh_CN',
- sendInterval: 10
- })
- hilog.info(0, 'VerifyCode', 'Success')
- } catch (e) {
- AlertDialog.show({ title: '错误', message: '验证码发送失败' })
- hilog.error(0, 'VerifyCode', JSON.stringify(e))
- }
- }
- build() {
- Row() {
- Column({ space: 10 }) {
- Text('登录')
- .fontSize(40)
- .fontWeight(FontWeight.Bold)
- Divider()
- TextInput({ placeholder: '请输入手机号' })
- .width('80%')
- .type(InputType.Number)
- Row({ space: 10 }) {
- TextInput({ placeholder: '请输入验证码' })
- .width('55%')
- .type(InputType.Number)
- .onChange(value => {
- this.phoneNumber = value
- })
- Button(this.verifyCodeButtonText)
- .enabled(this.verifyCodeButtonEnable) // 当点击了,之后按钮不可用
- .onClick(async ()=> {
- this.waiting()
- this.sending()
-
- })
- }
- .width('80%')
- .justifyContent(FlexAlign.SpaceBetween)
- Button('登录')
- // 判断是否是合法的手机号,验证码
- .enabled(this.phoneNumber.length === 11 && this.verifyCode.length === 6)
- .onClick(async ()=> {
- this.login()
- })
- }
- .width('100%')
- }
- .height('100%')
- }
- }
复制代码 个人设置页-登出
个人设置页修改昵称和头像
不用户信息存起来
取出头像信息
云存储
上传头像
开通云存储服务
图片缓存问题
工程模式
进入工程模式
用户授权
想使用云存储必要下面三步
1、开通云存储服务
2、更新项目的一个AGC的设置文件
3、用户授权,允许读取媒体文件(前面为什么没有,授权呢?因为我们使用的是端云一体化模板,设置都写好了)
下面我们就看看,模板帮我们写了那些设置
上传进度
问题4:上传进度实现
1.上传状态变量
2…上传进度文字变量、对应的Text
3.编写进度回调
- import cloud, { AuthUser } from '@hw-agconnect/cloud'
- import router from '@ohos.router'
- import hilog from '@ohos.hilog'
- import picker from '@ohos.file.picker'
- @Entry
- @Component
- struct MyIndex {
- @State photoUrl: string = ''
- @State displayName: string = ''
- @StorageLink('user') user: AuthUser = null
- @State uploading: boolean = false
- @State uploadingText: string = '0%'
- aboutToAppear() {
- // 1. cloud.auth().getCurrentUser()
- // 2. AppStorage
- this.displayName = this.user?.getDisplayName()
- this.photoUrl = this.user?.getPhotoUrl()
- }
- build() {
- Row() {
- Column({ space: 10 }) {
- Stack() { // 堆叠的效果
- Image(this.photoUrl ? this.photoUrl : $r('app.media.user_dark'))
- .width(70)
- .height(70)
- .borderRadius(70)
- .enabled(!this.uploading)
- .onComplete(()=>{
- this.uploading = false
- })
- .onClick(async () => {
- // this.photoUrl = 'https://img.zcool.cn/community/01a6095f110b9fa8012066219b67d4.png@1280w_1l_2o_100sh.png'
- try {
- // 1. 从相簿中选照片
- const options = new picker.PhotoSelectOptions()
- options.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE
- options.maxSelectNumber = 1
- const result = await new picker.PhotoViewPicker().select(options)
- hilog.info(0, 'Upload', `Picker Success ${result.photoUris[0]}`)
- this.uploading = true
- // 2. 调云存储 api 上传照片
- await cloud.storage().upload({
- localPath: result.photoUris[0],
- cloudPath: `test/${this.user.getUid()}.jpg`,
- onUploadProgress: event => {
- const percent = Math.floor(100 * event.loaded / event.total)
- this.uploadingText = `${percent}%`
- }
- })
- hilog.info(0, 'Upload', 'Upload Success')
- // 3. 获取上传照片的网络地址
- const url = await cloud.storage().getDownloadURL(`test/${this.user.getUid()}.jpg`)
- this.photoUrl = `${url}&ts=${new Date().getTime()}`
- // this.uploading = false
- hilog.info(0, 'Upload', `url: ${url}`)
- } catch (e) {
- hilog.error(0, 'Upload', JSON.stringify(e))
- }
- })
- if (this.uploading) {
- // 显示上传进度
- Text(this.uploadingText)
- .width(70)
- .height(70)
- .borderRadius(70)
- .fontColor('white')
- .backgroundColor('black')
- .opacity(0.6)
- .fontSize(24)
- .fontWeight(FontWeight.Bolder)
- .textAlign(TextAlign.Center)
- }
- }
- TextInput({ placeholder: '请设置昵称', text: this.displayName })
- .width('50%')
- .onChange(value => {
- this.displayName = value
- })
- Button(`保存`)
- .onClick(async () => {
- try {
- await this.user.updateProfile({
- displayName: this.displayName,
- photoUrl: this.photoUrl
- })
- hilog.info(0, 'updateProfile', 'Success')
- } catch (e) {
- hilog.error(0, 'updateProfile', JSON.stringify(e))
- }
- })
- Button(`登出`)
- .onClick(async () => {
- try {
- await cloud.auth().signOut()
- hilog.info(0, 'SignOut', 'Success')
- router.replaceUrl({ url: 'pages/MyLoginCustom' })
- } catch (e) {
- hilog.error(0, 'SignOut', JSON.stringify(e))
- }
- })
- }
- .width('100%')
- }
- .height('100%')
- }
- }
复制代码 在历程中直接竣事步伐(没有点击退出),再次点击登录,会报错
原因,我们虽然竣事了步伐,由于我们没有正常退出步伐,用户会话还在,再次登录的时间出现错误
云数据库
概念
存储区,对象类型,对象
数据类型
数据类型取值范围分析排序方式String最大长度200如果字符串长度凌驾200,建议使用Text类型。接纳 UTF-8 编码的字节次序Booleantrue/false-false < trueByte ( − 2 7 ) ∼ ( 2 7 − 1 ) (-2^7)\sim(2^7-1) (−27)∼(27−1)-数字次序Short ( − 2 15 ) ∼ ( 2 15 − 1 ) (-2^{15})\sim(2^{15}-1) (−215)∼(215−1)-Integer ( − 2 31 ) ∼ ( 2 31 − 1 ) (-2^{31})\sim(2^{31}-1) (−231)∼(231−1)-Long ( − 2 63 ) ∼ ( 2 63 − 1 ) (-2^{63})\sim(2^{63}-1) (−263)∼(263−1)由于JavaScript不支持数据类型“Long”,Web SDK通过引入第三方开源组件实现支持数据类型“Long”的能力。“Long”类型的使用方法请参考https://github.com/dcodeIO/long.js。Float-3.40E+38 ~ +3.40E+38-Double-1.79E+308 ~ +1.79E+308-ByteArray-一般用于文件类型的数据存储,如图片、文档和视频等。在端侧时,使用Android开发应用时,以byte[]表示为字节数组。接纳 UTF-8 编码的字节次序Text--Date--时间次序IntAutoIncrement 1 ∼ ( 2 31 − 1 ) 1\sim(2^{31}-1) 1∼(231−1)Android、HarmonyOS(Java)和iOS不支持此数据类型。数字次序LongAutoIncrement 1 ∼ ( 2 63 − 1 ) 1\sim(2^{63}-1) 1∼(263−1)Android、HarmonyOS(Java)和iOS不支持此数据类型。数字次序
- 假设有自增类型 id,执行 upsert (insert+update)
- id 值在数据库有,更新 {id:1, name:‘李四’ , age:20}
- id 值在数据库无,按自增加加 {id:5, name:‘王五’ , age:16}
- id 值不给,也按自增加加 {name:‘赵六’ , age:16}
- student 表
- id name age
- 1 李四 20
- 2 王五 16
- 3 赵六 16
复制代码 权限管理
【角色】共有四种
- World 所有人
- Authenticated 已认证
- Creator 创建者
- Administrator 管理员
【权限】共有三种:Read 查询、Upsert 新增和修改、Delete 删除
例如
- article 表
- id title
- 用户 111
- 1 探索自我成长的道路:我的心路历程
- 2 如何在忙碌的生活中保持身心健康
- 3 分享我的旅行经历:探索世界的美
- 用户 222
- 4 金融投资的新趋势:数字货币的崛起
- 5 未来科技发展展望:人工智能对社会的影响
复制代码
- 用户111 未登录,查询所有文章 1 2 3 4 5
- 用户333 未登录,查询所有文章 1 2 3 4 5
- 用户111 未登录,添加新文章 失败
- 用户111 已登录,添加新文章 成功
- 用户111 已登录,删除文章1 成功
- 用户111 已登录,删除文章4 失败
- 用户111 已登录,修改文章4 成功
从上面我们可知,华为的云数据库,权限设置比较粗糙,还是必要配合业务代码,进行
它的权限设置如下:
- "permissions": [
- {
- "rights": ["Read"],
- "role": "World"
- },
- {
- "rights": ["Read","Upsert"],
- "role": "Authenticated"
- },
- {
- "rights": ["Read","Upsert","Delete"],
- "role": "Creator"
- },
- {
- "rights": ["Read","Upsert","Delete"],
- "role": "Administrator"
- }
- ]
复制代码 则有:
- 未认证(未登录)的用户只能查询
- 这时最好不要给 Upsert 权限,否则由未认证的用户新增的数据,除了管理员都不能删除
- 已认证的用户可以查询、新增、修改
- 已认证的用户自己新增的数据,自己可以删除,别人的数据不能删除(但可以修改)
- 已认证用户查询时,还是能查到别的用户的数据的,因此必要自己维护 uid 来控制数据权限
准备云数据库
存储区
新建对象的类型,其实就是新建表
另一种方法准备云数据库
使用云端一体化模板
新建一张表
端侧调用云数据库
调用云数据库又分成了两种方式
一种叫端测调用:使用ArkTs它的API,然后直接去使用云数据库
另外一种叫云测调用: 云函数间接的使用云数据库
起首明确:云数据库必要对接华为帐号系统(与前面提到的权限相关联)
分成两种方式:
一. 直接在端侧调用数据库,优点是更直接面对数据库,而且根据文档具备缓存模式的利益
二. 通过云函数在云侧调用数据库,可能无法利用缓存模式的一些利益(未验证)。但又可以隐藏数据库细节,并具备云函数的优点
端侧调用
0)前提
- 添加依赖
- 下载 AGC 设置文件
- 初始化 AGC 连接器
这三步与调用云函数相同
long类型。js不支持,必要用到第三方库
每次我们做了新的设置,都要重新下载 AGC 设置文件
初始化 AGC 连接器
1)建立模子
js 代表端侧模子代码
serverSDK代表云侧模子代码
导出结果如下
- /*
- * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
- * Generated by the CloudDB ObjectType compiler. DO NOT EDIT!
- */
- class t_user {
- constructor() {
- this.id = undefined;
- this.name = "";
- this.birthday = undefined;
- }
- setId(id) {
- this.id = id;
- }
- getId() {
- return this.id;
- }
- setName(name) {
- this.name = name;
- }
- getName() {
- return this.name;
- }
- setBirthday(birthday) {
- this.birthday = birthday;
- }
- getBirthday() {
- return this.birthday;
- }
- }
- t_user.className = 't_user';
- export {t_user}
复制代码 2)导出 schema
导出数据库 schema 文件,例如下面是一个文件名 com.example.myapplication_21_cn.json,格式为【应用名_版本_语言.json】
3)初始化 database
改进–分页查询
改进–搜索功能
改进下滑显示搜索框
只有下滑到顶部的时间,才显示搜索框
- // @ts-ignore
- import schema from './com.example.myapplication_21_cn.json'
- @Entry
- @Component
- struct XXX {
- // ...
- private database: Database
- async aboutToAppear() {
- try {
- // 根据 schema 和 zoneName 创建数据库对象
- this.database = cloud.database({ objectTypeInfo: schema, zoneName: "shopping" })
- } catch (e) {
- hilog.error(0, 'User Query', 'error:' + JSON.stringify(e))
- }
- }
复制代码 4)查询
- import cloud, { Database } from '@hw-agconnect/cloud'
- // @ts-ignore
- import schema from '../../resources/rawfile/schema.json'
- import { t_student } from '../model/t_student'
- import hilog from '@ohos.hilog'
- @Entry
- @Component
- struct StudentPage {
- @State studentList: t_student[] = []
- private database: Database = null
- private dataOffset: number = 0
- @State searchAge: string = ''
- @State showSearch: boolean = false
- private startY: number = 0
- private startIndex: number = 0
- aboutToAppear() {
- this.database = cloud.database({
- zoneName: 'test',
- objectTypeInfo: schema
- })
- this.search('', '', '', this.dataOffset)
- }
- async search(id: string, name: string, age: string, offset: number, limit: number = 10) {
- try {
- const query = this.database.collection(t_student).query()
- if (id.length > 0) {
- // where id=?
- query.equalTo("id", Number(id))
- }
- if (name.length > 0) {
- // where name like ?
- query.contains("name", name)
- }
- if (age.length > 0) {
- // where age=?
- query.equalTo("age", Number(age))
- }
- query.limit(limit, offset)
- query.orderByAsc("id")
- const list: t_student[] = await query.get()
- this.studentList.push(...list)
- hilog.info(0, 'Query', `${list.map(s => s.id)}`)
- } catch (e) {
- hilog.error(0, 'Query', JSON.stringify(e))
- }
- }
- build() {
- Column({ space: 26 }) {
- Row() {
- Text(`编号`)
- .fontSize(18)
- .fontWeight(FontWeight.Bold)
- .fontColor('white')
- .textAlign(TextAlign.Center)
- .width('33%')
- Text(`姓名`)
- .fontSize(18)
- .fontWeight(FontWeight.Bold)
- .fontColor('white')
- .textAlign(TextAlign.Center)
- .width('34%')
- Text(`年龄`)
- .fontSize(18)
- .fontWeight(FontWeight.Bold)
- .fontColor('white')
- .textAlign(TextAlign.Center)
- .width('33%')
- }
- .width('100%')
- .height(36)
- .backgroundColor('black')
- if (this.showSearch) {
- Search()
- .searchButton('搜索')
- .onChange(value => {
- this.searchAge = value
- })
- .onSubmit(() => {
- this.studentList = []
- this.dataOffset = 0
- this.search('', '', this.searchAge, this.dataOffset)
- this.showSearch = false
- })
- }
- List({ space: 52 }) {
- ForEach(this.studentList, (stu: t_student) => {
- ListItem() {
- Row() {
- Text(`${stu.getId()}`)
- .fontSize(18)
- .textAlign(TextAlign.Center)
- .width('33%')
- Text(stu.getName())
- .fontSize(18)
- .textAlign(TextAlign.Center)
- .width('34%')
- Text(`${stu.getAge()}`)
- .fontSize(18)
- .textAlign(TextAlign.Center)
- .width('33%')
- }
- .width('100%')
- }
- })
- }
- .width('100%')
- .height('82%')
- .onReachEnd(() => {
- this.dataOffset += 10
- this.search('', '', '', this.dataOffset)
- })
- .onScrollIndex((start, end) => {
- hilog.info(0, 'Scroll', `start: ${start} end:${end}`)
- this.startIndex = start
- })
- .onTouch(event => {
- switch (event.type) {
- case TouchType.Down:
- this.startY = event.touches[0].y
- break;
- case TouchType.Move:
- const endY = event.touches[0].y
- if (endY - this.startY >= 35 && this.startIndex === 0) {
- this.showSearch = true
- } else if (this.startY - endY >= 25) {
- this.showSearch = false
- }
- break;
- }
- })
- Divider()
- }
- .width('100%')
- .justifyContent(FlexAlign.Start)
- }
- }
复制代码
实现左滑删除
有个难点bind
函数作为参数通报,this丢失问题
函数作为参数通报,剩余参数问问题
问题演示
问题出现
5)新增、修改、删除
- import cloud, { Database } from '@hw-agconnect/cloud'
- // @ts-ignore
- import schema from '../../resources/rawfile/schema.json'
- import { t_student } from '../model/t_student'
- import hilog from '@ohos.hilog'
- import { StudentInsertDialog } from './StudentInsertDialog'
- import router from '@ohos.router'
- import { StudentUpdateDialog } from './StudentUpdateDialog'
- @Entry
- @Component
- struct StudentPage {
- @State studentList: t_student[] = []
- private database: Database = null
- private dataOffset: number = 0
- @State searchAge: string = ''
- @State showSearch: boolean = false
- private startY: number = 0
- private startIndex: number = 0
- private studentInsertDialogController: CustomDialogController = new CustomDialogController({
- builder: StudentInsertDialog({
- confirm: async (name, age) => {
- try {
- const stu = new t_student()
- stu.setName(name)
- stu.setAge(age)
- await this.database.collection(t_student).upsert(stu)
- AlertDialog.show({ message: '添加学生成功' })
- hilog.info(0, 'Student Insert', 'Success')
- this.dataOffset = 0
- this.studentList = []
- this.search('', '', '', this.dataOffset)
- } catch (e) {
- hilog.error(0, 'Student Insert', JSON.stringify(e))
- }
- }
- })
- })
- private studentUpdateDialogController: CustomDialogController
- openStudentUpdateDialog(stu: t_student) {
- this.studentUpdateDialogController = new CustomDialogController({
- builder: StudentUpdateDialog({
- sid: stu.id, name: stu.name, age: stu.age,
- confirm: async (id, name, age) => {
- try {
- const stu = new t_student()
- stu.setId(id)
- stu.setName(name)
- stu.setAge(age)
- await this.database.collection(t_student).upsert(stu)
- AlertDialog.show({ message: '修改学生成功' })
- hilog.info(0, 'Student Update', 'Success')
- this.dataOffset = 0
- this.studentList = []
- this.search('', '', '', this.dataOffset)
- } catch (e) {
- hilog.error(0, 'Student Update', JSON.stringify(e))
- }
- }
- })
- })
- this.studentUpdateDialogController.open()
- }
- openStudentDeleteDialog(stu: t_student) {
- AlertDialog.show({
- title: '请确认',
- message: '真的要删除该用户吗?',
- confirm: {
- value: '确定',
- action: async () => {
- try {
- await this.database.collection(t_student).delete(stu)
- AlertDialog.show({ message: '删除学生成功' })
- hilog.info(0, 'Student Delete', 'Success')
- this.dataOffset = 0
- this.studentList = []
- this.search('', '', '', this.dataOffset)
- } catch (e) {
- hilog.error(0, 'Student Delete', JSON.stringify(e))
- }
- }
- }
- })
- }
- @Builder
- showOperation(stu: t_student) {
- Row({ space: 12 }) {
- Image($r("app.media.ic_public_edit_filled"))
- .width(20)
- .onClick(() => {
- this.openStudentUpdateDialog(stu)
- })
- Image($r("app.media.ic_public_delete_filled"))
- .width(21)
- .onClick(() => {
- this.openStudentDeleteDialog(stu)
- })
- }
- .width(80)
- .justifyContent(FlexAlign.Start)
- }
- aboutToAppear() {
- this.database = cloud.database({
- zoneName: 'test',
- objectTypeInfo: schema
- })
- this.search('', '', '', this.dataOffset)
- }
- async search(id: string, name: string, age: string, offset: number, limit: number = 10) {
- try {
- const query = this.database.collection(t_student).query()
- if (id.length > 0) {
- // where id=?
- query.equalTo("id", Number(id))
- }
- if (name.length > 0) {
- // where name like ?
- query.contains("name", name)
- }
- if (age.length > 0) {
- // where age=?
- query.equalTo("age", Number(age))
- }
- query.limit(limit, offset)
- query.orderByAsc("id")
- const list: t_student[] = await query.get()
- this.studentList.push(...list)
- hilog.info(0, 'Student Query', `${list.map(s => s.id)}`)
- } catch (e) {
- hilog.error(0, 'Student Query', JSON.stringify(e))
- }
- }
- build() {
- Column() {
- Row() {
- Text(`编号`)
- .fontSize(18)
- .fontWeight(FontWeight.Bold)
- .fontColor('white')
- .textAlign(TextAlign.Center)
- .width('33%')
- Text(`姓名`)
- .fontSize(18)
- .fontWeight(FontWeight.Bold)
- .fontColor('white')
- .textAlign(TextAlign.Center)
- .width('34%')
- Text(`年龄`)
- .fontSize(18)
- .fontWeight(FontWeight.Bold)
- .fontColor('white')
- .textAlign(TextAlign.Center)
- .width('33%')
- }
- .width('100%')
- .height(36)
- .backgroundColor('black')
- if (this.showSearch) {
- Search()
- .searchButton('搜索')
- .onChange(value => {
- this.searchAge = value
- })
- .onSubmit(() => {
- this.studentList = []
- this.dataOffset = 0
- this.search('', '', this.searchAge, this.dataOffset)
- this.showSearch = false
- })
- }
- List({ space: 48 }) {
- ForEach(this.studentList, (stu: t_student) => {
- ListItem() {
- Row() {
- Text(`${stu.getId()}`)
- .fontSize(18)
- .textAlign(TextAlign.Center)
- .width('33%')
- Text(stu.getName())
- .fontSize(18)
- .textAlign(TextAlign.Center)
- .width('34%')
- Text(`${stu.getAge()}`)
- .fontSize(18)
- .textAlign(TextAlign.Center)
- .width('33%')
- }
- .width('100%')
- }
- .swipeAction({ end: this.showOperation.bind(this, stu) })
- })
- }
- .width('100%')
- .height('78%')
- .margin({ top: 24, bottom: 24 })
- .onReachEnd(() => {
- this.dataOffset += 10
- this.search('', '', '', this.dataOffset)
- })
- .onScrollIndex((start, end) => {
- hilog.info(0, 'Scroll', `start: ${start} end:${end}`)
- this.startIndex = start
- })
- .onTouch(event => {
- switch (event.type) {
- case TouchType.Down:
- this.startY = event.touches[0].y
- break;
- case TouchType.Move:
- const endY = event.touches[0].y
- if (endY - this.startY >= 25 && this.startIndex === 0) {
- this.showSearch = true
- } else if (this.startY - endY >= 5 || this.startIndex === 0) {
- this.showSearch = false
- }
- break;
- }
- })
- Button('新增', { type: ButtonType.Normal })
- .width('100%')
- .margin({ bottom: 6 })
- .onClick(async () => {
- this.studentInsertDialogController.open()
- })
- Button('登出', { type: ButtonType.Normal })
- .width('100%')
- .backgroundColor(0xcccccc)
- .margin({ bottom: 6 })
- .onClick(async () => {
- try {
- await cloud.auth().signOut()
- hilog.info(0, 'SignOut', 'Success')
- router.replaceUrl({ url: 'pages/MyLoginCustom' })
- } catch (e) {
- hilog.error(0, 'SignOut', JSON.stringify(e))
- }
- })
- Divider()
- }
- .width('100%')
- .justifyContent(FlexAlign.Start)
- }
- }
复制代码- @CustomDialog
- export struct StudentInsertDialog {
- private name: string = ''
- private age: number = 18
- controller: CustomDialogController
- confirm: (name: string, age: number) => void
- private static range = (start, stop, step = 1) => Array.from({
- length: (stop - start - 1) / step + 1
- }, (_, i) => start + (i * step))
- static AgeRange: string[] = StudentInsertDialog.range(16, 60).map(i => String(i))
- build() {
- Column({ space: 15 }) {
- Row() {
- Text('姓名')
- .width('20%')
- TextInput({ text: this.name })
- .width('80%')
- .onChange(value => {
- this.name = value
- })
- }
- .width('80%')
- .justifyContent(FlexAlign.SpaceAround)
- Row() {
- Text('年龄')
- .width('20%')
- TextPicker({ range: StudentInsertDialog.AgeRange, selected: 2 })
- .width('80%')
- .onChange(value => {
- this.age = Number(value)
- })
- }
- .width('80%')
- Row() {
- Button('取消')
- .onClick(() => {
- this.controller.close()
- })
- .backgroundColor(0xcccccc)
- Button('确定')
- .onClick(() => {
- this.confirm(this.name, this.age)
- this.controller.close()
- })
- }
- .width('80%')
- .justifyContent(FlexAlign.SpaceAround)
- }
- .justifyContent(FlexAlign.SpaceAround)
- .width('80%')
- .height('55%')
- .margin({ top: 15 })
- }
- }
复制代码- import { StudentInsertDialog } from './StudentInsertDialog'
- @CustomDialog
- export struct StudentUpdateDialog {
- private sid: number
- private name: string
- private age: number
- controller: CustomDialogController
- confirm: (id: number, name: string, age: number) => void
- build() {
- Column({ space: 15 }) {
- Text(`${this.sid}`)
- Row() {
- Text('姓名')
- .width('20%')
- TextInput({ text: this.name })
- .width('80%')
- .onChange(value => {
- this.name = value
- })
- }
- .width('80%')
- .justifyContent(FlexAlign.SpaceAround)
- Row() {
- Text('年龄')
- .width('20%')
- TextPicker({ range: StudentInsertDialog.AgeRange, selected: 2 })
- .width('80%')
- .onChange(value => {
- this.age = Number(value)
- })
- }
- .width('80%')
- Row() {
- Button('取消')
- .onClick(() => {
- this.controller.close()
- })
- .backgroundColor(0xcccccc)
- Button('确定')
- .onClick(() => {
- this.confirm(this.sid, this.name, this.age)
- this.controller.close()
- })
- }
- .width('80%')
- .justifyContent(FlexAlign.SpaceAround)
- }
- .justifyContent(FlexAlign.SpaceAround)
- .width('80%')
- .height('65%')
- .margin({ top: 15 })
- }
- }
复制代码 云侧调用
这部分代码可以自动天生,不作为重点解说
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |