柏球侠 发表于 2026-1-16 14:50:01

金蝶云苍穹,新手初学者小白PC端java插件开发教学示例

注:
1.本文章的面向对象为刚刚接触金蝶云苍穹星空旗舰版,具有PC端Java插件开发需求的新手、小白、与初学者
2.本文章中涉及的开发环境包括:金蝶云苍穹星空旗舰版开发平台、安装了金蝶官方插件的IDEA
3.插件的实际开发涉及表单页面的生命周期,建议对此内容有一定熟悉,页面的生命周期参考文章:
https://vip.kingdee.com/article/403237280594265344?productLineId=29&lang=zh-CN
4.本文档涉及一些金蝶官方的插件代码方法,这些插件代码方法的使用与介绍可以参考SDK文档:
https://dev.kingdee.com/sdk/Cosmic%20V5.0.002/index.html?nav=package
5.文章的代码都是为了方便理解,使用的变量名都尽量简单,实际的业务开发中需要进行代码规范化处理,代码规范参考IDEA中金蝶官方插件的代码分析功能。
6.文章或许哪里讲的不够详细,或者存在疑意,有任何不明白或者不清楚的地方可以在评论区留言,如果我清楚的话会尽量尽快回复的
7.此文章在金蝶官方的开发者社区也有发布,本着能对像我一样熟悉博客园的金蝶开发者起到帮助的想法,所以将文章在园子又发布了一遍,金蝶开发者社区的此文链接:
https://vip.kingdee.com/article/799643532909519872?productLineId=29&lang=zh-CN
一、插件开发思路
对于插件的开发,我们首先要确定的,是插件要实现的功能。
然后根据功能,我们再进一步确定,这个功能包含的事件,事件触发页面的页面类型,事件的触发时机,事件的逻辑。
等到这些都确定完后,我们就可以进行实际开发了。
比如说,我想要开发一个表单插件,插件的功能是批量修改列表某些分录(数据行)的数量字段或者状态字段的值。
那么这时候我会确定,这个功能的流程是:用户选中数据——>点击按钮——>修改选中数据的字段值——>字段列刷新。
这样一来就可以确定,事件触发页面的页面类型(单据列表类型),触发时机(用户点击按钮之后),事件的逻辑(获取到用户选择的数据之后批量修改数据的字段值,最后刷新页面)。

二、新建插件类
在IDEA中新建一个项目,在项目的对应plugin路径下,新建一个插件类,新建时选择继承的插件类名与继承的插件类型,例如:
1.我的插件类为页面插件,所以选择plugin目录下的form文件夹新建插件类(右键点击form文件夹,点击新建,选择金蝶插件的继承插件)


2.命名插件类并选择继承的插件类类型,这里我是列表页面插件,于是我选择标准单据列表插件类型

新建后的插件类内容:
package ***.plugin.other;
import kd.bos.list.plugin.AbstractListPlugin;
import kd.sdk.plugin.Plugin;
/**
* 标准单据列表插件
*/
public class teacherListPlugin extends AbstractListPlugin implements PLugin {
}3.编写代码实现事件的逻辑
3.1,事件按钮添加
因为我的插件事件需要用户点击按钮来触发,所以我在页面上添加了两个新的按钮(状态正常按钮与数量0按钮),
并将按钮的操作代码选择为dothing(空操作),操作后刷新字段一个选择为数量(qty),一个选择为(status)


3.2,编写代码
因为我的事件在用户点击对应按钮后触发,所以首先注册两个按钮的点击监听事件
(添加工具栏按钮点击监听的事件为addItemClickListeners,在生命周期registerListener中添加)
private static final String FID_TOOLBAR = "toolbar";//默认的工具栏标识
    @Override
    public void registerListener(EventObject e) {
      super.registerListener(e);
      this.addItemClickListeners(FID_TOOLBAR);// 添加工具栏按钮点击的监听事件,监听的工具栏为字段标识对应的工具栏
    }插件类全代码:
package ***.plugin.other;
import kd.bos.list.plugin.AbstractListPlugin;
import kd.sdk.plugin.Plugin;
import java.util.EventObject;

/**
* 标准单据列表插件
*/
public class teacherListPlugin extends AbstractListPlugin implements Plugin {
    private static final String toolbar = "toolbar";//默认的工具栏标识
    @Override
    public void registerListener(EventObject e) {
      super.registerListener(e);
      this.addItemClickListeners(toolbar);// 添加工具栏按钮点击的监听事件,监听的工具栏为字段标识对应的工具栏
    }
}然后注册两个按钮的监听事件:
private static final String statusbtn = "statusbtn";//状态正常按钮的对应字段标识
private static final String qtybtn = "qtybtn";//数量0按钮的对应字段标识
@Override
    public void itemClick(ItemClickEvent evt) {
      if (statusbtn.equals(evt.getItemKey())) {//监听状态正常按钮的点击事件
            status();//状态正常事件逻辑处理方法
      } else if (qtybtn.equals(evt.getItemKey())) {//监听数量0按钮的点击事件
            qty();//数量重置为0事件逻辑处理方法
      }
    }
