华为HarmonyOS打造开放、合规的广告生态 - 激励广告

场景介绍

激励广告是一种全屏幕的视频广告,用户可以选择点击观看,以换取相应奖励。

接口说明

接口名

描述

loadAd(adParam: AdRequestParams, adOptions: AdOptions, listener: AdLoadListener): void

请求单广告位广告,通过AdRequestParams、AdOptions进行广告请求参数设置,通过AdLoadListener监听广告请求回调。

showAd(ad: Advertisement, options: AdDisplayOptions, context?: common.UIAbilityContext): void

展示广告,通过AdDisplayOptions进行广告展示参数设置。

开发步骤

  1. 获取OAID。

    如果想要为用户更精准的推送广告,可以在请求参数AdRequestParams中添加oaid属性。

    如何获取OAID参见获取OAID信息。

    说明

    使用以下示例中提供的测试广告位必须先获取OAID信息。

  2. 请求单广告位广告。

    需要先创建一个AdLoader对象,通过AdLoader的loadAd方法请求广告,最后通过AdLoadListener,来监听广告的加载状态。

    请求广告关键参数如下所示:

    请求广告参数名

    类型

    必填

    说明

    adType

    number

    是

    请求广告类型,激励广告类型为7。

    adId

    string

    是

    广告位ID。

    • 如果仅调测广告,可使用测试广告位ID:testx9dtjwj8hp。
    • 如果要接入正式广告,则需要申请正式的广告位ID。可在应用发布前进入流量变现官网,点击“开始变现”,登录鲸鸿动能媒体服务平台进行申请,具体操作详情请参见展示位创建。

    oaid

    string

    否

    开放匿名设备标识符,用于精准推送广告。不填无法获取到个性化广告。

    示例代码如下所示:
     
    1. import { advertising, identifier } from '@kit.AdsKit';
    2. import { common } from '@kit.AbilityKit';
    3. import { hilog } from '@kit.PerformanceAnalysisKit';
    4. import { BusinessError } from '@kit.BasicServicesKit';
    5. @Entry
    6. @Component
    7. struct Index {
    8. private ads: Array<advertising.Advertisement> = [];
    9. private context = getContext(this) as common.UIAbilityContext;
    10. private oaid: string = '';
    11. aboutToAppear() {
    12. try {
    13. // 使用Promise回调方式获取OAID
    14. identifier.getOAID().then((data: string) => {
    15. this.oaid = data;
    16. hilog.info(0x0000, 'testTag', '%{public}s', 'Succeeded in getting adsIdentifierInfo by promise');
    17. }).catch((error: BusinessError) => {
    18. hilog.error(0x0000, 'testTag', '%{public}s', `Failed to get adsIdentifierInfo, message: ${error.message}`);
    19. })
    20. } catch (error) {
    21. hilog.error(0x0000, 'testTag', '%{public}s', `Catch err, code: ${error.code}, message: ${error.message}`);
    22. }
    23. }
    24. build() {
    25. Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
    26. Row() {
    27. Button('requestAd').onClick(() => {
    28. let load: advertising.AdLoader = new advertising.AdLoader(this.context);
    29. this.requestAd(load);
    30. }).width('45%')
    31. }
    32. }
    33. }
    34. private requestAd(adLoader: advertising.AdLoader): void {
    35. const adRequestParam: advertising.AdRequestParams = {
    36. // 广告类型:激励广告
    37. adType: 7,
    38. // 'testx9dtjwj8hp'为测试专用的广告位ID,App正式发布时需要改为正式的广告位ID
    39. adId: 'testx9dtjwj8hp',
    40. // 开放匿名设备标识符
    41. oaid: this.oaid
    42. };
    43. const adOption: advertising.AdOptions = {
    44. // 设置是否请求非个性化广告
    45. nonPersonalizedAd: 0,
    46. // 是否允许流量下载0:不允许,1:允许,不设置以广告主设置为准
    47. allowMobileTraffic: 0,
    48. // 是否希望根据 COPPA 的规定将您的内容视为面向儿童的内容: -1默认值,不确定 0不希望 1希望
    49. tagForChildProtection: -1,
    50. // 是否希望按适合未达到法定承诺年龄的欧洲经济区 (EEA) 用户的方式处理该广告请求: -1默认值,不确定 0不希望 1希望
    51. tagForUnderAgeOfPromise: -1,
    52. // 设置广告内容分级上限: W: 3+,所有受众 PI: 7+,家长指导 J:12+,青少年 A: 16+/18+,成人受众
    53. adContentClassification: 'A'
    54. };
    55. const adLoaderListener: advertising.AdLoadListener = {
    56. onAdLoadFailure: (errorCode: number, errorMsg: string) => {
    57. hilog.error(0x0000, 'testTag', '%{public}s',
    58. `Failed to request ad, message: ${errorMsg}, error code: ${errorCode}`);
    59. },
    60. onAdLoadSuccess: (ads: Array<advertising.Advertisement>) => {
    61. hilog.info(0x0000, 'testTag', '%{public}s', `Succeeded in requesting ad`);
    62. this.ads.push(...ads);
    63. },
    64. };
    65. adLoader.loadAd(adRequestParam, adOption, adLoaderListener);
    66. }
    67. }

  3. 事件订阅。

    开发者需要在App中订阅com.huawei.hms.pps.action.PPS_REWARD_STATUS_CHANGED事件来监听激励广告页面变化并接收奖励信息。示例代码中的订阅方法registerPPSReceiver()需要在每次展示广告前调用 。

    在订阅到公共事件后,可以从CommonEventData的parameters参数中使用"reward_ad_status"作为key值获取激励广告页面变化状态,使用"reward_ad_data"作为key值获取奖励信息,属性rewardType用来获取奖励物品的名称,rewardAmount用来获取奖励物品的数量。

    示例代码如下所示:

     
    1. import { commonEventManager, BusinessError } from '@kit.BasicServicesKit';
    2. import { hilog } from '@kit.PerformanceAnalysisKit';
    3. const KEY_REWARD_DATA = "reward_ad_data";
    4. const KEY_REWARD_STATUS = "reward_ad_status";
    5. export class RewardAdStatusHandler {
    6. // 用于保存创建成功的订阅者对象,后续使用其完成订阅及退订的动作
    7. private subscriber: commonEventManager.CommonEventSubscriber | null = null;
    8. // 订阅方法,需要在每次展示广告前调用
    9. public registerPPSReceiver(): void {
    10. if (this.subscriber) {
    11. this.unRegisterPPSReceiver();
    12. }
    13. // 订阅者信息
    14. const subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {
    15. events: ['com.huawei.hms.pps.action.PPS_REWARD_STATUS_CHANGED'],
    16. // publisherBundleName被设置为"com.huawei.hms.adsservice",这意味着只有来自该包名的事件才会被订阅者接受和处理。
    17. // 如果没有明确声明publisherBundleName,那么订阅者可能会收到来自其它包名的伪造事件,从而导致安全性问题或误导。
    18. publisherBundleName: 'com.huawei.hms.adsservice'
    19. };
    20. // 创建订阅者回调
    21. commonEventManager.createSubscriber(subscribeInfo, (err: BusinessError, commonEventSubscriber:
    22. commonEventManager.CommonEventSubscriber) => {
    23. if (err) {
    24. hilog.error(0x0000, 'testTag', '%{public}s',
    25. `createSubscriber error, code: ${err.code}, message: ${err.message}`);
    26. return;
    27. }
    28. hilog.info(0x0000, 'testTag', '%{public}s', 'Succeeded in creating subscriber');
    29. this.subscriber = commonEventSubscriber;
    30. // 订阅公共事件回调
    31. if (!this.subscriber) {
    32. hilog.warn(0x0000, 'testTag', '%{public}s', 'Need create subscriber');
    33. return;
    34. }
    35. commonEventManager.subscribe(this.subscriber, (err: BusinessError, commonEventSubscriber:
    36. commonEventManager.CommonEventData) => {
    37. if (err) {
    38. hilog.error(0x0000, 'testTag', '%{public}s', `Subscribe error, code: ${err.code}, message: ${err.message}`);
    39. } else {
    40. hilog.info(0x0000, 'testTag', '%{public}s', 'Subscribe data');
    41. const status: string = commonEventSubscriber?.parameters?.[KEY_REWARD_STATUS];
    42. switch (status) {
    43. case AdStatus.AD_OPEN:
    44. hilog.info(0x0000, 'testTag', '%{public}s', 'onAdOpen');
    45. break;
    46. case AdStatus.AD_CLICKED:
    47. hilog.info(0x0000, 'testTag', '%{public}s', 'onAdClick');
    48. break;
    49. case AdStatus.AD_CLOSED:
    50. hilog.info(0x0000, 'testTag', '%{public}s', 'onAdClose');
    51. this.unRegisterPPSReceiver();
    52. break;
    53. case AdStatus.AD_REWARDED:
    54. const rewardData: Record<string, string | number> = commonEventSubscriber?.parameters?.[KEY_REWARD_DATA];
    55. const rewardType: string = rewardData?.rewardType as string;
    56. const rewardAmount: number = rewardData?.rewardAmount as number;
    57. hilog.info(0x0000, 'testTag', '%{public}s',
    58. `onAdReward, rewardType: ${rewardType}, rewardAmount: ${rewardAmount}`);
    59. break;
    60. case AdStatus.AD_VIDEO_START:
    61. hilog.info(0x0000, 'testTag', '%{public}s', 'onAdVideoStart');
    62. break;
    63. case AdStatus.AD_COMPLETED:
    64. hilog.info(0x0000, 'testTag', '%{public}s', 'onAdCompleted');
    65. break;
    66. default:
    67. break;
    68. }
    69. }
    70. });
    71. });
    72. }
    73. // 取消订阅
    74. public unRegisterPPSReceiver(): void {
    75. commonEventManager.unsubscribe(this.subscriber, (err: BusinessError) => {
    76. if (err) {
    77. hilog.error(0x0000, 'testTag', '%{public}s', `Unsubscribe error, code: ${err.code}, message: ${err.message}`);
    78. } else {
    79. hilog.info(0x0000, 'testTag', '%{public}s', 'Succeeded in unsubscribing');
    80. this.subscriber = null;
    81. }
    82. });
    83. }
    84. }
    85. enum AdStatus {
    86. AD_OPEN = 'onAdOpen',
    87. AD_CLICKED = 'onAdClick',
    88. AD_CLOSED = 'onAdClose',
    89. AD_REWARDED = 'onAdReward',
    90. AD_VIDEO_START = 'onVideoPlayBegin',
    91. AD_COMPLETED = 'onVideoPlayEnd'
    92. }

  4. 展示广告。

    ads为步骤2请求到的广告信息,调用showAd方法来展示广告。示例代码如下所示:
     
    1. import { advertising } from '@kit.AdsKit';
    2. import { common } from '@kit.AbilityKit';
    3. @Entry
    4. @Component
    5. struct Index {
    6. private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
    7. // 步骤2中请求到的广告内容
    8. private ads: Array<advertising.Advertisement> = [];
    9. private displayOptions: advertising.AdDisplayOptions = {
    10. // 激励广告视频播放是否静音
    11. mute: true
    12. };
    13. build() {
    14. Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
    15. Row() {
    16. Button('showAd').onClick(() => {
    17. this.showAd();
    18. }).width('45%')
    19. }
    20. }
    21. }
    22. private showAd() {
    23. let load: advertising.AdLoader = new advertising.AdLoader(this.context);
    24. // 此处ads[0]表示请求到的第一个广告,用户根据实际情况选择
    25. advertising.showAd(this.ads[0], this.displayOptions, this.context);
    26. }
    27. }

