Joget DX 8 Stable Released
The stable release for Joget DX 8 is now available, with a focus on UX and Governance.
ในบทเรียนนี้เราจะติมตาม guideline of developing a plugin เพื่อพัฒนาปลั๊กอิน Form Submission Statistics Generator ของเรา. โปรดอ้างอิงถึงบทเรียนแรก วิธีการพัฒนา Bean Shell Hash Variable สำหรับรายละเอียดเพิ่มเติม.
เรามี 2 SQL Chart menus (the queries used are dependent on MySQL) to show form data submission statistics and this 2 menus always need to replicate for different form.
เราสามารถพัฒนา Generator Plugin เพื่อลดความยุ่งยากในการทำซ้ำเมนู SQL แผนภูมิ 2 รายการสำหรับฟอร์มอื่น ๆ
ในการพัฒนาปลั๊กอินตัวสร้างสำหรับเมนูแผนภูมิ SQL ของเรา 2 รายการเราสามารถพิจารณาให้ข้อมูลต่อไปนี้เป็นอินพุต
2 เมนูแผนภูมิ SQL จะถูกเพิ่มไปยัง userview ที่เลือกภายใต้หมวดหมู่ใหม่.หนึ่งในเมนูจะแสดงแผนภูมิส่งรายเดือนและอีกหนึ่งรายการจะแสดงแผนภูมิส่งรายวันตามตัวกรองปีและเดือน
อันดับแรกเราสามารถสร้างเมนูแผนภูมิ SQL ของเรา 2 รายการในหนึ่งใน userview ที่มีอยู่. จากนั้นคัดลอกคำนิยาม JSON ของหมวดหมู่ที่มีเมนูแผนภูมิ SQL ของเรา 2 รายการในรูปแบบ "ADVANCED: JSON Definition" ที่ด้านล่างของ
ตัวสร้าง Userview
เราจะได้คำจำกัดความของ JSON ของหมวดหมู่ดังต่อไปนี้. โปรดทราบว่าแบบสอบถามที่ใช้ในเมนูแผนภูมิ SQL 2 รายการนั้นขึ้นอยู่กับฐานข้อมูล 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 หมวดหมู่เข้ากับนิยาม JSON ของเราที่เลือกไว้
เราจำเป็นต้องให้ซอร์สโค้ด Joget Workflow ของเราพร้อมและสร้างโดยทำตาม this guideline.
บทช่วยสอนต่อไปนี้จัดทำขึ้นด้วย Macbook Pro และ Joget Source Code version 5.0.0. โปรดอ้างอิงถึง แนวทางสำหรับการพัฒนาปลั๊กอิน สำหรับคำสั่งแพลตฟอร์มอื่นๆ
ให้กล่าวว่าไดเรกทอรีโฟลเดอร์ของเราดังต่อไปนี้
- Home - joget - plugins - jw-community -5.0.0
ไดเรกทอรี "ปลั๊กอิน" คือโฟลเดอร์ที่เราจะสร้างและจัดเก็บปลั๊กอินทั้งหมดของเราและไดเรกทอรี "jw-community" เป็นที่เก็บซอร์สโค้ด Joget Workflow
เรียกใช้คำสั่งต่อไปนี้เพื่อสร้างโครงการ 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
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" ที่ปรากฏในเครื่องของเราและโฟลเดอร์ "form_submission_statistics_generator" ที่สร้างในโฟลเดอร์ "ปลั๊กอิน"
เปิดโครงการ maven ด้วย IDE ที่คุณโปรดปราน เราแนะนำให้ใช้ NetBeans.
สร้างคลาส "FormSubmissionStatisticsGenerator" ภายใต้ "org.joget.tutorial" package. จากนั้นขยายคลาสด้วย org.joget.apps.generator.model.GeneratorPlugin abstract class. โปรดอ้างอิงถึง Generator Plugin.
เช่นเคย เราจำเป็นต้องใช้ abstract methods ของเราทั้งหมด. เราจะใช้ AppPluginUtil.getMessage method เพื่อสนับสนุน i18n และใช้ตัวแปรคงที่ MESSAGE_PATH สำหรับ message resource bundle directory.
จากนั้นเราต้องทำ UI สำหรับ admin user เพื่อเตรียมอินพุตสำหรับปลั๊กอินของเรา. ใน getPropertyOptions method, เราได้ระบุไฟล์ ตัวเลือกคุณสมบัติปลั๊กอิน ไว้ที่ "/properties/formSubmissionStatisticsGenerator.json". ให้สร้าง directory "resources/properties" ภายใต้ "form_submission_statistics_generator/src/main" directory. หลังจากสร้าง directory, สร้างไฟล์ชื่อ "formSubmissionStatisticsGenerator.json" ในโฟลเดอร์ "properties"
ในไฟล์ตัวเลือกคุณสมบัติ เราจะต้องกำหนดตัวเลือกดังต่อไปนี้. โปรดทราบว่าเราสามารถใช้ "@@message.key@@" syntax เพื่อสนับสนุน 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; }
เมื่อเราทำตัวเลือกคุณสมบัติเพื่อรวบรวมอินพุตแล้วเราสามารถทำงานกับวิธีหลักของปลั๊กอินซึ่งเป็นวิธีการจัดรูปแบบ
@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 เราจะดึงข้อมูลไฟล์ "/resources/category.json" ในหมวดหมู่ JSON ให้เราสร้างไดเรกทอรี "resources / resources" ภายใต้ไดเรกทอรี "form_submission_statistics_generator / src / main" หลังจากสร้างไดเรกทอรีให้สร้างไฟล์ชื่อ "category.json" ในโฟลเดอร์ "resources" จากนั้นคัดลอกคำนิยามหมวดหมู่ JSON ที่เราสร้างไว้ก่อนหน้านี้และวางไว้ในไฟล์นี้ เราจะต้องแทนที่ค่า hardcoded บางส่วนเป็นตัวแปรและอย่าลืมหลีกเลี่ยง "%"
เป็น "%%" ที่มีอยู่เหล่านั้นเป็น AppUtil.readPluginResource โดยใช้ String.format เพื่อใส่ค่าลงในไฟล์
{ "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": "" } }] }
ปลั๊กอินของเราใช้ 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 -->
เรากำลังใช้ i18n message key ใน getLabel และ getDescription method. เรายังใช้ i18n message key ในไฟล์ตัวเลือกคุณสมบัติของเรา. ดังนั้นเราจะต้องสร้างไฟล์ message resource bundle properties เพื่อปลั๊กอินของเรา
สร้าง directory "resources/messages" ภายใต้ "form_submission_statistics_generator/src/main" directory. จากนั้นสร้างไฟล์ "FormSubmissionStatisticsGenerator.properties" ในโฟลเดอร์. ในไฟล์ตัวเลือกเราต้องเพิ่ม message keys และ label ดังต่อไปนี้
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!
เราจะต้องลงทะเบียนปลั๊กอินของเราที่ Activator class (Auto generated in the same class package) เพื่อบอก Felix Framework ว่านี่คือปลั๊กอิน
public void start(BundleContext context) { registrationList = new ArrayList<ServiceRegistration>(); //Register plugin here registrationList.add(context.registerService(FormSubmissionStatisticsGenerator.class.getName(), new FormSubmissionStatisticsGenerator(), null)); }
สร้างปลั๊กอินของเรา. หลังจากสร้างเสร็จเราจะพบไฟล์ "form_submission_statistics_generator-5.0.0.jar" สร้างภายใต้ "form_submission_statistics_generator/target" directory.
จากนั้นให้เราอัพโหลดปลั๊กอิน Manage Plugins. หลังจากอัพโหลดเสร็จให้เราตรวจสอบอีกครั้งวา่าปลั๊กอินสามารถให้ได้ไหม
ตอนนี้เราสามารถเปิดหนึ่งสำหรับแบบฟอร์มของเรามา ตัวสร้างฟอร์มสำหรับการทดสอบเครื่องกำเนิดไฟฟ้า คลิกที่ปุ่ม " Generate App" ที่ด้านบนขวาของตัวสร้างแบบฟอร์ม โปรดอ้างอิงถึง สร้างแอป (Generate App).
ให้เราตรวจสอบหน้าคุณสมบัติสำหรับ "เครื่องมือสร้างขั้นสูง"
หลังจากกระบวนการสร้างเสร็จสิ้น
หมวดหมู่ใหม่จะถูกเพิ่มเข้าไปในมุมมองของเรา
เมนูแผนภูมิ SQL จะแสดงดังต่อไปนี้
คุณสามารถดาวน์โหลด source code จาก form_submission_statistics_generator.zip.
หากต้องการดาวน์โหลด jar ปลั๊กอินที่พร้อมใช้งานโปรดค้นหา http://marketplace.joget.org/.