发布移动端可视化应用

通过移动端可视化应用的发布功能,可以将已经开发完成的移动端可视化应用发布到线上环境,并进行访问权限的设置,供其他人员在线观看。本文介绍如何发布一个移动端可视化应用。

操作步骤

  1. 登录DataV控制台
  2. 我的可视化页面中,选择一个可视化应用,单击编辑

  3. 在移动端画布编辑器中,单击页面右上角的发布图标。

    发布
  4. 发布对话框中,单击发布大屏

    发布大屏
    说明

    如果是首次发布可视化应用,系统会弹出发布成功的对话框,在对话框中您可以单击前往快照管理查看快照,如果无需查看请单击取消进入发布页面。当首次发布可视化应用时出现发布失败的情况,您可以将当前页面的DataV网址从HTTP协议切换成HTTPS协议网址后再重新选择发布。前往移动端快照管理

  5. 发布成功后,系统会开启已发布开关,并生成分享链接和二维码。

  6. 扫描二维码访问您的移动端可视化应用。

    单击二维码可展示当前可视化应用的二维码,扫描该二维码即可在线访问您的可视化应用。

    image
  7. 在线访问您的移动端可视化应用。

    单击分享链接右侧的复制图标,打开浏览器,将复制的链接粘贴到地址栏中,即可在线访问您的移动端可视化应用。

    image
    说明

    可视化应用项目发布后,如果您想更换分享链接,可单击分享链接左侧的重新生成链接重新生成链接)图标,重新生成一个分享链接。重新生成后,旧的分享链接将不可用,请使用新的分享链接访问目标可视化应用。

  8. 可选,可视化应用分享成功后,您可以配置发布快照的参数内容,还可以进行访问限制分享信息加载页设置的配置。

发布快照

设置分享链接后,可以配置发布快照,指定访问者看到的可视化应用版本(默认为快照发布版本)。屏幕的内容会锁定在快照创建的那一刻。 image

重要

存档之后,屏幕内容的编辑和修改不会同步到历史快照中,可作为稳定预览版本的备份。

具体操作方式如下。

  1. 发布对话框中,在发布快照列表中,选择一个已存档的历史快照即可完成该历史快照的发布。

    • 如果当前可视化应用没有历史快照,系统会将当前编辑器的内容作为第一个快照进行发布。

    • 如果当前可视化应用有历史快照,系统会自动发布最新一条快照。

  2. 单击下方覆盖已发布快照,把已发布快照内的可视化应用的内容变成当前编辑页下的内容。

  3. 单击下方自动新增快照并发布,自动新增一个快照并选中新增的快照后立刻发布。

  4. 单击下方管理快照,可在管理快照界面管理多个历史快照,详情请参见快照管理

快照管理

单击发布对话框内的管理快照,或者您也可以单击可视化应用编辑器右上角生成快照右侧的管理快照图标(管理快照下拉框),然后在快照管理对话框内可进行如下快照管理操作。

重要

当在管理快照界面内,单击新增快照或修改快照,显示新增或修改快照失败时,您可以将当前页面的DataV网址从HTTP协议切换成HTTPS协议网址后再重新操作。

  • 查看额度:在快照管理对话框右上角可以查看管理快照界面内剩余可创建快照的额度。一旦快照数量达到上限后无法新增快照,需要删除不需要的快照。

    说明

    不同版本快照额度的数量不同。

    • 企业版:不超过3个。

    • 专业版:不超过10个。

    • 尊享版:不超过10个。

  • 新增快照:在快照管理对话框中单击新增快照即可新增一个历史快照。

  • 覆盖已发布快照:单击覆盖已发布快照,编辑器的内容覆盖发布页快照原有的内容,即更新发布页内容,并且实时生效。更新内容包括画布编辑器配置、数据源配置、蓝图编辑器配置。覆盖快照

  • 发布或关闭快照:选中管理栏内某个历史快照,单击右侧发布快照图标可快捷发布可视化应用或切换发布的快照,切换后,发布页内容将切换成对应快照的内容,再次单击图标即可关闭快照。

  • 锁定快照:单击某个历史快照右侧的锁定快照图标即可锁定快照,快照锁定后,不可删除和覆盖。

  • 批量删除:在管理界面内多选或全选快照后,单击下方批量删除图标可进行快照批量删除。批量删除功能无法删除已发布和被锁定的快照。

    说明

    已发布的快照无法被删除。

    批量删除
    重要

    目前仅支持切换快照,不具备回滚的功能,删除快照后无法恢复,请谨慎操作。

  • 注释快照:可单击编辑注释图标,自定义添加快照的注释内容。注释图标