校验激励广告服务端验证回调

服务端验证回调是指鲸鸿动能平台发送给媒体服务器的网址请求,其中带有特定的查询参数,用来通知媒体服务器某位用户因为与激励视频广告互动而应予以奖励,从而规避欺骗的行为。

奖励用户

  • 在给用户发奖励时,要把握好用户体验和奖励验证之间的平衡。由于服务器端回调会存在延迟的情况,因此我们建议客户端立即奖励用户,同时在收到服务器端回调时对所有奖励进行验证。这种做法可确保奖励符合发放条件,同时提供良好的用户体验。
  • 对于某些应用而言,奖励是否达到发放条件非常重要,用户可适当接受延迟。这时,推荐做法是等待服务器端回调完成验证,再向用户发放奖励。

校验服务端验证回调

说明

App上架至华为应用市场(AppGallery)时间超过12小时才可以收到回调。

  1. 设置激励广告的奖励配置。

    您在鲸鸿动能媒体服务平台上申请激励视频广告位时选择“媒体管理(点击媒体名)> 新增展示位 > 选择激励视频(点击下一步,进入编辑页面)”,设置奖励类型和奖励数量,并点击“高级设置”,设置服务器端验证的URL。如下图:

  2. (可选)设置自定义数据customData和userId。

    ads为步骤2请求到的广告信息,调用showAd方法来展示广告。

    您在App中展示激励广告之前设置自定义数据customData和userId。示例代码如下所示:

     
    1. import { advertising } from '@kit.AdsKit';
    2. import { common } from '@kit.AbilityKit';
    3. @Entry
    4. @Component
    5. struct Index {
    6. private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
    7. // 步骤2中请求到的广告内容
    8. private ads: Array<advertising.Advertisement> = [];
    9. private displayOptions: advertising.AdDisplayOptions = {
    10. // 激励广告视频播放是否静音
    11. mute: true,
    12. // 设置自定义数据
    13. customData: 'CUSTOM_DATA',
    14. // 设置自定义数据
    15. userId: '1234567'
    16. };
    17. build() {
    18. Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
    19. Row() {
    20. Button('showAd').onClick(() => {
    21. this.showAd();
    22. }).width('45%')
    23. }
    24. }
    25. }
    26. private showAd() {
    27. let load: advertising.AdLoader = new advertising.AdLoader(this.context);
    28. // 此处ads[0]表示请求到的第一个广告,用户根据实际情况选择
    29. advertising.showAd(this.ads[0], this.displayOptions, this.context);
    30. }
    31. }

    说明

    如果没有设置customData和userId,不影响发放奖励事件上报但是服务端验证的参数中没有这两个字段。如果设置customData和userId,必须在展示广告之前设置并且URLEncode之后,长度不超过1024个字符,否则影响服务端验证。

  3. 获取要验证的内容。

    用户观看完激励广告时,鲸鸿动能平台服务端会把需要验证的参数以及keyId和sign传给媒体提供的URL:https://www.example.com/feedback(即步骤1中配置的验证URL)。请求体样例:

     
    1. {
    2. "adId" : "testx9dtjwj8hp",
    3. "data" : "CUSTOM_DATA",
    4. "keyId" : "12345678",
    5. "rewardAmount" : "10",
    6. "rewardName" : "金币",
    7. "sign" : "OA33u6mypnhE4hbmF32N/ibYi1uXt72nDDyYMwjDI6JXVVFKePZYo4F7Fuk2MaG......",
    8. "uniqueId" : "3361626337333932313435313430373438383561376265636130393939313166",
    9. "userId" : "1234567"
    10. }

    服务器端验证回调查询参数说明:

    参数名称

    类型

    是否必选

    描述

    adId

    String

    是

    激励视频广告位ID

    data

    String

    否

    自定义数据字符串

    keyId

    String

    是

    验证回调的密钥

    rewardAmount

    String

    否

    奖励数量

    rewardName

    String

    否

    奖励奖品

    sign

    String

    是

    回调的签名

    uniqueId

    String

    是

    获奖事件生成的十六进制的标识符

    userId

    String

    否

    用户ID

  4. 组装验证参数

    验证内容(除sign、keyId)格式顺序如下:

    adId={adId}&data={data}&rewardAmount={rewardAmount}&rewardName={rewardName}&uniqueId={uniqueId}&userId={userId}

    其中‘{}’里面表示参数的值,且参数顺序不能变。如果参数为null或者空字符串,则URL中不拼接该参数。然后用SHA256计算散列值,得到paramContentData。示例代码如下所示:

     
    1. String adId = request.getParameter("adId");
    2. String data = request.getParameter("data");
    3. ...
    4. String userId = request.getParameter("userId");
    5. String param = "adId=" + adId + "&data=" + data + "&rewardAmount=" + rewardAmount + "&rewardName=" + rewardName + "&uniqueId=" + uniqueId + "&userId=" + userId;
    6. String sha256Value = Sha256Util.digest(param);
    7. byte[] paramContentData = sha256Value.getBytes(Charset.forName("UTF-8"));
  5. 获取公钥列表。

    a. 在鲸鸿动能媒体服务平台上查看对应的帐户信息时选择“账户”。

    通过点击上图所示的“获取密钥”按钮弹出如下所示的弹框,获取“开发者ID”和“密钥”。

    b. 您根据应用分发区域不同,需要使用对应站点的接口URL去获取公钥列表,不同站点对应的接口URL如下所示:

    • 中国:https://ppscrowd-drcn.op.hicloud.com/action-lib-track/publickeys

    将body通过密钥进行HMAC-SHA256加密得到签名,替换到Authorization中,并设置“开发者ID”和Authorization到Header中。示例代码如下所示:

     
    1. String data = "";
    2. String url = "https://ppscrowd-dre.op.dbankcloud.com/action-lib-track/publickeys";
    3. String authorization = "Digest validTime=\"{0}\", response=\"{1}\"";
    4. // 开发者ID
    5. String userId = "YOUR_PUBLISHER_ID";
    6. // 密钥
    7. String key = "YOUR_KEY";
    8. HttpClient httpclient = HttpClients.createDefault();
    9. HttpGet request = new HttpGet();
    10. try {
    11. // 将body通过密钥进行HMAC-SHA256加密得到签名,替换到Authorization中
    12. String validTime = String.valueOf(System.currentTimeMillis());
    13. String body = validTime + ":/publickeys";
    14. byte[] keyBytes = Base64.decodeBase64(key);
    15. byte[] bodyBytes = body.getBytes(Charsets.UTF_8);
    16. Mac mac = Mac.getInstance("HmacSHA256");
    17. SecretKey secretKey = new SecretKeySpec(keyBytes, "HmacSHA256");
    18. mac.init(secretKey);
    19. byte[] signatureBytes = mac.doFinal(bodyBytes);
    20. String signature = (signatureBytes == null) ? null : Hex.encodeHexString(signatureBytes);
    21. authorization = MessageFormat.format(authorization, validTime, signature);
    22. // 设置开发者ID和Authorization到Header中
    23. request.setURI(new URI(url));
    24. request.setHeader("userId", userId);
    25. request.setHeader("Authorization", authorization);
    26. HttpResponse response = httpclient.execute(request);
    27. data = EntityUtils.toString(response.getEntity());
    28. } catch (Exception e) {
    29. System.out.println(e.getMessage());
    30. }

    返回data消息体(publicKey已匿名化):

     
    1. {
    2. "keys": [
    3. {
    4. "keyId":"12345678",
    5. "publicKey":"LS0tLS1*******************************************************"
    6. },
    7. {
    8. "keyId": "22345678",
    9. "publicKey":"LS0tLS1*******************************************************"
    10. }
    11. ]
    12. }

    返回消息结构体:

    参数名称

    类型

    是否必选

    描述

    keys

    List<key>

    是

    返回公钥列表

    • key结构体:

    参数名称

    类型

    是否必选

    描述

    keyId

    String

    是

    密钥ID

    publicKey

    String

    是

    公钥

  6. 执行验证。

    a. 根据keyId从公钥列表中找到对应的base64编码后的publicKey。

    b. 将paramContentData、publicKey、sign和SHA256withRSA数字签名算法的入参,执行验证。

    示例代码如下所示:

     
    1. public static boolean verify(byte[] data, String publicKey, String sign, String signatureAlgorithm) {
    2. try {
    3. byte[] keyBytes = base64Decode(publicKey);
    4. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
    5. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    6. PublicKey publicK = keyFactory.generatePublic(keySpec);
    7. Signature signature = Signature.getInstance(signatureAlgorithm);
    8. signature.initVerify(publicK);
    9. signature.update(data);
    10. return signature.verify(base64Decode(sign));
    11. } catch (InvalidKeyException | SignatureException | UnsupportedEncodingException | InvalidKeySpecException | NoSuchAlgorithmException e) {
    12. return false;
    13. }
    14. }
    15. private static byte[] base64Decode(String encoded) throws UnsupportedEncodingException {
    16. return Base64.decodeBase64(encoded.getBytes("UTF-8"));
    17. }

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

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