private void status(){//状态正常事件逻辑

}
private void qty(){//数量0事件逻辑

}插件类全部代码:
package ***.plugin.other;
import kd.bos.form.control.events.ItemClickEvent;
import kd.bos.list.plugin.AbstractListPlugin;
import kd.sdk.plugin.Plugin;
import java.util.EventObject;

/**
* 标准单据列表插件
*/
public class teacherListPlugin extends AbstractListPlugin implements Plugin {
    private static final String toolbar = "toolbar";//默认的工具栏标识
    private static final String statusbtn = "statusbtn";//状态正常按钮的对应字段标识
    private static final String qtybtn = "qtybtn";//数量0按钮的对应字段标识
    @Override
    public void registerListener(EventObject e) {
      super.registerListener(e);
      this.addItemClickListeners(toolbar);// 添加工具栏按钮点击的监听事件,监听的工具栏为字段标识对应的工具栏
    }
    @Override
    public void itemClick(ItemClickEvent evt) {
      if (statusbtn.equals(evt.getItemKey())) {//监听状态正常按钮的点击事件
            status();//状态正常事件逻辑处理方法
      } else if (qtybtn.equals(evt.getItemKey())) {//监听数量0按钮的点击事件
            qty();//数量重置为0事件逻辑处理方法
      }
    }
    private void status(){//状态正常事件逻辑

    }
    private void qty(){//数量0事件逻辑

    }
}然后开始编写事件逻辑方法,(补充:状态字段的字段标识为status,控件类型为下拉列表,状态正常的对应值为"0",数量字段的字段标识为qty,控件类型为整数)
状态正常事件:
private void status(){//状态正常事件逻辑
      ListSelectedRowCollection selectedRows = this.getSelectedRows();//获取当前列表选中行的索引
      if (selectedRows == null || selectedRows.isEmpty()) {//校验选中行数量是否为空,为空则停止事件并提示
            this.getView().showTipNotification("请先选择要操作的数据");
            return;
      }
      //根据选中行的索引获取对应数据的主键值
      List<Long> ids = new ArrayList<>();
      for(ListSelectedRow row : selectedRows){
            ids.add((Long)row.getPrimaryKeyValue());
      }
      //根据获取到的对应事件主键值批量查询获取数据
      DynamicObject[] datas = BusinessDataServiceHelper.load("teacher",//第一个参数:要查询数据的表单的标识
                "id,number,name,status",//第二个参数:要查询的数据的属性名
                new QFilter[]{new QFilter("id", QCP.in,ids)}//第三个参数:要查询的数据的过滤条件
      );
      //遍历数据数组,对数据的对应字段的值进行修改
      for (DynamicObject data : datas){
            data.set("status","0");//正常状态的对应值为"0"
      }
      SaveServiceHelper.save(datas);//保存修改后的结果
        this.getView().invokeOperation("refresh");//刷新页面
}数量0事件:
ListSelectedRowCollection selectedRows = this.getSelectedRows();//获取当前列表选中行的索引
      if (selectedRows == null || selectedRows.isEmpty()) {//校验选中行数量是否为空,为空则停止事件并提示
            this.getView().showTipNotification("请先选择要操作的数据");
            return;
      }
      //根据选中行的索引获取对应数据的主键值
      List<Long> ids = new ArrayList<>();
      for(ListSelectedRow row : selectedRows){
            ids.add((Long)row.getPrimaryKeyValue());
      }
      //根据获取到的对应事件主键值批量查询获取数据
      DynamicObject[] datas = BusinessDataServiceHelper.load("teacher",//第一个参数:要查询数据的表单的标识
                "id,number,name,qty",//第二个参数:要查询的数据的属性名
                new QFilter[]{new QFilter("id", QCP.in,ids)}//第三个参数:要查询的数据的过滤条件
      );
      //遍历数据数组,对数据的对应字段的值进行修改
      for (DynamicObject data : datas){
            data.set("qty",0);//正常状态的对应值为"0"
      }
      SaveServiceHelper.save(datas);//保存修改后的结果
        this.getView().invokeOperation("refresh");//刷新页面插件类全代码:
