在这篇教程中,我们会讨论如何使用Promise对象来访问Liferay的web service.
在我们开展详细讨论之前,请注意,我现在所使用的是Liferay DXP DE-15。因为在这个补丁中包含了不少关于soy开发体验的改进。
在本篇教程中,我们将把所学过的知识连贯起来,来创建一个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 theknowledge
you 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; } |
希望你会喜欢。
本文的源码在
这里可以下载。