相关文章

自由学习记录(18)

动画事件的碰撞器触发 Physics 类的常用方法 RaycastHit hit; if (Physics.Raycast(origin, direction, out hit, maxDistance)) {Debug.Log("Hit: " hit.collider.name); } Physics.Raycast&#xff1a;从指定点向某个方向发射射线&#xff0c;检测是否与碰撞体…

【elkb】创建用户和角色

在使用中我们不能把超管的用户信息给到所有者&#xff0c;我们需要为不用的使用场景创建不同的用户。 登录管理员用户 打开管理页面 创建角色 点击角色&#xff0c;创建角色 填写角色信息 设置Kibana 权限 最后点击创建角色 创建用户 点击用户--->创建用户 填写信息 登录…

【论文复现】语言模型中的多模态链式推理

&#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步&#xff0c;喜爱音乐、摄影的一位博主。 &#x1f4d7;本文收录于论文复现系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏C语言初阶、C…

Mysql常用语法一篇文章速成

文章目录 前言前置环境数据库的增删改查查询数据查询所有条件查询多条件查询模糊查询分页查询排序查询分组查询⭐️⭐️关联查询关联分页查询 添加数据insert插入多条记录不指定列名(适用于所有列都有值的情况) 更新数据更新多条记录更新多个列更新不满足条件的记录 删除统计数…