package ***.plugin.other;import kd.bos.dataentity.entity.DynamicObject;import kd.bos.entity.datamodel.ListSelectedRow;import kd.bos.entity.datamodel.ListSelectedRowCollection;import kd.bos.form.control.events.ItemClickEvent;import kd.bos.list.plugin.AbstractListPlugin;import kd.bos.orm.query.QCP;import kd.bos.orm.query.QFilter;import kd.bos.servicehelper.BusinessDataServiceHelper;import kd.bos.servicehelper.operation.SaveServiceHelper;import kd.sdk.plugin.Plugin;import java.util.ArrayList;import java.util.EventObject;import java.util.List;/** * 标准单据列表插件 */public class teacherListPlugin extends AbstractListPlugin implements Plugin {    private static final String toolbar = "toolbar";//默认的工具栏标识    private static final String statusbtn = "statusbtn";//状态正常按钮的对应字段标识    private static final String qtybtn = "qtybtn";//数量0按钮的对应字段标识    @Override    public void registerListener(EventObject e) {      super.registerListener(e);      this.addItemClickListeners(toolbar);// 添加工具栏按钮点击的监听事件,监听的工具栏为字段标识对应的工具栏    }    @Override    public void itemClick(ItemClickEvent evt) {      if (statusbtn.equals(evt.getItemKey())) {//监听状态正常按钮的点击事件            status();//状态正常事件逻辑处理方法      } else if (qtybtn.equals(evt.getItemKey())) {//监听数量0按钮的点击事件            qty();//数量重置为0事件逻辑处理方法      }    }    private void status(){//状态正常事件逻辑      ListSelectedRowCollection selectedRows = this.getSelectedRows();//获取当前列表选中行的索引      if (selectedRows == null || selectedRows.isEmpty()) {//校验选中行数量是否为空,为空则停止事件并提示            this.getView().showTipNotification("请先选择要操作的数据");            return;      }      //根据选中行的索引获取对应数据的主键值      List ids = new ArrayList();      for(ListSelectedRow row : selectedRows){            ids.add((Long)row.getPrimaryKeyValue());      }      //根据获取到的对应事件主键值批量查询获取数据      DynamicObject[] datas = BusinessDataServiceHelper.load("teacher",//第一个参数:要查询数据的表单的标识                "id,number,name,status",//第二个参数:要查询的数据的属性名                new QFilter[]{new QFilter("id", QCP.in,ids)}//第三个参数:要查询的数据的过滤条件      );      //遍历数据数组,对数据的对应字段的值进行修改      for (DynamicObject data : datas){            data.set("status","0");//正常状态的对应值为"0"      }      SaveServiceHelper.save(datas);//保存修改后的结果        this.getView().invokeOperation("refresh");//刷新页面    }    private void qty(){//数量0事件逻辑      ListSelectedRowCollection selectedRows = this.getSelectedRows();//获取当前列表选中行的索引
      if (selectedRows == null || selectedRows.isEmpty()) {//校验选中行数量是否为空,为空则停止事件并提示
            this.getView().showTipNotification("请先选择要操作的数据");
            return;
      }
      //根据选中行的索引获取对应数据的主键值
      List<Long> ids = new ArrayList<>();
      for(ListSelectedRow row : selectedRows){
            ids.add((Long)row.getPrimaryKeyValue());
      }
      //根据获取到的对应事件主键值批量查询获取数据
      DynamicObject[] datas = BusinessDataServiceHelper.load("teacher",//第一个参数:要查询数据的表单的标识
                "id,number,name,qty",//第二个参数:要查询的数据的属性名
                new QFilter[]{new QFilter("id", QCP.in,ids)}//第三个参数:要查询的数据的过滤条件
      );
      //遍历数据数组,对数据的对应字段的值进行修改
      for (DynamicObject data : datas){
            data.set("qty",0);//正常状态的对应值为"0"
      }
      SaveServiceHelper.save(datas);//保存修改后的结果
        this.getView().invokeOperation("refresh");//刷新页面    }}3.3,注册插件
插件类编写完成后,需要将代码绑定到对应页面上才能生效:


示例:

然后点击保存页面

三、页面运行测试插件
点击页面预览按钮进入预览模式,然后测试对应功能

我的:
点击状态正常按钮前与点击正常状态按钮后:


点击数量0前与点击数量0按钮后:



来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

狭踝仇 发表于 2026-1-18 06:08:10

懂技术并乐意极积无私分享的人越来越少。珍惜

俏挺喳 发表于 2026-1-20 23:32:51

用心讨论,共获提升!

嶝扁 发表于 2026-1-22 07:39:31

感谢,下载保存了

祉遛吾 发表于 2026-1-23 06:09:22

分享、互助 让互联网精神温暖你我

镝赋洧 发表于 2026-1-27 07:18:56

感谢分享,学习下。

龙玮奇 发表于 2026-1-27 07:44:48

喜欢鼓捣这些软件,现在用得少,谢谢分享!

向梦桐 发表于 2026-2-2 04:33:24

鼓励转贴优秀软件安全工具和文档!

甦忻愉 发表于 2026-2-3 04:46:15

热心回复!

橘芜 发表于 2026-2-3 10:42:23

热心回复!

吕颐然 发表于 2026-2-4 09:37:13

感谢分享,学习下。

寨重 发表于 2026-2-5 14:19:12

收藏一下   不知道什么时候能用到

冷晓晴 发表于 2026-2-7 22:38:23

热心回复!

疝镜泛 发表于 2026-2-8 15:06:18

感谢分享,学习下。

尚腱埂 发表于 2026-2-9 02:55:54

感谢,下载保存了

水苯 发表于 2026-2-9 05:04:21

谢谢分享,试用一下

秦欣艷 发表于 2026-2-10 13:08:12

谢谢楼主提供!

度阡舅 发表于 2026-2-10 19:54:57

分享、互助 让互联网精神温暖你我

乃阕饯 发表于 2026-2-11 12:13:48

谢谢分享,辛苦了

屠焘 发表于 2026-2-12 05:19:01

这个有用。
页: [1] 2
查看完整版本: 金蝶云苍穹,新手初学者小白PC端java插件开发教学示例