访问限制

DataV的发布功能提供了四种分享可视化应用的方式:

  • 公开分享(默认)。

  • 密码访问分享。

  • 通过Token验证分享。

  • IP白名单访问分享。

重要

仅企业版及以上版本支持访问限制功能。

密码访问

  1. 发布对话框中,打开访问密码image

  2. 访问密码输入框中,输入您的验证密码。

    密码长度为6位以上,且必须具备以下三个条件:

    • 至少包含一个英文大写字母A~Z。

    • 至少包含一个英文小写字母a~z。

    • 至少包含一个数字0~9。

    密码设置成功后,系统会提示已设置访问限制

  3. 可选:配置验证有效期

    重要

    只有密码设置成功或开启Token验证后,才可配置验证有效期

    • 选中验证有效期,可以设置密码的有效期,最长为32小时。访问者首次输入密码且成功访问可视化应用后,在设置的有效期时间内,可任意访问该可视化应用而无需输入密码。

    • 去选中验证有效期,每次访问都需要输入密码。

    密码设置成功后,当您再次访问可视化应用的分享链接时,系统会提示需要输入密码。密码访问大屏页面

通过Token验证

您可以通过Token验证的方式,将可视化应用的访问权限与您的权限体系进行集成。

发布对话框中,打开通过Token验证开关,即可开启Token验证。Token验证开启后,您可进行如下操作:

  • 获取Token验证码。

    打开通过Token验证开关后,DataV会生成一个Token,如下图所示。您需要记录这个Token,以备后用。获取Token验证码

  • (可选)配置验证有效期

    • 选中验证有效期,可自定义调整Token验证的有效期,最长设置为32小时。访问者首次进行Token验证并成功访问可视化应用后,在设置的有效期时间内,可任意访问该可视化应用而无需再次进行验证。设置TOKEN有效期限

    • 去选中验证有效期,每次访问都需要通过验证。

Token验证开启后,再次打开可视化应用的分享页面,会收到一个Access Denied消息,表示您的访问被拒绝了。如果想要打开您的页面,需要完成以下步骤。

重要

