在本教程中,我们将遵循开发插件  来开发我们的JDBC Form Load Binder插件的  指导原则。请参考本教程,  如何开发一个Bean Shell Hash变量插件,  以及一个JDBC相关的插件,如何开发一个JDBC选项绑定器  以获得更多的细节步骤。

1.什么问题?

为了集成的目的,我们想从不同的数据库表中加载我们的表单数据,而不是Joget表单数据表。

2.如何解决问题?

Joget Workflow提供了一个名为Form Load Binder Plugin的插件类型  。我们将参考前者开发一个插件来支持JDBC连接和自定义查询来加载表单数据。

3.你的插件需要什么输入?

为了开发一个JDBC加载绑定器,我们需要JDBC连接设置以及自定义查询来基于主键或外键(对于网格)填充表单数据。

  1. 数据源:使用自定义数据源或Joget默认数据源
  2. 自定义JDBC驱动程序:自定义数据源的JDBC驱动程序
  3. 自定义JDBC URL:  自定义数据源的JDBC连接URL
  4. 自定义JDBC用户名:  自定义数据源的用户名
  5. 自定义JDBC密码:  自定义数据源的密码
  6. SQL查询:填充表单数据的查询。  

查询还应该支持注入主键(对于Form / Section)或外键(对于Grid元素)的语法,

例:

  1. SELECT * from app_fd_sample where id =?

4.你的插件的输出和预期结果是什么?

所有检索到的列自动映射到列名称等于字段ID的字段。 

5.是否有任何资源/ API可以重复使用?

我们可以参考其他可用的  Form Load Binder插件的实现。可以使用AppUtil.getApplicationContext().getBean("setupDataSource")来检索Joget的默认数据源。

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 jdbc_load_binder 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: jdbc_load_binder
version: 5.0.0
package: org.joget.tutorial
Y: : y

 

我们应该“使成功”,在我们的终端和“插件”文件夹中创建一个“jdbc_load_binder”文件夹中显示的信息。

用你喜欢的IDE打开maven项目。我将使用  NetBeans。  

7.只需编码!

a. 扩展插件类型的抽象类

在“org.joget.tutorial”包下创建一个“JdbcLoadBinder”类。然后,使用org.joget.apps.form.model.FormBinder  抽象类来扩展  该类。

为了使它作为一个表单加载活页夹,我们将需要实现  org.joget.apps.form.model.FormLoadBinder  接口。然后,我们需要实现 org.joget.apps.form.model.FormLoadElementBinder接口,使这个插件显示为一个选择,在载入活页夹选择框中实现 org.joget.apps.form.model.FormLoadMultiRowElementBinder接口,将其列在加载网格元素的活页夹选择框。 

 请参阅  表单加载活页夹插件

b. 实现所有的抽象方法

像往常一样,我们必须执行所有的抽象方法。我们将使用AppPluginUtil.getMessage方法来支持i18n,并使用常量变量MESSAGE_PATH作为消息资源包目录。

 

 

package org.joget.tutorial;
 
import org.joget.apps.app.service.AppPluginUtil;
import org.joget.apps.app.service.AppUtil;
import org.joget.apps.form.model.Element;
import org.joget.apps.form.model.FormBinder;
import org.joget.apps.form.model.FormData;
import org.joget.apps.form.model.FormLoadBinder;
import org.joget.apps.form.model.FormLoadElementBinder;
import org.joget.apps.form.model.FormLoadMultiRowElementBinder;
import org.joget.apps.form.model.FormRowSet;
 
public class JdbcLoadBinder extends FormBinder implements FormLoadBinder, FormLoadElementBinder, FormLoadMultiRowElementBinder {
    
    private final static String MESSAGE_PATH = "messages/JdbcLoadBinder";
    
    public String getName() {
        return "JDBC Load Binder";
    }
 
    public String getVersion() {
        return "5.0.0";
    }
    
    public String getClassName() {
        return getClass().getName();
    }
 
    public String getLabel() {
        //support i18n
        return AppPluginUtil.getMessage("org.joget.tutorial.JdbcLoadBinder.pluginLabel", getClassName(), MESSAGE_PATH);
    }
    
    public String getDescription() {
        //support i18n
        return AppPluginUtil.getMessage("org.joget.tutorial.JdbcLoadBinder.pluginDesc", getClassName(), MESSAGE_PATH);
    }
 
    public String getPropertyOptions() {
        return AppUtil.readPluginResource(getClassName(), "/properties/jdbcLoadBinder.json", null, true, MESSAGE_PATH);
    }
 
    public FormRowSet load(Element element, String primaryKey, FormData formData) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
}

