在本教程中,我们将遵循开发插件的 指导方针 来开发我们的表单提交统计信息生成器。 有关更多详细信息步骤,请参阅第一个教程 如何开发一个Bean Shell哈希变量插件。
1.什么问题?
我们有2个SQL Chart菜单(使用的查询依赖于MySQL)来显示表单数据提交统计信息,这2个菜单总是需要复制不同的表单。
2.你有什么想法来解决这个问题?
我们可以开发一个 Generator插件 来简化这个过程,为其他表单复制2个SQL Chart菜单。
3.你的插件需要什么输入?
要为我们的2个SQL图表菜单开发Generator插件,我们可以考虑提供以下内容作为输入。
- Userview ID:哪个用户视图添加这2个SQL菜单
- “类别”标签,“菜单”标签和“图表”标签中的一些标签更改选项
4.你的插件的输出和预期结果是什么?
2 SQL Chart菜单将被添加到选定的用户视图下一个新的类别。其中一个菜单将显示每月提交图表,另一个将显示基于年份和月份过滤器的每日提交图表。
5.有没有可重用的资源/ API?
首先,我们可以在现有的用户视图之一中构建我们的2个SQL图表菜单。然后,将包含我们的2个SQL Chart菜单的类别的JSON定义复制到Userview Builder的底部的“ADVANCED:JSON Definition” 。
我们将得到我们的类别的JSON定义如下。请注意在2个SQL图表菜单中使用的查询依赖于MySQL数据库。
{
"className": "org.joget.apps.userview.model.UserviewCategory",
"properties": {
"id": "category-8722A52FFBB64D058E2CD41174922807",
"label": "Proposal Form Statistics"
},
"menus": [{
"className": "org.joget.plugin.enterprise.SqlChartMenu",
"properties": {
"id": "807F165BFA9C4BB589E5B52E4C071250",
"customId": "crm_proposal_monthly",
"label": "Monthly Submission Chart",
"chartType": "bar",
"title": "Proposal Form Monthly Submission Chart",
"categoryAxisLabel": "Month",
"xAxisDisplayAS": "",
"valueAxisLabel": "Number",
"yaxisPrefix": "",
"showLegend": "",
"showValueLabel": "true",
"stack": "",
"horizontal": "",
"chartWidth": "100%",
"chartHeight": "80%",
"colors": "",
"query": "SELECT DATE_FORMAT(STR_TO_DATE(m.monthYear, '%c-%Y'),'%b %y') as monthYear, COUNT(fd.dateCreated) AS 'Number'\nFROM \n(\n SELECT my.month, CONCAT(my.month, '-', IF(('#requestParam.year?sql#' REGEXP '^[0-9]{4}$'), '#requestParam.year?sql#' , '#date.yyyy?sql#')) AS monthYear FROM (\n SELECT 1 AS month UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 UNION SELECT 11 UNION SELECT 12\n ) my\n) m\nLEFT JOIN \n(\n\t select dateCreated FROM app_fd_crm_proposal\n) fd\nON m.monthYear=DATE_FORMAT(fd.dateCreated,'%c-%Y')\nGROUP BY monthYear\nORDER BY m.month",
"customHeader": "<div class=\"filter\">\n <form action=\"?\" method=\"GET\">\n <label>Year: <\/label><input name=\"year\" value=\"#requestParam.year?html#\"\/>\n <input type=\"submit\" value=\"Show\"\/>\n <\/form>\n<\/div>\n<script>\n $(function(){\n if ($(\"[name='year']\").val() === \"\") {\n $(\"[name='year']\").val(\"#date.yyyy#\");\n }\n });\n<\/script>\n<br\/>\n<br\/>",
"customFooter": "",
"datasource": "default",
"keyName": ""
}
}, {
"className": "org.joget.plugin.enterprise.SqlChartMenu",
"properties": {
"id": "39E2163319D84FD693D164D92FA93C06",
"customId": "crm_proposal_daily",
"label": "Daily Submission Chart",
"chartType": "bar",
"title": "Proposal Form Daily Submission Chart",
"categoryAxisLabel": "Date",
"xAxisDisplayAS": "",
"valueAxisLabel": "Number",
"yaxisPrefix": "",
"showLegend": "",
"showValueLabel": "true",
"stack": "",
"horizontal": "true",
"chartWidth": "100%",
"chartHeight": "80%",
"colors": "",
"query": "SELECT d.date_field, COUNT(fd.dateCreated) AS 'Number'\nFROM\n(\n SELECT\n MAKEDATE(IF(('#requestParam.year?sql#' REGEXP '^[0-9]{4}$'), '#requestParam.year?sql#' , '#date.yyyy?sql#'),1) +\n INTERVAL (IF(('#requestParam.month?sql#' REGEXP '^[0-9]{2}$'), '#requestParam.month?sql#' , '#date.MM?sql#') -1) MONTH +\n INTERVAL daynum DAY date_field\n FROM\n (\n SELECT t*10+u daynum\n FROM\n (SELECT 0 t UNION SELECT 1 UNION SELECT 2 UNION SELECT 3) A,\n (SELECT 0 u UNION SELECT 1 UNION SELECT 2 UNION SELECT 3\n UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7\n UNION SELECT 8 UNION SELECT 9) B\n ORDER BY daynum\n ) AA\n) d\nLEFT JOIN \n(\n\t select dateCreated FROM app_fd_crm_proposal\n) fd\nON d.date_field=DATE_FORMAT(fd.dateCreated,'%Y-%m-%d')\nWHERE DATE_FORMAT(d.date_field,'%m') = IF(('#requestParam.month?sql#' REGEXP '^[0-9]{2}$'), '#requestParam.month?sql#' , '#date.MM?sql#')\nGROUP BY d.date_field\nORDER BY d.date_field desc",
"customHeader": "<div class=\"filter\">\n <form action=\"?\" method=\"GET\">\n <label>Year: <\/label><input name=\"year\" value=\"#requestParam.year?html#\"\/> \n <label>Month: <\/label><select name=\"month\"\/>\n <option value=\"01\">Jan<\/option>\n <option value=\"02\">Feb<\/option>\n <option value=\"03\">Mar<\/option>\n <option value=\"04\">Apr<\/option>\n <option value=\"05\">May<\/option>\n <option value=\"06\">Jun<\/option>\n <option value=\"07\">Jul<\/option>\n <option value=\"08\">Aug<\/option>\n <option value=\"09\">Sep<\/option>\n <option value=\"10\">Oct<\/option>\n <option value=\"11\">Nov<\/option>\n <option value=\"12\">Dec<\/option>\n <\/select>\n <input type=\"submit\" value=\"Show\"\/>\n <\/form>\n<\/div>\n<script>\n $(function(){\n if ($(\"[name='year']\").val() === \"\") {\n $(\"[name='year']\").val(\"#date.yyyy#\");\n }\n if ($(\"[name='month']\").val() !== \"#requestParam.month?javascript#\" \n && '#requestParam.month?javascript#' !== \"\"\n && $(\"[name='month'] option[value='#requestParam.month?javascript#']\").length > 0 ) {\n $(\"[name='month']\").val('#requestParam.month?javascript#');\n } else {\n $(\"[name='month']\").val(\"#date.MM#\");\n }\n });\n<\/script>\n<br\/>\n<br\/>",
"customFooter": "",
"datasource": "default",
"keyName": ""
}
}]
}
之后,我们可以利用 GeneratorUtil 将类别JSON定义添加到我们选择的userview JSON定义中。
6. 准备你的开发环境
我们需要始终准备好Joget Workflow Source Code,并按照这个指导方针建立起来 。
本教程的以下内容是使用Macbook Pro和Joget源代码5.0.0版编写的。 其他平台命令请参考 如何开发插件。
让我们说我们的文件夹目录如下。
- Home
- joget
- plugins
- jw-community
-5.0.0
“plugins”目录是我们要创建和存储我们所有插件的文件夹,“jw-community”目录是Joget Workflow源代码存储的地方。
运行以下命令在“plugins”目录下创建一个maven项目。
cd joget/plugins/ ~/joget/jw-community/5.0.0/wflow-plugin-archetype/create-plugin.sh org.joget.tutorial form_submission_statistics_generator 5.0.0
然后,shell脚本将要求我们为您的插件输入一个版本,并在生成maven项目之前要求我们确认。
Define value for property 'version': 1.0-SNAPSHOT: : 5.0.0 [INFO] Using property: package = org.joget.tutorial Confirm properties configuration: groupId: org.joget.tutorial artifactId: form_submission_statistics_generator version: 5.0.0 package: org.joget.tutorial Y: : y
我们应该在终端上显示“BUILD SUCCESS”消息,在“plugins”文件夹中创建一个“form_submission_statistics_generator”文件夹。
用你喜欢的IDE打开maven项目。我将使用 NetBeans。
7. Just code it!
a. Extending the abstract class of a plugin type
在“org.joget.tutorial”包下创建一个“FormSubmissionStatisticsGenerator”类。然后,使用org.joget.apps.generator.model.GeneratorPlugin 抽象类来扩展 该类。请参考 Generator插件。
b. Implement all the abstract methods
像往常一样,我们必须执行所有的抽象方法。我们将使用AppPluginUtil.getMessage方法来支持i18n,并使用常量变量MESSAGE_PATH作为消息资源包目录
然后,我们必须为管理员用户提供一个UI来为我们的插件提供输入。在getPropertyOptions方法中,我们已经指定了我们的 插件属性选项和配置 定义文件位于“/properties/formSubmissionStatisticsGenerator.json”。让我们在“form_submission_statistics_generator / src / main”目录下创建一个目录“resources / properties”。创建目录后,在“properties”文件夹中创建一个名为“formSubmissionStatisticsGenerator.json”的文件。
在属性定义选项文件中,我们需要提供如下的选项。请注意,我们可以在我们的属性选项中使用“@@ message.key @@”语法来支持i18n。
[{
title : '@@generator.formSubmissionStatistics.config@@',
properties : [
{
name : 'userviewId',
label : '@@generator.formSubmissionStatistics.userview@@',
type : 'selectbox',
value: '[default_userviewId]',
options_ajax : '[CONTEXT_PATH]/web/json/console/app[APP_PATH]/userview/options'
}]
},
{
title : '@@generator.formSubmissionStatistics.advanced@@',
properties : [
{
label : '@@generator.formSubmissionStatistics.label.options@@',
type : 'header'
},
{
name : 'monthlyChartTitle',
label : '@@generator.formSubmissionStatistics.monthlyChartTitle@@',
type : 'textfield',
required : 'true',
value : '@@generator.formSubmissionStatistics.monthlyChartTitle.value@@'
},
{
name : 'monthlyXAxisLabel',
label : '@@generator.formSubmissionStatistics.monthlyXAxisLabel@@',
type : 'textfield',
required : 'true',
value : '@@generator.formSubmissionStatistics.monthlyXAxisLabel.value@@'
},
{
name : 'dailyChartTitle',
label : '@@generator.formSubmissionStatistics.dailyChartTitle@@',
type : 'textfield',
required : 'true',
value : '@@generator.formSubmissionStatistics.dailyChartTitle.value@@'
},
{
name : 'dailyXAxisLabel',
label : '@@generator.formSubmissionStatistics.dailyXAxisLabel@@',
type : 'textfield',
required : 'true',
value : '@@generator.formSubmissionStatistics.dailyXAxisLabel.value@@'
},
{
name : 'yAxisLabel',
label : '@@generator.formSubmissionStatistics.yAxisLabel@@',
type : 'textfield',
required : 'true',
value : '@@generator.formSubmissionStatistics.yAxisLabel.value@@'
},
{
name : 'yearLabel',
label : '@@generator.formSubmissionStatistics.yearLabel@@',
type : 'textfield',
required : 'true',
value : '@@generator.formSubmissionStatistics.yearLabel.value@@'
},
{
name : 'monthLabel',
label : '@@generator.formSubmissionStatistics.monthLabel@@',
type : 'textfield',
required : 'true',
value : '@@generator.formSubmissionStatistics.monthLabel.value@@'
},
{
name : 'showLabel',
label : '@@generator.formSubmissionStatistics.showLabel@@',
type : 'textfield',
required : 'true',
value : '@@generator.formSubmissionStatistics.showLabel.value@@'
},
{
label : '@@generator.formSubmissionStatistics.useriewMenu.options@@',
type : 'header'
},
{
name : 'categoryLabel',
label : '@@generator.formSubmissionStatistics.categoryLabel@@',
type : 'textfield',
required : 'true',
value : '@@generator.formSubmissionStatistics.categoryLabel.value@@'
},
{
name : 'monthlyMenuId',
label : '@@generator.formSubmissionStatistics.monthlyMenuId@@',
type : 'textfield',
required : 'true',
regex_validation : '^[a-zA-Z0-9_]+$',
validation_message : '@@generator.formSubmissionStatistics.menuId.invalidId@@',
value : '[formId]_monthly'
},
{
name : 'monthlyMenuLabel',
label : '@@generator.formSubmissionStatistics.monthlyMenuLabel@@',
type : 'textfield',
required : 'true',
value : '@@generator.formSubmissionStatistics.monthlyMenuLabel.value@@'
},
{
name : 'dailyMenuId',
label : '@@generator.formSubmissionStatistics.dailyMenuId@@',
type : 'textfield',
required : 'true',
regex_validation : '^[a-zA-Z0-9_]+$',
validation_message : '@@generator.formSubmissionStatistics.menuId.invalidId@@',
value : '[formId]_daily'
},
{
name : 'dailyMenuLabel',
label : '@@generator.formSubmissionStatistics.dailyMenuLabel@@',
type : 'textfield',
required : 'true',
value : '@@generator.formSubmissionStatistics.dailyMenuLabel.value@@'
},
{
label : '@@generator.formSubmissionStatistics.createUserviewOptions@@',
type : 'header',
control_field: 'userviewId',
control_value: '',
control_use_regex: 'false',
},
{
name : 'userviewNewId',
label : '@@generator.formSubmissionStatistics.userview.id@@',
type : 'textfield',
required : 'true',
value : '@@generator.formSubmissionStatistics.userview.id.value@@',
regex_validation : '^[a-zA-Z0-9_]+$',
validation_message : '@@generator.formSubmissionStatistics.userview.id.invalidId@@',
control_field: 'userviewId',
control_value: '',
control_use_regex: 'false'
},
{
name : 'userviewName',
label : '@@generator.formSubmissionStatistics.userview.name@@',
type : 'textfield',
required : 'true',
value : '@@generator.formSubmissionStatistics.userview.name.value@@',
control_field: 'userviewId',
control_value: '',
control_use_regex: 'false'
},
{
name : 'userviewDesc',
label : '@@generator.formSubmissionStatistics.userview.description@@',
type : 'textarea',
rows : "3",
control_field: 'userviewId',
control_value: '',
control_use_regex: 'false'
}]
}]
public String getPropertyOptions() {
String options = AppUtil.readPluginResource(getClassName(), "/properties/formSubmissionStatisticsGenerator.json", null, true, MESSAGE_PATH);
//populate value like [formName] and [formId]
options = GeneratorUtil.populateFormMeta(options, getFormId(), getAppDefinition());
//populate value of [default_userviewId]
options = options.replace("[default_userviewId]", GeneratorUtil.getFirstAvailableUserviewId(getAppDefinition()));
return options;
}
一旦我们完成了属性选项来收集输入, 我们可以在插件的主方法,format方法中工作
@Override
public GeneratorResult generate() {
GeneratorResult result = new GeneratorResult();
AppDefinition appDef = getAppDefinition();
try {
//get userview
UserviewDefinitionDao userviewDefinitionDao = (UserviewDefinitionDao) AppUtil.getApplicationContext().getBean("userviewDefinitionDao");
UserviewDefinition userviewDef = null;
String json = null;
String userviewId = getPropertyString("userviewId");
String userviewName;
String userviewDesc;
if (userviewId != null && !userviewId.isEmpty()) {
userviewDef = userviewDefinitionDao.loadById(userviewId, appDef);
}
if (userviewDef != null) {
userviewName = userviewDef.getName();
userviewDesc = userviewDef.getDescription();
json = userviewDef.getJson();
} else {
userviewId = getPropertyString("userviewNewId");
int count = 0;
while (isExist(userviewId, userviewDefinitionDao)) {
count++;
userviewId = userviewId + count;
}
userviewName = getPropertyString("userviewName");
userviewDesc = getPropertyString("userviewDesc");
}
if (json == null || json.isEmpty()) {
//create a new userview json
json = GeneratorUtil.createNewUserviewJson(userviewId, userviewName, userviewDesc);
}
//add the category json to userview json
json = GeneratorUtil.addCategoryJsonToUserviewJson(getCategoryJson(appDef), json);
//Store the userview json
if (userviewDef != null) {
userviewDef.setJson(json);
userviewDefinitionDao.update(userviewDef);
}else {
userviewDef = new UserviewDefinition();
userviewDef.setJson(json);
userviewDef.setId(userviewId);
userviewDef.setName(userviewName);
userviewDef.setAppDefinition(appDef);
userviewDefinitionDao.add(userviewDef);
//Set current published version
final AppDefinition currentAppDef = appDef;
TransactionTemplate transactionTemplate = (TransactionTemplate)AppUtil.getApplicationContext().getBean("transactionTemplate");
transactionTemplate.execute(new TransactionCallback<Object>() {
public Object doInTransaction(TransactionStatus ts) {
AppService appService = (AppService)AppUtil.getApplicationContext().getBean("appService");
appService.publishApp(currentAppDef.getId(), currentAppDef.getVersion().toString());
return null;
}
});
}
//show message to continue edit
String editLink = WorkflowUtil.getHttpServletRequest().getContextPath() + "/web/console/app/"+appDef.getAppId()+"/"+appDef.getVersion()+"/userview/builder/"+userviewId;
String msg = AppPluginUtil.getMessage("generator.formSubmissionStatistics.msg.success", getClassName(), MESSAGE_PATH);
msg = msg.replace("[url]", editLink);
result.setMessage(msg);
} catch (Exception e) {
result.setError(true);
result.setMessage(AppPluginUtil.getMessage("generator.formSubmissionStatistics.msg.error", getClassName(), MESSAGE_PATH));
LogUtil.error(getClassName(), e, "Not able to generate the menus");
}
return result;
}
/**
* Retrieves the category JSON definition
* @param appDef
* @return
*/
protected String getCategoryJson(AppDefinition appDef) {
Collection<String> args = new ArrayList<String>();
AppService appService = (AppService)AppUtil.getApplicationContext().getBean("appService");
String tabelName = appService.getFormTableName(appDef, getFormId());
args.add(UuidGenerator.getInstance().getUuid()); //category id
args.add(StringUtil.escapeString(getPropertyString("categoryLabel"), StringUtil.TYPE_JSON, null)); //category label
args.add(UuidGenerator.getInstance().getUuid()); //monthly menu uuid
args.add(StringUtil.escapeString(getPropertyString("monthlyMenuId"), StringUtil.TYPE_JSON, null)); //monthly menu custom id
args.add(StringUtil.escapeString(getPropertyString("monthlyMenuLabel"), StringUtil.TYPE_JSON, null)); //monthly menu label
args.add(StringUtil.escapeString(getPropertyString("monthlyChartTitle"), StringUtil.TYPE_JSON, null)); //monthly chart title
args.add(StringUtil.escapeString(getPropertyString("monthlyXAxisLabel"), StringUtil.TYPE_JSON, null)); //monthly x-axis label
args.add(StringUtil.escapeString(getPropertyString("yAxisLabel"), StringUtil.TYPE_JSON, null)); //monthly y-axis label
args.add(StringUtil.escapeString(tabelName, StringUtil.TYPE_JSON, null)); //monthly form table name
args.add(StringUtil.escapeString(getPropertyString("yearLabel"), StringUtil.TYPE_JSON, null)); //monthly year label
args.add(StringUtil.escapeString(getPropertyString("showLabel"), StringUtil.TYPE_JSON, null)); //monthly show button label
args.add(UuidGenerator.getInstance().getUuid()); //daily menu uuid
args.add(StringUtil.escapeString(getPropertyString("dailyMenuId"), StringUtil.TYPE_JSON, null)); //daily menu custom id
args.add(StringUtil.escapeString(getPropertyString("dailyMenuLabel"), StringUtil.TYPE_JSON, null)); //daily menu label
args.add(StringUtil.escapeString(getPropertyString("dailyChartTitle"), StringUtil.TYPE_JSON, null)); //daily chart title
args.add(StringUtil.escapeString(getPropertyString("dailyXAxisLabel"), StringUtil.TYPE_JSON, null)); //daily x-axis label
args.add(StringUtil.escapeString(getPropertyString("yAxisLabel"), StringUtil.TYPE_JSON, null)); //daily y-axis label
args.add(StringUtil.escapeString(tabelName, StringUtil.TYPE_JSON, null)); //daily form table name
args.add(StringUtil.escapeString(getPropertyString("yearLabel"), StringUtil.TYPE_JSON, null)); //daily year label
args.add(StringUtil.escapeString(getPropertyString("monthLabel"), StringUtil.TYPE_JSON, null)); //daily month label
args.add(StringUtil.escapeString(getPropertyString("showLabel"), StringUtil.TYPE_JSON, null)); //daily show button label
String json = AppUtil.readPluginResource(getClass().getName(), "/resources/category.json", args.toArray(), true, null);
return json;
}
/**
* Checks for a userview is already exist
* @param id
* @param userviewDefinitionDao
* @return
*/
protected boolean isExist(String id, UserviewDefinitionDao userviewDefinitionDao) {
Long count = userviewDefinitionDao.count("AND id = ?", new String[]{id}, getAppDefinition());
return count > 0;
}
在getCategoryJson方法中,我们将检索类别JSON定义形式“/resources/category.json”文件。让我们在“form_submission_statistics_generator / src / main”目录下创建一个目录“resources / resources”。创建目录后,在“resources”文件夹中创建一个名为“category.json”的文件。然后,复制我们之前创建的类别JSON定义,并将其粘贴到此文件中。我们将需要将一些硬编码值替换为变量,并记住将使用String.format的AppUtil.readPluginResource转义为将现有的“%”转义为“%%”,以便将值注入到文件中。
{
"className": "org.joget.apps.userview.model.UserviewCategory",
"properties": {
"id": "category-%s",
"label": "%s"
},
"menus": [{
"className": "org.joget.plugin.enterprise.SqlChartMenu",
"properties": {
"id": "%s",
"customId": "%s",
"label": "%s",
"chartType": "bar",
"title": "%s",
"categoryAxisLabel": "%s",
"xAxisDisplayAS": "",
"valueAxisLabel": "%s",
"yaxisPrefix": "",
"showLegend": "",
"showValueLabel": "true",
"stack": "",
"horizontal": "",
"chartWidth": "100%%",
"chartHeight": "80%%",
"colors": "",
"query": "SELECT DATE_FORMAT(STR_TO_DATE(m.monthYear, '%%c-%%Y'),'%%b %%y') as monthYear, COUNT(fd.dateCreated) AS 'Number'\nFROM \n(\n SELECT my.month, CONCAT(my.month, '-', IF(('#requestParam.year?sql#' REGEXP '^[0-9]{4}$'), '#requestParam.year?sql#' , '#date.yyyy?sql#')) AS monthYear FROM (\n SELECT 1 AS month UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 UNION SELECT 11 UNION SELECT 12\n ) my\n) m\nLEFT JOIN \n(\n\t select dateCreated FROM app_fd_%s\n) fd\nON m.monthYear=DATE_FORMAT(fd.dateCreated,'%%c-%%Y')\nGROUP BY monthYear\nORDER BY m.month",
"customHeader": "<div class=\"filter\">\n <form action=\"?\" method=\"GET\">\n <label>%s: <\/label><input name=\"year\" value=\"#requestParam.year?html#\"\/>\n <input type=\"submit\" value=\"%s\"\/>\n <\/form>\n<\/div>\n<script>\n $(function(){\n if ($(\"[name='year']\").val() === \"\") {\n $(\"[name='year']\").val(\"#date.yyyy#\");\n }\n });\n<\/script>\n<br\/>\n<br\/>",
"customFooter": "",
"datasource": "default",
"keyName": ""
}
}, {
"className": "org.joget.plugin.enterprise.SqlChartMenu",
"properties": {
"id": "%s",
"customId": "%s",
"label": "%s",
"chartType": "bar",
"title": "%s",
"categoryAxisLabel": "%s",
"xAxisDisplayAS": "",
"valueAxisLabel": "%s",
"yaxisPrefix": "",
"showLegend": "",
"showValueLabel": "true",
"stack": "",
"horizontal": "true",
"chartWidth": "100%%",
"chartHeight": "80%%",
"colors": "",
"query": "SELECT d.date_field, COUNT(fd.dateCreated) AS 'Number'\nFROM\n(\n SELECT\n MAKEDATE(IF(('#requestParam.year?sql#' REGEXP '^[0-9]{4}$'), '#requestParam.year?sql#' , '#date.yyyy?sql#'),1) +\n INTERVAL (IF(('#requestParam.month?sql#' REGEXP '^[0-9]{2}$'), '#requestParam.month?sql#' , '#date.MM?sql#') -1) MONTH +\n INTERVAL daynum DAY date_field\n FROM\n (\n SELECT t*10+u daynum\n FROM\n (SELECT 0 t UNION SELECT 1 UNION SELECT 2 UNION SELECT 3) A,\n (SELECT 0 u UNION SELECT 1 UNION SELECT 2 UNION SELECT 3\n UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7\n UNION SELECT 8 UNION SELECT 9) B\n ORDER BY daynum\n ) AA\n) d\nLEFT JOIN \n(\n\t select dateCreated FROM app_fd_%s\n) fd\nON d.date_field=DATE_FORMAT(fd.dateCreated,'%%Y-%%m-%%d')\nWHERE DATE_FORMAT(d.date_field,'%%m') = IF(('#requestParam.month?sql#' REGEXP '^[0-9]{2}$'), '#requestParam.month?sql#' , '#date.MM?sql#')\nGROUP BY d.date_field\nORDER BY d.date_field desc",
"customHeader": "<div class=\"filter\">\n <form action=\"?\" method=\"GET\">\n <label>%s: <\/label><input name=\"year\" value=\"#requestParam.year?html#\"\/> \n <label>%s: <\/label><select name=\"month\"\/>\n <option value=\"01\">Jan<\/option>\n <option value=\"02\">Feb<\/option>\n <option value=\"03\">Mar<\/option>\n <option value=\"04\">Apr<\/option>\n <option value=\"05\">May<\/option>\n <option value=\"06\">Jun<\/option>\n <option value=\"07\">Jul<\/option>\n <option value=\"08\">Aug<\/option>\n <option value=\"09\">Sep<\/option>\n <option value=\"10\">Oct<\/option>\n <option value=\"11\">Nov<\/option>\n <option value=\"12\">Dec<\/option>\n <\/select>\n <input type=\"submit\" value=\"%s\"\/>\n <\/form>\n<\/div>\n<script>\n $(function(){\n if ($(\"[name='year']\").val() === \"\") {\n $(\"[name='year']\").val(\"#date.yyyy#\");\n }\n if ($(\"[name='month']\").val() !== \"#requestParam.month?javascript#\" \n && '#requestParam.month?javascript#' !== \"\"\n && $(\"[name='month'] option[value='#requestParam.month?javascript#']\").length > 0 ) {\n $(\"[name='month']\").val('#requestParam.month?javascript#');\n } else {\n $(\"[name='month']\").val(\"#date.MM#\");\n }\n });\n<\/script>\n<br\/>\n<br\/>",
"customFooter": "",
"datasource": "default",
"keyName": ""
}
}]
}
c. Manage the dependency libraries of your plugin
我们的插件使用javax.servlet.http.HttpServletRequest和javax.servlet.http.HttpServletResponse类,因此我们需要将jsp-api库添加到我们的POM文件中。
<!-- Change plugin specific dependencies here -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
<!-- End change plugin specific dependencies here -->
d. Make your plugin internationalization (i18n) ready
我们在getLabel和getDescription方法中使用i18n消息密钥。我们还在我们的属性选项定义中使用了i18n消息密钥。所以,我们需要为我们的插件创建一个消息资源包属性文件。
在“form_submission_statistics_generator / src / main”目录下创建目录“resources / messages”。然后,在该文件夹中创建一个“FormSubmissionStatisticsGenerator.properties”文件。在属性文件中,让我们添加所有的消息键和它的标签如下。
org.joget.tutorial.FormSubmissionStatisticsGenerator.pluginLabel=Generate Form Submission Statistics org.joget.tutorial.FormSubmissionStatisticsGenerator.pluginDesc=Generate 2 SQL Chart Menus for form submission statistics generator.formSubmissionStatistics.explanation=Create 2 SQL Chart Menus based on the current form for submission statistics. Note: This is dependent for MySQL database. generator.formSubmissionStatistics.config=Options generator.formSubmissionStatistics.userview=Userview generator.formSubmissionStatistics.advanced=Advanced generator.formSubmissionStatistics.label.options=Label Options generator.formSubmissionStatistics.categoryLabel=Category Label generator.formSubmissionStatistics.categoryLabel.value=[formName] Statistics generator.formSubmissionStatistics.menuId.invalidId=Only alpha-numeric and underscore characters allowed generator.formSubmissionStatistics.monthlyMenuId=Monthly Menu id generator.formSubmissionStatistics.monthlyMenuLabel=Montly Menu Label generator.formSubmissionStatistics.monthlyMenuLabel.value=Monthly Submission Chart generator.formSubmissionStatistics.monthlyChartTitle=Montly Chart Title generator.formSubmissionStatistics.monthlyChartTitle.value=[formName] Monthly Submission Chart generator.formSubmissionStatistics.monthlyXAxisLabel=Montly X-axis Label generator.formSubmissionStatistics.monthlyXAxisLabel.value=Month generator.formSubmissionStatistics.dailyMenuId=Daily Menu Id generator.formSubmissionStatistics.dailyMenuLabel=Daily Menu Label generator.formSubmissionStatistics.dailyMenuLabel.value=Daily Submission Chart generator.formSubmissionStatistics.dailyChartTitle=Daily Chart Title generator.formSubmissionStatistics.dailyChartTitle.value=[formName] Daily Submission Chart generator.formSubmissionStatistics.dailyXAxisLabel=Daily X-axis Label generator.formSubmissionStatistics.dailyXAxisLabel.value=Date generator.formSubmissionStatistics.yAxisLabel=Y-axis Label generator.formSubmissionStatistics.yAxisLabel.value=Number generator.formSubmissionStatistics.yearLabel=Year Label generator.formSubmissionStatistics.yearLabel.value=Year generator.formSubmissionStatistics.monthLabel=Month Label generator.formSubmissionStatistics.monthLabel.value=Month generator.formSubmissionStatistics.showLabel=Show Label generator.formSubmissionStatistics.showLabel.value=Show generator.formSubmissionStatistics.useriewMenu.options=Userview Label Options generator.formSubmissionStatistics.createUserviewOptions=Create New Userview Options generator.formSubmissionStatistics.userview.id=Userview ID generator.formSubmissionStatistics.userview.id.value=v generator.formSubmissionStatistics.userview.id.invalidId=Only alpha-numeric and underscore characters allowed generator.formSubmissionStatistics.userview.name=Userview Name generator.formSubmissionStatistics.userview.name.value=[appName] generator.formSubmissionStatistics.userview.description=Userview Description generator.formSubmissionStatistics.msg.success=Menus generated. Click <a href="[url]" target="_blank">here</a> to continue edit in Userview Builder. generator.formSubmissionStatistics.msg.error=Error during generating Form Submission Statistics Menus!
e. Register your plugin to Felix Framework
我们将不得不在Activator类(在同一个类包中自动生成)中注册我们的插件类,以告诉Felix框架这是一个插件。
public void start(BundleContext context) {
registrationList = new ArrayList<ServiceRegistration>();
//Register plugin here
registrationList.add(context.registerService(FormSubmissionStatisticsGenerator.class.getName(), new FormSubmissionStatisticsGenerator(), null));
}
f. Build it and testing
让我们建立我们的插件。一旦构建过程完成,我们将在“form_submission_statistics_generator / target”目录下创建一个“form_submission_statistics_generator-5.0.0.jar”文件。
然后,让插件jar上传到 管理插件。上传jar文件后,仔细检查插件是否正确上传和激活。
现在,我们可以在Form Builder中为我们的表单打开一个测试生成器。点击Form Builder右上方的“Generate App”按钮。请参阅 生成应用程序。
让我们检查“高级生成器”的属性页面。
生成过程完成后。
一个新的类别被添加到我们的用户视图。
SQL图表菜单将显示如下。
8. 再进一步,分享或出售
您可以从form_submission_statistics_generator.zip下载源代码 。
要下载现成的插件jar,请在http://marketplace.joget.org/上找到它 。