为了防止重放攻击,请确保您的服务器时间为东8区标准时间。DataV只会提供1分钟的误差,如果时间误差超过1分钟将会验证失败。

  1. 发布可视化应用,记录可视化应用编码(URL的最后一段)。

  2. 将编码与当前时间(毫秒)连起来,并用 |(竖线)分隔开。

  3. 使用Token通过HMAC-SHA256 base64,对上一步得到的Token验证码进行加密。

  4. 将时间和加密后的签名分别命名为_datav_time_datav_signature

  5. 将它们依次放入URLquerystring中。

    重要

    如果您的可视化应用URL中需要使用GET的方式传递参数,为了安全性,建议您使用DataV提供的Token参数签名校验,详情请参见DataV分享页Token参数签名校验

    示例代码如下:

    • PHP:

      <?php
        $token = "kBwoX9rFX9v4zbOT0Gjd_wr65DZ****";
        $screenID = "03d1b68faeb09671046d1ef43f58****";
        $time = time()*1000;
        $stringToSign = $screenID.'|'.$time;
        $signature = urlencode(base64_encode(hash_hmac('sha256', $stringToSign, $token, true)));
        $url = "http://datav.aliyuncs.com/share/".$screenID."?_datav_time=".$time."&_datav_signature=".$signature;
      ?>
      <iframe width=100% height=100% src="<?=$url?>"/>
    • Node.js:

      const crypto = require('crypto');
      var token = "Ev97wOUSAtJusc3Vsd9O2ngr_vfV****";
      var screenID ="14c5448c00ecde02b065c231d165****";
      var time = Date.now();
      var stringToSign = screenID +'|'+ time;
      var signature = crypto.createHmac('sha256', token).update(stringToSign).digest().toString('base64');
      var url="http://datav.aliyuncs.com/share/"+ screenID +"?_datav_time="+time+"&_datav_signature="+ encodeURIComponent(signature);
    • Java:

      package com.company;
      import java.security.*;
      import java.util.Date;
      import javax.crypto.*;
      import javax.crypto.spec.SecretKeySpec;
      import org.apache.commons.codec.binary.Base64;
      import java.net.URLEncoder;
      public class TokenTest {
          public static String getSignedUrl(String screenID, String token){
              Date date = new Date();
              Long time = date.getTime();
              String stringToSign = screenID + "|" + time;
              String signature = HMACSHA256(stringToSign.getBytes(), token.getBytes());
              String url = "http://datav.aliyuncs.com/share/"+ screenID +"?_datav_time="+time+"&_datav_signature="+ signature;
              return url;
          }
          /**
           *  使用java原生的摘要实现SHA256加密。
           * @param str加密后的报文。
           * @return
           */
          public static String HMACSHA256(byte[] data, byte[] key)
          {
              try  {
                  SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA256");
                  Mac mac = Mac.getInstance("HmacSHA256");
                  mac.init(signingKey);
                  return URLEncoder.encode(byte2Base64(mac.doFinal(data)));
              } catch (NoSuchAlgorithmException e) {
                  e.printStackTrace();
              } catch (InvalidKeyException e) {
                  e.printStackTrace();
              }
              return null;
          }
          private static String byte2Base64(byte[] bytes){
              return Base64.encodeBase64String(bytes);
          }
          public static void main(String[] args) throws Exception {
              System.out.println(getSignedUrl("screenId", "token"));
          }
      }
    • C#:

      using System;
      using System.Security.Cryptography;
      using System.Text.RegularExpressions;
      using System.Collections.Generic;
      using System.Linq;
      using System.Web;
      using System.Text;
      
      namespace datavToken
      {
          class Program
          {
              static void Main(string[] args)
              {
                  var dic = new Dictionary<string, string>();  // 自定义参数。
                  dic.Add("datav_sign_no", "123998");         // datav_sign_开头,需要签名。
                  dic.Add("datav_sign_lo", "kk");
                  dic.Add("datav_sign_ao", "xx");
      
                  dic.Add("name", "123");   // 不需要签名。
                  // 分享页前缀,屏幕分享id、token,自定义参数字典。
                  Console.WriteLine(GenerateUrl("https://datav.aliyun.com/share/", "ca74bea5e45503070d607795e0****", "66DsL2qjrXRHluSJScv_flOUhn****", dic));
              }
              private static string GenerateUrl(string datavBase, string screenId, string token, Dictionary<string, string> customeParams)
              {
                  string pattern = @"^datav_sign_.*";
                  string timestamp = GetTimeStamp();
      
                  // 参数排序。
                  Dictionary<string, string>.KeyCollection keyCol = customeParams.Keys;
                  List<string> signKeys = new List<string>();
      
                  foreach (var item in keyCol.ToList())
                  {
                      if (Regex.IsMatch(item, pattern))
                      {
                          signKeys.Add(item);
                      }
                  }
      
                  // 按照key排序。
                  signKeys = signKeys.OrderBy(k => k).ToList();
      
                  string paramsSignStr = signKeys.Aggregate("", (total, key) =>
                  {
                      if (total != "")
                      {
                          total += "&";
                      }
                      total += key + "=" + customeParams[key];
                      return total;
                  });
                  //不存在参数认证
                  string signStr = screenId + "|" + timestamp;
                  //存在参数认证
                  //string signStr = screenId + "|" + timestamp + "|" + paramsSignStr;
                  
      
                  var encoding = new System.Text.ASCIIEncoding();
                  byte[] keyByte = encoding.GetBytes(token);
                  byte[] messageBytes = encoding.GetBytes(signStr);
                  string signature;
                  using (var hmacsha256 = new HMACSHA256(keyByte))
                  {
                      byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
                      signature = Convert.ToBase64String(hashmessage);
                  }
      
      
                  var paramDic = new Dictionary<string, string>();
                  paramDic.Add("_datav_time", timestamp);
                  paramDic.Add("_datav_signature", signature);
      
                  foreach (var item in customeParams)
                  {
                      paramDic.Add(item.Key, item.Value);
                  }
                  return datavBase + screenId + "?" + ParseToString(paramDic);
              }
              public static string GetTimeStamp()
              {
                  TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
                  return Convert.ToInt64(ts.TotalMilliseconds).ToString();
              }
              static public string ParseToString(IDictionary<string, string> parameters)
              {
                  IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
                  IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();
      
                  StringBuilder query = new StringBuilder("");
                  while (dem.MoveNext())
                  {
                      string key = dem.Current.Key;
                      string value = dem.Current.Value;
                      if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
                      {
                          query.Append(key).Append("=").Append(HttpUtility.UrlEncode(value)).Append("&");
                      }
                  }
                  string content = query.ToString().Substring(0, query.Length - 1);
      
                  return content;
              }
          }
      }