【每日C/C++问题】

一、 结构体和联合体有什么区别&#xff1f;能否在声明过程当中缺省名字&#xff1f;&#xff08;需要写清楚使用方法&#xff09; 结构体的各个成员占用不同的内存空间&#xff0c;总大小是所有成员大小之和&#xff08;结构体字节对齐&#xff09;&#xff1a; typedef str…

Docker小记

Docker就是将程序和环境一同打包成一个独立的容器&#xff0c;容器和容器之间独立&#xff0c;可以理解为一个app,一个手机就是一个pod&#xff0c;一个pod上可以运行多个容器&#xff0c;容器之间共享磁盘和网络&#xff0c;每个容器仍然运行在自己的进程空间中&#xff0c;有…

Spring Boot代理问题

在 Spring Boot 2.x 中&#xff0c;AOP&#xff08;面向切面编程&#xff09;默认使用 CGLIB&#xff08;Code Generation Library&#xff09;来实现类的代理。CGLIB 代理是通过在运行时生成目标类的子类来增强目标类的方法。这种方式允许对没有实现接口的类进行代理。以下是一…

“不可原谅的漏洞”论文导读

文章《Unforgivable Vulnerabilities》由Steve Christey 2007年撰写&#xff0c;主要探讨了在软件安全领域中那些本可以避免的漏洞&#xff0c;即“不可原谅的漏洞”。这些漏洞通常由于开发者忽视了基本的安全开发实践而存在&#xff0c;且容易被发现和利用。文章提出了建立一套…

