Joget DX 8 Stable Released
The stable release for Joget DX 8 is now available, with a focus on UX and Governance.
...
在本教程中,我们将遵循 guideline for developing a plugin 来开发一个下载PDF 数据列表插件.有关更多详细信息步骤,请参阅第一个教程 如何开发一个Bean Shell Hash Variable插件.
我们需要能够从datalist下载PDF格式的表格数据。
我们将开发一个 Datalist Action插件 来显示一个按钮来生成一个表单PDF文件。
要开发一个PDF下载Datalist Action插件,我们将考虑提供以下内容作为输入。
当“PDF Download Datalist Action”用作数据列行操作或列操作时,普通用户将在数据列表的每一行中看到链接以下载PDF文件。一旦链接被点击,一个PDF文件将被提示下载该特定的行。
当插件用于多个datalist行(整个列表操作)时,包含所有生成的每个选定行的PDF文件的zip文件将被点击按钮时提示下载。
要开发PDF下载Datalist Action插件,我们可以重用FormPdfUtil中的方法 来生成PDF格式的表单。我们也可以参考 Datalist Form Data Delete Action插件的 源代码。除此之外,我们可以参考 导出表单电子邮件工具 ,了解我们可以在插件中提供哪种插件属性选项,因为导出表单电子邮件工具也使用FormPdfUtil中的方法。
我们需要始终准备好Joget Workflow Source Code,并按照这个指导方针建立起来 。
...
用你最喜欢的IDE打开maven项目。我将使用 NetBeans。
在“org.joget.tutorial”包下创建一个“DownloadPdfDatalistAction”类。然后,使用org.joget.apps.datalist.model.DataListActionDefault抽象类来扩展 该类。请参阅 Datalist Action插件。
像往常一样,我们必须执行所有的抽象方法。我们将使用AppPluginUtil.getMessage方法来支持i18n,并使用常量变量MESSAGE_PATH作为消息资源包目录。
...
Code Block | ||
---|---|---|
| ||
public DataListActionResult executeAction(DataList dataList, String[] rowKeys) { // only allow POST HttpServletRequest request = WorkflowUtil.getHttpServletRequest(); if (request != null && !"POST".equalsIgnoreCase(request.getMethod())) { return null; } // check for submited rows if (rowKeys != null && rowKeys.length > 0) { try { //get the HTTP Response HttpServletResponse response = WorkflowUtil.getHttpServletResponse(); if (rowKeys.length == 1) { //generate a pdf for download singlePdf(request, response, rowKeys[0]); } else { //generate a zip of all pdfs multiplePdfs(request, response, rowKeys); } } catch (Exception e) { LogUtil.error(getClassName(), e, "Fail to generate PDF for " + ArrayUtils.toString(rowKeys)); } } //return null to do nothing return null; } /** * Handles for single pdf file * @param request * @param response * @param rowKey * @throws IOException * @throws javax.servlet.ServletException */ protected void singlePdf(HttpServletRequest request, HttpServletResponse response, String rowKey) throws IOException, ServletException { byte[] pdf = getPdf(rowKey); writeResponse(request, response, pdf, rowKey+".pdf", "application/pdf"); } /** * Handles for multiple files download. Put all pdfs in zip. * @param request * @param response * @param rowKeys * @throws java.io.IOException * @throws javax.servlet.ServletException */ protected void multiplePdfs(HttpServletRequest request, HttpServletResponse response, String[] rowKeys) throws IOException, ServletException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(baos); try { //create pdf and put in zip for (String id : rowKeys) { byte[] pdf = getPdf(id); zip.putNextEntry(new ZipEntry(id+".pdf")); zip.write(pdf); zip.closeEntry(); } zip.finish(); writeResponse(request, response, baos.toByteArray(), getLinkLabel() +".zip", "application/zip"); } finally { baos.close(); zip.flush(); } } /** * Generate PDF using FormPdfUtil * @param id * @return */ protected byte[] getPdf(String id) { AppDefinition appDef = AppUtil.getCurrentAppDefinition(); String formDefId = getPropertyString("formDefId"); Boolean hideEmptyValueField = null; if (getPropertyString("hideEmptyValueField").equals("true")) { hideEmptyValueField = true; } Boolean showNotSelectedOptions = null; if (getPropertyString("showNotSelectedOptions").equals("true")) { showNotSelectedOptions = true; } Boolean repeatHeader = null; if ("true".equals(getPropertyString("repeatHeader"))) { repeatHeader = true; } Boolean repeatFooter = null; if ("true".equals(getPropertyString("repeatFooter"))) { repeatFooter = true; } String css = null; if (!getPropertyString("formatting").isEmpty()) { css = getPropertyString("formatting"); } String header = null; if (!getPropertyString("headerHtml").isEmpty()) { header = getPropertyString("headerHtml"); header = AppUtil.processHashVariable(header, null, null, null); } String footer = null; if (!getPropertyString("footerHtml").isEmpty()) { footer = getPropertyString("footerHtml"); footer = AppUtil.processHashVariable(footer, null, null, null); } return FormPdfUtil.createPdf(formDefId, id, appDef, null, hideEmptyValueField, header, footer, css, showNotSelectedOptions, repeatHeader, repeatFooter); } /** * Write to response for download * @param response * @param bytes * @param filename * @param contentType * @throws IOException */ protected void writeResponse(HttpServletRequest request, HttpServletResponse response, byte[] bytes, String filename, String contentType) throws IOException, ServletException { OutputStream out = response.getOutputStream(); try { String name = URLEncoder.encode(filename, "UTF8").replaceAll("\\+", "%20"); response.setHeader("Content-Disposition", "attachment; filename="+name+"; filename*=UTF-8''" + name); response.setContentType(contentType+"; charset=UTF-8"); if (bytes.length > 0) { response.setContentLength(bytes.length); out.write(bytes); } } finally { out.flush(); out.close(); //simply foward to a request.getRequestDispatcher(filename).forward(request, response); } } |
我们的插件使用javax.servlet.http.HttpServletRequest和javax.servlet.http.HttpServletResponse类,因此我们需要将jsp-api库添加到我们的POM文件中。
Code Block | ||
---|---|---|
| ||
<!-- 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 --> |
我们在getLabel和getDescription方法中使用i18n消息密钥。我们将在我们的属性选项定义中使用i18n消息密钥。然后,我们将需要为我们的插件创建一个消息资源包属性文件。
...
Code Block |
---|
org.joget.tutorial.DownloadPdfDatalistAction.pluginLabel=Download PDF org.joget.tutorial.DownloadPdfDatalistAction.pluginDesc=Support to download form PDF from datalist datalist.downloadPdf.download=Download datalist.downloadPdf.config=Configure Download PDF Action datalist.downloadPdf.label=Label datalist.downloadPdf.form=Form datalist.downloadPdf.recordIdColumn=Record Id Column datalist.downloadPdf.recordIdColumn.desc=Default to the primary key of the configured binder datalist.downloadPdf.confirmationMessage=Confirmation Message datalist.downloadPdf.hideEmptyValueField=Hide field that without value datalist.downloadPdf.showNotSelectedOptions=Show unselected options for multi options field datalist.downloadPdf.advanced=Advanced datalist.downloadPdf.formatting=Formatting (CSS) datalist.downloadPdf.headerHtml=Header (HTML) datalist.downloadPdf.repeatHeader=Repeat header on every page? datalist.downloadPdf.footerHtml=Footer (HTML) datalist.downloadPdf.repeatFooter=Repeat footer on every page? |
接下来,我们将需要在Activator类(在同一个类包中自动生成)中注册我们的插件类,以告诉Felix框架这是一个插件。
Code Block | ||
---|---|---|
| ||
public void start(BundleContext context) { registrationList = new ArrayList<ServiceRegistration>(); //Register plugin here registrationList.add(context.registerService(DownloadPdfDatalistAction.class.getName(), new DownloadPdfDatalistAction(), null)); } |
让我们建立我们的插件。一旦构建过程完成,我们将在“download_pdf_datalist_action / target”目录下找到一个“download_pdf_datalist_action-5.0.0.jar”文件。
...
当点击时,下载pdf。
当整个列表动作被点击时,一个zip文件被下载。
您可以从download_pdf_datalist_action.zip下载源代码 。
...