IP白名单访问

设置启用IP白名单后,发布后的可视化应用仅允许在设置范围内的白名单IP下访问。

  1. 发布对话框中,打开IP白名单

    IP白名单限制
  2. 在下方IP白名单输入框中,输入您的IP,并用“,“号分隔不同的白名单。

    IP白名单设置成功后,当您再次访问可视化应用的分享链接时,如果您使用了非白名单IP访问当前可视化应用,可视化应用页面访问将被拒绝。访问拒绝

分享信息

DataV可视化应用在钉钉客户端内分享发布链接时提供了可自定义修改分享信息内容的功能,详细参数配置介绍如下。

图 1. 分享信息配置内容样例分享信息配置内容举例

图 2. 钉钉客户端分享链接样例展示分享链接样例展示

配置参数

说明

标题

您可以自定义修改即将发布的可视化应用分享链接的标题名称,默认显示为创建该可视化应用时的标题名。

描述

您可以对即将发布的可视化应用分享链接进行简单的内容描述。

图片

您可以对即将发布的可视化应用,通过自定义输入图片URL链接或拖动本地图片到右侧图片栏内,为分享链接设置一张图片。

重要

此处支持添加静态或动态图片,但在分享链接展示中均为静态展示。

重要

如果您分享的卡片未生效,可能是由于钉钉客户端的缓存机制,导致多次修改分享信息。建议您重启钉钉客户端,再进行链接分享。

加载页设置

DataV可视化应用在分享发布链接时提供了可自定义设置加载页内容的功能,详细参数配置介绍如下。

重要

仅专业版及以上版本支持加载页配置功能。

图 3. 加载页配置内容样例加载页案例

图 4. 加载页样例展示加载页展示

配置参数

说明

背景

您可以自定义修改即将发布的可视化应用加载页的背景颜色,支持纯色及渐变色。

Logo

您可以对即将发布的可视化应用加载页的Logo图片,通过自定义输入图片URL链接或拖动本地图片到右侧图片栏内,为Logo设置一张图片。

重要

此处支持添加静态或动态图片,如果设置的是动态图片,在加载页面会动态展示。