正则表达式(Regular Expressions)

正则表达式&#xff08;Regular Expressions, 简称 Regex&#xff09;是一种用于字符串匹配和处理的强大工具&#xff0c;通过特定的模式&#xff08;Pattern&#xff09;描述字符串。它在验证、替换、分割、提取等操作中非常有效。以下是一些基本概念和常见使用场景&#xff1…

文件夹无法访问?全面解析与高效恢复策略

一、文件夹无法访问的困境 在日常的计算机使用中&#xff0c;我们时常会遇到文件夹无法访问的尴尬情况。这种故障表现为双击文件夹时&#xff0c;系统毫无反应&#xff0c;或者弹出“无法访问&#xff0c;拒绝访问”的错误提示。更令人头疼的是&#xff0c;有时文件夹内的文件…

设计模式 策略模式 场景Vue (技术提升)

策略模式 (建议复制编辑器查看更佳) 在给定的 Vue.js 组件代码中&#xff0c;根据optionKey的不同值&#xff0c;展示了不同的表单内容并定义了不同的表单验证规则。在这里&#xff0c;optionMap对象内部定义了不同的策略&#xff08;addAccount、editAccount、editPassword&am…

万字长文详解Hive聚合函数 grouping sets、cube、rollup原理、语法、案例和优化