然后,我们必须为管理员用户提供一个UI来为我们的插件提供输入。在getPropertyOptions方法中,我们已经指定了我们的  插件属性选项和配置  定义文件位于“/properties/jdbcLoadBinder.json”。让我们在“jdbc_load_binder / src / main”目录下创建一个目录“resources / properties”。创建目录后,在“properties”文件夹中创建一个名为“jdbcLoadBinder.json”的文件。

在属性定义选项文件中,我们需要提供如下的选项。请注意,我们可以在我们的属性选项中使用“@@ message.key @@”语法来支持i18n。

 

[{
    title : '@@form.jdbcLoadBinder.config@@',
    properties : [{
        name : 'jdbcDatasource',
        label : '@@form.jdbcLoadBinder.datasource@@',
        type : 'selectbox',
        options : [{
            value : 'custom',
            label : '@@form.jdbcLoadBinder.customDatasource@@'
        },{
            value : 'default',
            label : '@@form.jdbcLoadBinder.defaultDatasource@@'
        }],
        value : 'default'
    },{
        name : 'jdbcDriver',
        label : '@@form.jdbcLoadBinder.driver@@',
        description : '@@form.jdbcLoadBinder.driver.desc@@',
        type : 'textfield',
        value : 'com.mysql.jdbc.Driver',
        control_field: 'jdbcDatasource',
        control_value: 'custom',
        control_use_regex: 'false',
        required : 'true'
    },{
        name : 'jdbcUrl',
        label : '@@form.jdbcLoadBinder.url@@',
        type : 'textfield',
        value : 'jdbc:mysql://localhost/jwdb?characterEncoding=UTF8',
        control_field: 'jdbcDatasource',
        control_value: 'custom',
        control_use_regex: 'false',
        required : 'true'
    },{
        name : 'jdbcUser',
        label : '@@form.jdbcLoadBinder.username@@',
        type : 'textfield',
        control_field: 'jdbcDatasource',
        control_value: 'custom',
        control_use_regex: 'false',
        value : 'root',
        required : 'true'
    },{
        name : 'jdbcPassword',
        label : '@@form.jdbcLoadBinder.password@@',
        type : 'password',
        control_field: 'jdbcDatasource',
        control_value: 'custom',
        control_use_regex: 'false',
        value : ''
    },{
        name : 'sql',
        label : '@@form.jdbcLoadBinder.sql@@',
        description : '@@form.jdbcLoadBinder.sql.desc@@',
        type : 'codeeditor',
        mode : 'sql',
        required : 'true'
    }],
    buttons : [{
        name : 'testConnection',   
        label : '@@form.jdbcLoadBinder.testConnection@@',
        ajax_url : '[CONTEXT_PATH]/web/json/app[APP_PATH]/plugin/org.joget.tutorial.JdbcLoadBinder/service?action=testConnection',
        fields : ['jdbcDriver''jdbcUrl''jdbcUser''jdbcPassword'],
        control_field: 'jdbcDatasource',
        control_value: 'custom',
        control_use_regex: 'false'
    }]
}]

 

JDBC Options Binder相同  ,我们需要添加一个测试连接按钮来进行自定义的JDBC设置。请参阅  如何开发一个JDBC选项绑定器上的  Web服务插件实现。

一旦我们完成了收集输入的属性选项和Web服务来测试连接,我们可以在插件的主要方法,这是加载方法。

 

