Joget DX 8 Stable Released
The stable release for Joget DX 8 is now available, with a focus on UX and Governance.
在本教程中,我们将遵循开发插件的 指导方针 来开发我们的超链接选项过滤器插件。 有关更多详细信息步骤,请参阅第一个教程 如何开发一个Bean Shell哈希变量插件。
我们希望有一个类似于以下的过滤器。
2.如何解决问题?
我们将开发一个 Datalist Filter Type插件 来呈现我们的超链接选项过滤器。
要开发一个超链接选项过滤器插件,我们将需要提供一些输入如下。
超链接列表将列出所有选项及其数据计数。当点击超链接时将过滤数据列表。
请参阅数据 滤波器类型插件。
我们需要始终准备好Joget Workflow Source Code,并按照这个指导方针建立起来 。
下面的教程是用Macbook Pro编写的,Joget源代码是5.0.1版本。 其他平台命令请参阅 如何开发插件文章。
假设我们的文件夹目录如下所示。
- Home - joget - plugins - jw-community -5.0.1
“插件”目录是我们将创建和存储我们所有插件的文件夹,“jw-community”目录是Joget Workflow源代码的存储位置。
运行以下命令在“plugins”目录下创建一个maven项目。
cd joget/plugins/ ~/joget/jw-community/5.0.1/wflow-plugin-archetype/create-plugin.sh org.joget hyperlink_options_filter 5.0.1
然后,shell脚本会要求我们输入插件的版本号,并在生成maven项目之前要求我们确认。
Define value for property 'version': 1.0-SNAPSHOT: : 5.0.0 [INFO] Using property: package = org.joget Confirm properties configuration: groupId: org.joget artifactId: hyperlink_options_filter version: 5.0.0 package: org.joget Y: : y
我们应该在终端上显示“BUILD SUCCESS”消息,并在“plugins”文件夹中创建一个“hyperlink_options_filter”文件夹。
用你最喜欢的IDE打开maven项目。我将使用 NetBeans。
在“org.joget”包下创建一个“HyperlinkOptionsFilter”类。然后,使用org.joget.apps.datalist.model.DataListFilterTypeDefault 抽象类来扩展 该类。请参阅 Datalist Filter Type插件。
像往常一样,我们必须执行所有的抽象方法。我们将使用AppPluginUtil.getMessage方法来支持i18n,并使用常量变量MESSAGE_PATH作为消息资源包目录。
现在,我们必须为管理员用户创建一个UI,为我们的插件提供输入。在getPropertyOptions方法中,我们已经指定了我们的 插件属性选项和配置 定义文件位于“/properties/hyperlinkOptionsFilter.json”。让我们在“hyperlink_options_filter / src / main”目录下创建一个目录“resources / properties”。创建目录后,在“properties”文件夹中创建一个名为“hyperlinkOptionsFilter.json”的文件。
在属性定义选项文件中,我们需要提供如下的选项。请注意,我们可以在我们的属性选项中使用“@@ message.key @@”语法来支持i18n。
[{ title : '@@HyperlinkOptionsFilter.config@@', properties : [{ name:'defaultValue', label:'@@HyperlinkOptionsFilter.defaultValue@@', type:'textfield' }, { name : 'showLabel', label : '@@HyperlinkOptionsFilter.showLabel@@', type : 'checkbox', options : [{ value : 'true', label : '' }] }, { name : 'displayFull', label : '@@HyperlinkOptionsFilter.displayFull@@', type : 'checkbox', value : 'true', options : [{ value : 'true', label : '' }] }, { name : 'showCount', label : '@@HyperlinkOptionsFilter.showCount@@', type : 'checkbox', value : '', options : [{ value : 'true', label : '' }] }, { name : 'options', label : '@@HyperlinkOptionsFilter.options@@', type : 'grid', columns : [{ key : 'value', label : '@@HyperlinkOptionsFilter.value@@' }, { key : 'label', label : '@@HyperlinkOptionsFilter.label@@' }] }] }, { title : '@@HyperlinkOptionsFilter.chooseOptionsBinder@@', properties : [{ name : 'optionsBinder', label : '@@HyperlinkOptionsFilter.optionsBinder@@', type : 'elementselect', options_ajax : '[CONTEXT_PATH]/web/property/json/getElements?classname=org.joget.apps.form.model.FormLoadOptionsBinder', url : '[CONTEXT_PATH]/web/property/json[APP_PATH]/getPropertyOptions' }] }]
完成属性选项以收集输入后,我们可以使用getTemplate和getQueryObject方法来处理插件的主要方法。在getTemplate方法中,我们将根据配置的插件属性检索选项和计数。
public String getTemplate(DataList datalist, String name, String label) { PluginManager pluginManager = (PluginManager) AppUtil.getApplicationContext().getBean("pluginManager"); Map dataModel = new HashMap(); dataModel.put("element", this); dataModel.put("name", datalist.getDataListEncodedParamName(DataList.PARAMETER_FILTER_PREFIX+name)); dataModel.put("label", label); Map<String, String> options = getOptionMap(); if ("true".equalsIgnoreCase(getPropertyString("showCount"))) { DataListBinder binder = datalist.getBinder(); for (String key : options.keySet()) { DataListFilterQueryObject filter = getQueryObject(datalist, name, key); int count = 0; if (binder != null) { if (filter != null) { count = binder.getDataTotalRowCount(datalist, binder.getProperties(), new DataListFilterQueryObject[]{filter}); } else { count = binder.getDataTotalRowCount(datalist, binder.getProperties(), new DataListFilterQueryObject[]{}); } } options.put(key, options.get(key) + " (" + count + ")"); } } String value = getValue(datalist, name, getPropertyString("defaultValue")); dataModel.put("value", value); dataModel.put("options", options); return pluginManager.getPluginFreeMarkerTemplate(dataModel, getClassName(), "/templates/hyperlinkOptionsFilter.ftl", null); } protected Map<String, String> getOptionMap() { Map<String, String> optionMap = new ListOrderedMap(); // load from "options" property Object[] options = (Object[]) getProperty(FormUtil.PROPERTY_OPTIONS); for (Object o : options) { Map option = (HashMap) o; Object value = option.get(FormUtil.PROPERTY_VALUE); Object label = option.get(FormUtil.PROPERTY_LABEL); if (value != null && label != null) { optionMap.put(value.toString(), label.toString()); } } // load from binder if available Map optionsBinderProperties = (Map) getProperty("optionsBinder"); if (optionsBinderProperties != null && optionsBinderProperties.get("className") != null && !optionsBinderProperties.get("className").toString().isEmpty()) { PluginManager pluginManager = (PluginManager) AppUtil.getApplicationContext().getBean("pluginManager"); FormBinder optionBinder = (FormBinder) pluginManager.getPlugin(optionsBinderProperties.get("className").toString()); if (optionBinder != null) { optionBinder.setProperties((Map) optionsBinderProperties.get("properties")); FormRowSet rowSet = ((FormLoadBinder) optionBinder).load(null, null, null); if (rowSet != null) { optionMap = new ListOrderedMap(); for (FormRow row : rowSet) { Iterator<String> it = row.stringPropertyNames().iterator(); // get the key based on the "value" property String value = row.getProperty(FormUtil.PROPERTY_VALUE); if (value == null) { // no "value" property, use first property instead String key = it.next(); value = row.getProperty(key); } // get the label based on the "label" property String label = row.getProperty(FormUtil.PROPERTY_LABEL); if (label == null) { // no "label" property, use next property instead String key = it.next(); label = row.getProperty(key); } optionMap.put(value, label); } } } } if (!optionMap.containsKey("")) { Map<String, String> tempOptionMap = new ListOrderedMap(); tempOptionMap.put("", AppPluginUtil.getMessage("HyperlinkOptionsFilter.all", getClassName(), MESSAGE_PATH)); tempOptionMap.putAll(optionMap); optionMap = tempOptionMap; } return optionMap; } protected DataListFilterQueryObject getQueryObject(DataList datalist, String name, String value) { DataListFilterQueryObject queryObject = new DataListFilterQueryObject(); if (datalist != null && datalist.getBinder() != null && value != null && !value.isEmpty()) { String columnName = datalist.getBinder().getColumnName(name); List<String> valuesList = new ArrayList<String>(); String query = "("+columnName+" = ? or "+columnName+" like ? or "+columnName+" like ? or "+columnName+" like ?)"; valuesList.add(value); valuesList.add(value + ";%"); valuesList.add("%;" + value + ";%"); valuesList.add("%;" + value); queryObject.setOperator(DataListFilter.OPERATOR_AND); queryObject.setQuery(query); queryObject.setValues(valuesList.toArray(new String[0])); return queryObject; } return null; } public DataListFilterQueryObject getQueryObject(DataList datalist, String name) { String value = getValue(datalist, name, getPropertyString("defaultValue")); return getQueryObject(datalist, name, value); }
在getTemplate中,我们指定模板文件为“hyperlinkOptionsFilter.ftl”。在“hyperlink_options_filter / src / main / resources / templates”目录下创建这个文件。然后,使用 FreeMaker 语法来构建我们的模板,如下所示:
<div id="${name!}_container" style="display:none;margin:5px 0;"> <input id="${name!}" name="${name!}" type="hidden" value="${value!?html}" /> <#if element.properties.showLabel! == "true" > <label><strong>${label!?html} :</strong></label> </#if> <#list options?keys as key> <a ref="${key?html}" href="${key?html}" class="<#if value! == key >active</#if>"><span><#if value! == key ><strong></#if>${options[key]!?html}<#if value! == key ></strong></#if></span></a> </#list> <script type="text/javascript"> $(document).ready(function(){ <#if element.properties.displayFull! == "true" > $('#${name!}_container').insertBefore($('#${name!}_container').closest(".filters")); </#if> $('#${name!}_container').show(); $('#${name!}_container a').click(function(){ var value = $(this).attr("ref"); $(this).parent().find("input").val(value); $(this).closest("form").submit(); return false; }); }); </script> </div>
我们需要在我们的POM文件中包含“commons-collections”库。
<!-- Change plugin specific dependencies here --> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2.1</version> </dependency> <!-- End change plugin specific dependencies here -->
我们在getLabel和getDescription方法中使用i18n消息密钥。我们将在我们的属性选项定义中使用i18n消息密钥。然后,我们将需要为我们的插件创建一个消息资源包属性文件。
在“hyperlink_options_filter / src / main”目录下创建一个目录“resources / message”。然后,在该文件夹中创建一个“HyperlinkOptionsFilter.properties”文件。在属性文件中,添加所有消息密钥及其标签,如下所示。
org.joget.HyperlinkOptionsFilter.pluginLabel=Hyperlink Options org.joget.HyperlinkOptionsFilter.pluginDesc=Show options as Hyperlink to perform filter. HyperlinkOptionsFilter.all=All HyperlinkOptionsFilter.config=Configure Hyperlink Options Filter HyperlinkOptionsFilter.options=Options HyperlinkOptionsFilter.value=Value HyperlinkOptionsFilter.label=Label HyperlinkOptionsFilter.chooseOptionsBinder=Choose Options Binder HyperlinkOptionsFilter.optionsBinder=Options Binder HyperlinkOptionsFilter.defaultValue=Default Value HyperlinkOptionsFilter.showCount=Show Data Count? HyperlinkOptionsFilter.displayFull=Display in full width (Above other filters) HyperlinkOptionsFilter.showLabel=Show label?
接下来,我们将需要在Activator类(在同一个类包中自动生成)中注册我们的插件类,以告诉Felix框架这是一个插件。
public void start(BundleContext context) { registrationList = new ArrayList<ServiceRegistration>(); //Register plugin here registrationList.add(context.registerService(HyperlinkOptionsFilter.class.getName(), new HyperlinkOptionsFilter(), null)); }
让我们建立我们的插件。构建过程完成后,我们将在“hyperlink_options_filter / target”目录下找到一个“hyperlink_options_filter-5.0.0.jar”文件。
然后,让我们上传插件jar到 管理插件。上传jar文件后,再次检查插件是否正确上传并激活。
然后,检查“超链接选项”过滤器在“列表设计器.”中显示为过滤器类型的选择。
配置其属性。
保存属性并检查过滤器是否在画布中呈现,如下所示
检查并测试datalist中的过滤器。
您可以从hyperlink_options_filter_src.zip下载源代码 。
要下载现成的插件jar,请在http://marketplace.joget.org/上找到它 。(快来了)