目录 原理与语法 使用场景 多维度报表生成 复杂的数据分析 实际案例 原理与语法 与GROUPINGSETS的区别 实际案例 原理与语法 与CUBE的对比 实际案例 执行效率比较 优化建议 Hive提供了三个强大的高级聚合函数: GROUPING SETS 、 CUBE 和 ROLLUP ,用于处理复杂的…

长短期记忆网络(LSTM)如何在连续的时间步骤中处理信息

长短期记忆网络&#xff08;LSTM&#xff09;如何在连续的时间步骤中处理信息 长短期记忆网络&#xff08;LSTM&#xff09;是一种高级的循环神经网络&#xff08;RNN&#xff09;&#xff0c;设计用来解决传统RNN在处理长时间序列数据时遇到的梯度消失或爆炸问题。LSTM通过其…

Spring @RequestMapping 注解

文章目录 Spring RequestMapping 注解一、引言二、RequestMapping注解基础1、基本用法2、处理多个URI 三、高级用法1、处理HTTP方法2、参数和消息头处理 四、总结 Spring RequestMapping 注解 一、引言 在Spring框架中&#xff0c;RequestMapping 注解是构建Web应用程序时不可…

飞牛OS在Docker中安装ODOO ERP系统

从后台的Docker镜像库安装一直报错误&#xff0c;无法安装成功&#xff0c;使用以下命令进入OS系统&#xff0c;以下是执行脚本: Start a PostgreSQL server $ docker run -d -e POSTGRES_USERodoo -e POSTGRES_PASSWORDodoo -e POSTGRES_DBpostgres --name db postgres:15 S…