public FormRowSet load(Element element, String primaryKey, FormData formData) {
    FormRowSet rows = new FormRowSet();
    rows.setMultiRow(true);
    //Check the sql. If require primary key and primary key is null, return empty result.
    String sql = getPropertyString("sql");
    if ((primaryKey == null || primaryKey.isEmpty()) && sql.contains("?")) {
        return rows;
    }
     
    Connection con = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
     
    try {
        DataSource ds = createDataSource();
        con = ds.getConnection();
         
        pstmt = con.prepareStatement(sql);
         
        //set query parameters
        if (sql.contains("?") && primaryKey != null && !primaryKey.isEmpty()) {
            pstmt.setObject(1, primaryKey);
        }
         
        rs = pstmt.executeQuery();
        ResultSetMetaData rsmd = rs.getMetaData();
        int columnsNumber = rsmd.getColumnCount();
         
        // Set retrieved result to Form Row Set
        while (rs.next()) {
            FormRow row = new FormRow();
             
            //get the name of each column as field id
            for (int i = 1; i <= columnsNumber; i++) {
                String name = rsmd.getColumnName(i);
                String value = rs.getString(name);
                 
                if (FormUtil.PROPERTY_ID.equals(name)) {
                    row.setId(value);
                else {
                    row.setProperty(name, (value != null)?value:"");
                }
            }
             
            rows.add(row);
        }
    catch (Exception e) {
        LogUtil.error(getClassName(), e, "");
    finally {
        try {
            if (rs != null) {
                rs.close();
            }
            if (pstmt != null) {
                pstmt.close();
            }
            if (con != null) {
                con.close();
            }
        catch (Exception e) {
            LogUtil.error(getClassName(), e, "");
        }
    }
     
    return rows;
}
 
/**
 * To creates data source based on setting
 * @return
 * @throws Exception
 */
protected DataSource createDataSource() throws Exception {
    DataSource ds = null;
    String datasource = getPropertyString("jdbcDatasource");
    if ("default".equals(datasource)) {
        // use current datasource
         ds = (DataSource)AppUtil.getApplicationContext().getBean("setupDataSource");
    else {
        // use custom datasource
        Properties dsProps = new Properties();
        dsProps.put("driverClassName", getPropertyString("jdbcDriver"));
        dsProps.put("url", getPropertyString("jdbcUrl"));
        dsProps.put("username", getPropertyString("jdbcUser"));
        dsProps.put("password", getPropertyString("jdbcPassword"));
        ds = BasicDataSourceFactory.createDataSource(dsProps);
    }
    return ds;
}

 

C。管理你的插件的依赖库

我们的插件使用dbcp,javax.servlet.http.HttpServletRequest和javax.servlet.http.HttpServletResponse类,所以我们需要将jsp-api和commons-dbcp库添加到我们的POM文件中。

 

<!-- Change plugin specific dependencies here -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.0</version>
</dependency>
<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.3</version>
</dependency>
<!-- End change plugin specific dependencies here -->

 

d。让你的插件国际化(i18n)准备就绪

我们在getLabel和getDescription方法中使用i18n消息密钥。我们还在我们的属性选项定义中使用了i18n消息密钥。所以,我们需要为我们的插件创建一个消息资源包属性文件。

在“jdbc_load_binder / src / main”目录下创建目录“resources / messages”。然后,在该文件夹中创建一个“JdbcLoadBinder.properties”文件。在属性文件中,让我们添加所有的消息键和它的标签如下。

 

org.joget.tutorial.JdbcLoadBinder.pluginLabel=JDBC Binder
org.joget.tutorial.JdbcLoadBinder.pluginDesc=Used to load form data using JDBC
form.jdbcLoadBinder.config=Configure JDBC Binder
form.jdbcLoadBinder.datasource=Datasource
form.jdbcLoadBinder.customDatasource=Custom Datasource
form.jdbcLoadBinder.defaultDatasource=Default Datasource
form.jdbcLoadBinder.driver=Custom JDBC Driver
form.jdbcLoadBinder.driver.desc=Eg. com.mysql.jdbc.Driver (MySQL), oracle.jdbc.driver.OracleDriver (Oracle), com.microsoft.sqlserver.jdbc.SQLServerDriver (Microsoft SQL Server)
form.jdbcLoadBinder.url=Custom JDBC URL
form.jdbcLoadBinder.username=Custom JDBC Username
form.jdbcLoadBinder.password=Custom JDBC Password
form.jdbcLoadBinder.sql=SQL SELECT Query
form.jdbcLoadBinder.sql.desc=Use question mark (?) in your query to represent primary key or foreign key
form.jdbcLoadBinder.testConnection=Test Connection
form.jdbcLoadBinder.connectionOk=Database connected
form.jdbcLoadBinder.connectionFail=Not able to establish connection.

 

e. 注册你的插件Felix框架

我们将不得不在Activator类(在同一个类包中自动生成)中注册我们的插件类,以告诉Felix框架这是一个插件。

 

public void start(BundleContext context) {
    registrationList = new ArrayList<ServiceRegistration>();
    //Register plugin here
    registrationList.add(context.registerService(JdbcLoadBinder.class.getName(), new JdbcLoadBinder(), null));

 

f. 建设和测试

让我们建立我们的插件。一旦构建过程完成,我们将在“jdbc_load_binder / target”目录下创建一个“jdbc_load_binder-5.0.0.jar”文件。

然后,让插件jar上传到  管理插件。上传jar文件后,仔细检查插件是否正确上传和激活。

让我们创建一个表单,根据用户名从dir_user表中加载firstName,lastName和email,以测试加载联编程序。

然后,将表单的加载联编程序配置为使用JDBC联编程序和以下查询。

 

select from dir_user where username = ?

 

让我们创建一个用户视图并拖动一个表单菜单元素来显示我们的表单。然后,发布它并用“id”参数测试我们的表单。

接下来,让我们添加一个网格元素,并使用以下查询进行测试。

 

select from dir_group g
join dir_user_group ug on ug.groupId = g.id
where ug.userId = ?

 

再次检查我们的结果。

有用!请记住测试插件的其他功能。 (big grin)

8.再进一步,分享或出售

您可以从jdbc_load_binder_src.zip下载源代码  。

要下载现成的插件jar,请在http://marketplace.joget.org/上找到它  。