Liferay DXP Soy porlet系列(四)使用Promise对象访问Liferay web service

来源:互联网 发布:debian安装软件命令 编辑:程序博客网 时间:2024/05/22 11:54
在这篇教程中,我们会讨论如何使用Promise对象来访问Liferay的web service.

在我们开展详细讨论之前,请注意,我现在所使用的是Liferay DXP DE-15。因为在这个补丁中包含了不少关于soy开发体验的改进。

之前我们讨论过了一些话题:如何创建Soy portlet,如何使用第三方js类库,如何利用Servce Builder创建远程服务。

在本篇教程中,我们将把所学过的知识连贯起来,来创建一个portlet来可视化我们的数据。数据来源于我们的web service。之前的文章,我们已经讲过关于使用Service Builder创建一个远程服务。Liferay作为服务的提供者(Provider)。现在我们将会使Liferay作为服务的消费者(Consumer)来调用这个服务。当然这个服务也不仅限于在Liferay本身的平台上,它可以是任何系统。这也是Liferay支持整合第三方系统的一种方式。Liferay的强项是作为数字化的用户体验平台,提供一致性的用户体验。第三方系统也各有在自己领域的强项。所以将系统整合在一起,可以为用户提供功能强大并且有优秀用户体验的平台。

这篇教程可以满足现实当中的需求可以是:
用户信息板,信息板内容来自第三方系统。
响应式设计信息板(bootstrap)
即插即用服务和个性化配置(osgi micro-service, portlet)
灵活的技术选项(NodeJS NPM)

Let's Go!

第一步:利用我们现有的知识来创建一个ChartJS portlet
Step 1, User theknowledgeyou already have to create a chart JS portlet
正如我们在之前教程中学过的,我们来创建一个soy portlet项目,项目名称叫做monthly-trading-web。注意一下package.json中,metal-cli的版本,是4.0.1。这个版本修复了CRLF和LF的编译问题。

{
 "dependencies": {
  "metal-component": "^2.10.0",
  "metal-soy": "^2.10.0",
  "chart.js": "^2.4.0"
 },
 "devDependencies": {
  "liferay-module-config-generator": "^1.2.1",
  "metal-cli": "^4.0.1"
 },
 "name": "monthly-trading",
 "version": "1.0.0"
}
在此向我的好友Chema Balsas和Liferay UI团队致敬,感谢他们为优化开发体验所做出的努力!

第二步:找到你的服务和数据

正如我们之前文章中所做的,我们可以通过/api/jsonws添加一些数据样本。远程服务的上下文是Banking。方法名称是add-monthly-trading。

在添加完数据样本之后,可以点击 get-monthly-trading-by-year方法,然后输入年份测试数据输出。然后点击URL Example来获取服务URL。


注意一下p_auth。这个是服务的验证标志(auth token),也有叫认证令牌的。

第三步:将服务URL传递给JS

在portlet类中的render方法中,我们可以将这个URL存进template对象,这样soy模板和es.js就可以收到这个变量了。
public void render(
   RenderRequest renderRequest, RenderResponse renderResponse)
  throws IOException, PortletException {

   String tradingYear = "2017";
   String pauth = AuthTokenUtil.getToken(PortalUtil.getHttpServletRequest(renderRequest));

   String portletNamespace = renderResponse.getNamespace();

   template.put("remoteURL", "/api/jsonws/banking.monthlytrading/get-monthly-trading-by-year/year/" + tradingYear + "?p_auth=" + pauth);
   template.put("tradingYear", tradingYear);
   template.put("portletNamespace", portletNamespace);
   super.render(renderRequest, renderResponse);
  }

在es.js中,我们可以在constructor方法中接收这个变量。
constructor(opt_config) {

  super(opt_config);

  let remoteURL = opt_config.remoteURL;
  let tradingYear = opt_config.tradingYear;
  this.portletNamespace = opt_config.portletNamespace;
  this.createRemoteChart_(remoteURL, tradingYear); // Hasn't been defined yet.
 }

第四步,创建promise对象

什么是Promise对象?
"Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers )。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象"--MDN

在Soy portlet中我们可以利用ES6语法来使用Promise对象。
在我们的es.js文件中,我们这么定义并且返回promise对象:
首先需要导入Promise对象。
import { CancellablePromise } from 'metal-promise/src/promise/Promise';
这个使用的是metaljs的cancellable promise。

然后可以定义一个方法,并且返回promise对象。
/**
  * Get remote trading data
  * @protected
  * @param {String} remoetURL
  * @return {CancellablePromise} A promise that will resolve save permise
  */
 getChartData_(remoteURL) {
  let promise = new CancellablePromise((resolve, reject) => {
   let requestConfig = {
    contentType: false,
    dataType: "json",
    processData: false,
    type: "GET",
    url: remoteURL
   };

   AUI.$.ajax(requestConfig)
    .done((data) => resolve(data))
    .fail((jqXHF, status, error) => reject(error));
  });

  return promise;
 }
注意一下,我们使用的是Liferay内置的jQuery。在Liferay中我们已经在AUI中沙盒化了jQuery(v2.4.1)。当需要调用jQuery方法时,使用AUI.$....就可以。并且如果你想使用自己的其他版本的jQuery时,不会出现命名冲突。
第五步:实现你的Promise

接下来我们就要根据web serivce返回的数据写我们的UI逻辑了。
/**
  * Create Chart with data url
  *
  * @param {String} remoteURL
  * @protected
  */
 createRemoteChart_(remoteURL, tradingYear) {
  this.getChartData_(remoteURL).then(data => {

   let chartcanvas = document.getElementById(this.portletNamespace + "monthly-trading-chart");

   let labels = Array.from(data, d => d.month);
   let bgColor = this.getPreferedColors_(data.length, 0.3);
   let borderColor = this.getPreferedColors_(data.length, 0.8);
   let dataValue = Array.from(data, d => d.volume);

   let chartData = {
    labels: labels,
    datasets: [
     {
      label: "Monthly Trade of " + tradingYear,
      backgroundColor: bgColor,
      borderColor: borderColor,
      borderWidth: 1,
      data: dataValue,
     }
    ]
   };

   let options = {
    scales: {
     xAxes: [{
      stacked: true
     }],
     yAxes: [{
      stacked: true
     }]
    }
   };

   let myBarChart = new Chart(chartcanvas, {
    type: 'bar',
    data: chartData,
    options: options
   });
  });

 }

我也有写一个方法,使我们的bar chart只使用我们所定义的颜色库。
/**
  * Get Bar background colors from prefered colors
  * @protected
  * @param {int} length
  * @param {string} opacity
  * @return {Array} a color array
  */
 getPreferedColors_(length, opacity=1) {

  let colorsRepo = [
   "255, 99, 132",
   "54, 162, 235",
   "255, 206, 86",
   "75, 192, 192",
   "153, 102, 255",
   "255, 159, 64"
  ];

  let colors = new Array();

  for (let i = 0; i < length; i++) {
   let index = i % colorsRepo.length ;
   let color = "rgba(" + colorsRepo[index] + "," + opacity + ")";
   colors.push(color)
  }

  return colors;
 }

希望你会喜欢。
本文的源码在这里可以下载。

原创粉丝点击