cookie、session、http简单理解

Cookie:以key-value键值对的形式存储一些文本信息数据 并将数据保存在客户端(浏览器) sessionid&#xff08;身份&#xff09; 数据库中有一个seesion表&#xff0c;存放着所有的Session数据&#xff0c; 而sessionid就对应数据库数据这个id&#xff0c;服务器找到对应id的Ses…

VLAN间通信以及ospf配置

目录 1.基础知识介绍 1.1 什么是VLAN&#xff1f; 1.2 VLAN有什么用&#xff1f; 1.3 不同VLAN如何实现通信&#xff1f; 1.4 什么是路由汇总&#xff1f; 1.4.1 路由汇总的好处&#xff1a; 2. 实验 2.1 网络拓扑设计 2.2 实验配置要求 2.2.1 三层交换配置&#xff…

Redis的数据结构

一、Redis概述 Redis&#xff0c;英文全称是Remote Dictionary Server&#xff08;远程字典服务&#xff09;&#xff0c;是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库&#xff0c;并提供多种语言的API。与MySQL数据库不同的是&a…

十四届蓝桥杯STEMA考试Python真题试卷第二套第一题

来源&#xff1a;十四届蓝桥杯STEMA考试Python真题试卷第二套编程第一题 题目描述&#xff1a; 给定一个字符串&#xff0c;输出字符串中最后一个字符。 输入描述&#xff1a; 输入一个字符串 输出描述&#xff1a; 输出字符串中最后一个字符 样例输入&#xff1a; hgf 样…

Spring Boot 注解大全:全面解析 Spring Boot 常用注解及其应用场景

Spring Boot 注解大全:全面解析 Spring Boot 常用注解及其应用场景 简介 Spring Boot 是一个基于 Spring 框架的简化开发框架,它旨在简化 Spring 应用的初始搭建和开发过程。Spring Boot 提供了一系列的注解,使得开发者可以更加方便地进行应用开发和配置。本文将详细介绍 S…