泛微E9二次开发资料完整总结版

avatar
作者
筋斗云
阅读量:0

文章目录

1、EC9系统说明

如需本地版本,请移步下载资源
https://download.csdn.net/download/u010048119/86444408?spm=1001.2014.3001.5503

1.1、系统核心框架

image-20220315110246299

  • 后端增加了分层、AOP、IOC、interceptor的支持
  • 新架构要求service和Command层必须面向接口编程, 同时通过IOC和命令委托方式进行各层的解耦
  • 新架构还提供全局interceptor和局部interceptor、SERVICE-AOP、COMMAND-AOP的支持,可以进行比如日志记录、声明性事务、安全性,和缓存等等功能的实现和无侵入二开

image-20220315151709001

1.2、系统目录结构

WEAVER

ecology
classbean 存放编译后的CLASS文件
WEB-INF
lib 系统依赖Jar文件目录
prop 系统配置文件存放

2、环境搭建

2.1、Ecology测试环境搭建

步骤1:从服务器上拷贝WEAVER/ecology代码
从服务器拷贝ecology相关代码到本地,目录服务器上文件如下图,需拷贝ecologyResin/Resin4,如果本机已安装JDK则可以不需拷贝JDK

image-20210917145946880

步骤2:代码复制至本地D:/WEAVER 文件夹下

步骤3:备份ecology数据库,还原到本地或测试数据库

请一定要记得修改数据库配置文件中的数据库配置,否则搭建的开发环境也是连接到正式库,那就很有可能会导致正式库中的数据出错

配置文件:D:/weaver/ecology/WEB-INF/prop/weaver.properties

SQLServer

DriverClasses = com.microsoft.sqlserver.jdbc.SQLServerDriver ecology.url = jdbc:sqlserver://192.168.4.246:1433;DatabaseName=ecology60 ecology.user = sa ecology.password = ecology 

Oracle

DriverClasses = oracle.jdbc.OracleDriver ecology.url = jdbc:oracle:thin:@192.168.4.238:1521:ecology ecology.user = nmsy ecology.password = ecology 

2.2、后端开发环境搭建

https://e-cloudstore.com/doc.html?appId=c6a9ae6e47b74d4da04c935ed51d177a

2.3、ecode使用说明

https://e-cloudstore.com/doc.html

2.4、e9技术站

https://e-cloudstore.com/e9/index2.html

2.5、后端代码目录结构

image-20220523143556166

image-20220523143645054

image-20220523143712127

image-20220523143752345

image-20220523143817623

image-20220523143839332

3、数据存储

3.1、流程数据存储

常用流程相关存储说明,详情见表结构说明文档

数据库表名中文说明
workflow_base流程基本信息
workflow_bill流程表单信息
workflow_billfield表单字段信息
workflow_nodebase节点信息
workflow_currentoperator请求节点操作人
workflow_requestlog请求签字意见
workflow_nownode请求当前节点
workflow_selectitem下拉框信息

3.2、人力资源相关数据存储

以下只列举一些常用表结构,更多表结构参考表建构文档。

表名说明
HrmResource人力资源基本信息表
HrmResourceManager系统管理员信息表
HrmDepartment人力资源部门表
HrmSubCompany人力资源分部表
hrmjobtitles岗位信息表

3.3、文档相关相关数据存储


以下只列举一些常用表结构,更多表结构参考表建构文档。

表名说明
Docdetail文档信息表
DocImageFile文档附件图片表
ImageFile文件存放信息表
DocShare文档共享信息表
DocSecCategory文档子目录表

4、数据源 DataSource

该接口主要用来在e-cology配置和异构系统的数据库的链接方式,通过此链接在e-cology中直接操作其他系统的数据。

后台设置
路径:集成中心-功能集成数据源设置

image-20210916113553525

程序调用

//引入相关的类 import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import weaver.general.BaseBean; import weaver.general.StaticObj; import weaver.interfaces.datasource.DataSource;   //调用数据源生成jdbc链接 DataSource ds = (DataSource)StaticObj.getServiceByFullname(("datasource.NC"),DataSource.class); //local为配置的数据源标识 Connection conn = null ;   try{     conn = ds.getConnection();     ResultSet rs = conn.createStatement().executeQuery("select top 10 lastname,password from 	  hrmresource");     while(rs.next()){       System.out.println("name-->"+rs.getString("lastname")+" pwd-->"+rs.getString("password"));     }     rs.close();   }catch(Exception e){     writeLog(e);   }finally{     try {       conn.close();     } catch (SQLException e) {      }   } 

5、流程自定义接口动作

5.1、流程流转过程理解

这是一个简单的流程图

image-20220315143624985

对应实际的流程流转过程

image-20220315143451919

5.2、自定义接口动作示例代码

该接口主要实现在流程的流转当中,实时通过自定义的动作去操作异构形体系统的数据或者是其他一些特定的操作。

在流程的每个出口或者节点都可以定义这样的自定义动作,从而实现在流程流转过程导入,导出流程的相关信息,或者将流程信息和

其他应用相结合进行数据交互。

注意自定义接口动作代码在退回到第一节点前是生效的,创建时不会生效

编写Action

新建Action实现类必须实现接口weaver.interfaces.workflow.action方法

public String execute(RequestInfo request)

package weaver.interfaces.workflow.action;  import weaver.general.BaseBean; import weaver.soa.workflow.request.DetailTableInfo; import weaver.soa.workflow.request.MainTableInfo; import weaver.soa.workflow.request.Property; import weaver.soa.workflow.request.RequestInfo;  public class TestAction extends BaseBean implements Action {      public String p1; //自定义参数1     public String p2; //自定义参数2 	public String getP1() {         return p1;     }     public void setP1(String p1) {         this.p1 = p1;     }     public String getP2() {         return p2;     }     public void setP2(String p2) {         this.p2 = p2;     }     public String execute(RequestInfo requestinfo) {         System.out.println("进入Action requestid="+requestinfo.getRequestid());         //请求ID         String requestid = requestinfo.getRequestid();         //请求紧急程度         String requestlevel = requestinfo.getRequestlevel();          //当前操作类型 submit:提交/reject:退回         String src = requestinfo.getRequestManager().getSrc();         //流程ID         String workflowid = requestinfo.getWorkflowid();         //表单名称 主表         String tablename = requestinfo.getRequestManager().getBillTableName();         //  tablename 中的id         int billid = requestinfo.getRequestManager().getBillid();//表单数据ID         //获取当前操作用户对象         User usr = requestinfo.getRequestManager().getUser();         //请求标题         String requestname = requestinfo.getRequestManager().getRequestname();         //当前用户提交时的签字意见         String remark = requestinfo.getRequestManager().getRemark();         //表单ID         int formid = requestinfo.getRequestManager().getFormid();         //是否是自定义表单         int isbill = requestinfo.getRequestManager().getIsbill();         //取主表数据         Property[] properties = request.getMainTableInfo().getProperty();         // 获取表单主字段信息         for (int i = 0; i < properties.length; i++) {             // 主字段名称             String name = properties[i].getName();             // 主字段对应的值             String value = Util.null2String(properties[i].getValue());             System.out.println(name + " " + value);         }         //取明细数据         DetailTable[] detailtable = request.getDetailTableInfo().getDetailTable();         if (detailtable.length > 0) {             // 获取所有明细表             for (int i = 0; i < detailtable.length; i++) {                 // 指定明细表                 DetailTable dt = detailtable[i];                 // 当前明细表的所有数据,按行存储                 Row[] s = dt.getRow();                 for (int j = 0; j < s.length; j++) {                     // 指定行                     Row r = s[j];                     // 每行数据再按列存储                     Cell c[] = r.getCell();                     for (int k = 0; k < c.length; k++) {                         // 指定列                         Cell c1 = c[k];                         // 明细字段名称                         String name = c1.getName();                         // 明细字段的值                         String value = c1.getValue();                         System.out.println(name + " " + value);                     }                 }             }         }         //控制流程流转,增加以下两行,流程不会向下流转,表单上显示返回的自定义错误信息         requestinfo.getRequestManager().setMessageid(System.currentTimeMillis() + "");         requestinfo.getRequestManager().setMessagecontent("返回自定义的错误信息");         //必须返回false,否则流程会提交下去 		    FAILURE_AND_CONTINUE;         System.out.println("Action执行完成 传入参数p1="+this.getP1()+"  p2="+this.getP2()); 		//return返回固定返回`SUCCESS`         return SUCCESS ;     } } 

编译好class后开始注册配置Action设置

image-20210916130452425

image-20210916130508262

6、流程表单代码块

流程前端API在线说明文档

https://e-cloudstore.com/doc.html?appId=98cb7a20fae34aa3a7e3a3381dd8764e

7、发布webservice

编写接口和实现类

发布自己的WebService接口,只要实现对应的接口和实现类即可。

以下以一个简单的输入输出为例:

编写接口

/**  * 自定义的WebService接口  */ package weaver.oatest.webservices; public interface TestService {     /**      * 输出接收的参数      * @param param      * @return      */     public String TestMethod(String... param); } 

实现类

package weaver.oatest.webservices;  import org.apache.commons.lang.StringUtils;  import weaver.general.BaseBean;  public class TestServiceImpl extends BaseBean implements TestService  {      public String TestMethod(String... param) {          return "接收到的参数为:"+StringUtils.join(param,",");     } } 

这样接口就编写好了,下一步就到发布接口。

发布接口

修改==./ecology/classbean/META-INF/xfire/services.xml==文件增加要发布的接口,增加下面内容 :
name:为接口名称
namespace:命名空间
serviceClass:接口的报名加类名
implementationClass:接口的实现包名加类名`

<service>     <name>TestService</name>     <namespace>webservices.test.weaver.com.cn</namespace>     <serviceClass>weaver.oatest.webservices.TestService</serviceClass>     <implementationClass>weaver.oatest.webservices.TestServiceImpl</implementationClass> </service> 

接口发布后,访问http://ip/services 可以看到发布的TestService

8、计划任务 CronJob

该接口用来用户在e-cology系统自由定义一些需要定时执行的操作,它是由Quartz这一个开源的作业调度框架来实现;该接口通过配置调度时间和自行开发调度动作来实现需要定时执行的任务。
该接口提供了两种调度方式:

  • CronJob接口,此接口在指定的时间点执行 ,BaseCronJob是系统默认的实现了CronJob的实现类,可以直接继承。

在开发调度动作需要实现e-cology提供的自定义动作接口。

package weaver.interfaces.schedule;  import weaver.conn.RecordSet; import weaver.workflow.request.MailAndMessage; import java.util.ArrayList;  public class SyncRequestTitleJob extends BaseCronJob {  public void execute() {        //实际执行的业务逻辑     }  } 

配置计划任务

在后台集成中心计划任务中添加计划任务类和执行时间,如:每30分钟同步一次请求标题。计划任务标识必须唯一不能重复。

image-20210916144519498

9、自定义短信接口

9.1、短信接口

短信集成需要实现接口

e-cology的短信接口除了提供了写中间表的方式发送短信外,还提供了通过程序实现短信接口的方式发送短信。自定义接口的接口类和属性根据需要进行设置。

自定义接口类必须实现接口weaver.sms.SmsService的方法

public boolean sendSMS(String smsId,String number,String msg)

package weaver.interfaces.sms; import weaver.general.TimeUtil; import weaver.sms.SmsService; public class TestSms implements SmsService {     //smsId 没用     //phoneno  手机号     //msg  短信内容     public boolean sendSMS(String smsId, String phoneno, String msg) {                 //实现相应的短信平台的API进行发送                  doSend(phoneno,msg);         return true;         } } 

自定义接口配置:

image-20210917145023378

9.2、消息接口

https://www.showdoc.com.cn/p/f217b01ce7c26aa9303ab93fe74eccb7

10、restful创建流程接口&鉴权

https://e-cloudstore.com/ec/api/applist/index.html#/

11、组织结构同步

https://e-cloudstore.com/doc.html?appId=c373a4b01fb74d098b62e2b969081d2d

12、免密登录OA

1、适用于第三方系统单点登录方式进入泛微Ecology8和Ecology9系统。
2、单点登录OA系统为令牌方式,即第三方系统请求OA系统传入应用标识即员工登录账号,OA系统返回一个令牌串。
3、第三方系统按照规则拼接令牌串则可以访问OA电脑和手机端的页面地址。

12.1、前提条件

1、两套系统的人员登录账号一致
​2、如果为Ec8系统,请确认kb版本是否为1806以上,kb低于此版本不支持该方案单点登录

12.2、OA系统检查配置

12.2.1、接口发布相关

在ecology\WEB-INF\web.xml最后面配置,如果有该配置,请忽略

<servlet>     <servlet-name>getToken</servlet-name>     <servlet-class>weaver.weaversso.GetToken</servlet-class> </servlet> <servlet-mapping>     <servlet-name>getToken</servlet-name>     <url-pattern>/ssologin/getToken</url-pattern> </servlet-mapping> <servlet>          <servlet-name>CheckToken</servlet-name>           <servlet-class>weaver.weaversso.CheckToken</servlet-class>      </servlet>       <servlet-mapping>          <servlet-name>CheckToken</servlet-name>           <url-pattern>/ssologin/checkToken</url-pattern>      </servlet-mapping> 

在ecology\WEB-INF\web.xml中配置:(需要放在安全补丁包的后面)

<filter>     <filter-name>WeaverLoginFilter</filter-name>     <filter-class>weaver.weaversso.WeaverLoginFilter</filter-class> </filter> <filter-mapping>     <filter-name>WeaverLoginFilter</filter-name>     <url-pattern>*.html</url-pattern>     <url-pattern>*.jsp</url-pattern> </filter-mapping> 

12.2.2、集成的应用配置相关

需要配置ecology\WEB-INF\prop\WeaverLoginClient.properties文件ssss=127.0.0.1

配置说明:
1、左侧配置单点登录OA标识,右侧配置允许单点登录OA的物理IP地址,多个以逗号分隔。

2、若有OA为Nginx集群的环境,需要在WeaverLoginClient.properties配置上nginx服务的ip。

3、如果访问接口时返回ip非法之类的,请检查/log/integration/integration.log日志里的requestip输出,确认是否有配置到。

4、E9新版本kb下,可以直接在统一认证中心配置,不需要在ecology\WEB-INF\prop\WeaverLoginClient.properties中配置集成应用的相关信息。

##12.3、获取token的接口

功能说明获取用户登录token
接口地址http://OA的pc端访问地址/ssologin/getToken
调用方式POST
参数说明
appid应用标识(WeaverLoginClient.properties文件中左侧标识)
loginidOA登录账号
返回值说明用户登录令牌
令牌生成规则AES(loginid+“|”+ts+“|”+appid)

生成的令牌要保存到数据库中securityfilter里需要配置第三方访问oa的服务器白名单,方能确保该方案正常使用
请检查ecology\WEB-INF\weaver_security_config.xml文件是否有is-login-check配置,若没有,则添加;若有,请调整为false

<is-login-check>false</is-login-check> 

Token参数只有一次有效,若已被使用,再次使用时,会直接跳转到OA登录页面。

12.3.1、postman请求示例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uxTlRjk7-1679280813349)(E9开发培训.assets/2bdb329b-4aef-4c6b-a00e-bf9e1608d9e0-164969218392812.png)]

12.4、单点登录跳转地址拼接

###12.4.1、pc下的地址拼接

携带拼接ssoToken时,注意拼接位置,E9的很多页面是单页面,不要拼在#路由地址后面,如:

http://192.168.95.101:8088/wui/index.html#/main?ssoToken=XXX

这是错的,需要这样拼:

http://192.168.95.101:8088/wui/index.html?ssoToken=XXX#/main

测试例子:
OA中人员cs001有requestid=5074的流程,对于PC端,流程路径配置:
将上面获取到token值拼接到地址中:
http://192.168.95.101:8088/spa/workflow/index_form.jsp?ssoToken=B4E721CCC7F210D5A44B3F5AF2046315BC314D205967E6911FCA4361BBA5851A#/main/workflow/req?requestid=5074
直接访问,可直接单点登录进入流程页面:

12.4.2、EM7的地址拼接

重新申请token值,进行拼接:
http://192.168.95.101:8088/spa/workflow/static4mobileform/index.html?ssoToken=9B3E7C2D58FED69547850D7002549C80541ED138EE450C17C75B25A9996FC846#/req?requestid=5074

移动端访问,也可直接单点登录打开流程页面:

13、注意事项

13.1、System.out

正式代码中严禁使用 System.out 进行日志的输出,原因是这个语句的性能非常低,一旦调用的非常频繁, 就会成为性能瓶颈。

13.2、BaseBean

import weaver.general.BaseBean; BaseBean baseBean = new BaseBean(); //日志打印 baseBean.writeLog("xxx"); //读取.properties配置文件的值 //.properties配置文件路径 /ecology/WEB-INF/prop目录下 baseBean.getPropValue("配置文件名(不含.properties)","键名"); 

13.3、数据库操作

13.3.1、RecordSet和RecordSetTrans

目前RecordSet和RecordSetTrans提供的execute和executeSql方法采用SQL拼接方法来执行SQL,这样会产生SQL注入安全威胁。

请大家以后写SQL语句时,使用以下两个方法来替代原来的拼接SQL的方式,以避免SQL渗透威胁。

RecordSet不要在循环体里new。

不做多方法传递。

现在提供以下两个方法来替代execute和executeSql。

方法名参数说明(示例)
executeQuery(String sql,Object… params)sql:待执行的SQL语句params:用于替换sql中的?的参数,可以是0个或多个该方法用于查询,RecordSet中执行完毕后会返回true|false,
RecordSetTrans执行失败会抛出异常。同时会保留结果集供使用。
遍历结果集的方法和executeSql执行后遍历一样。
示例:
rs.executeQuery(“select id,loginid from hrmresource where lastname like ?”,”%王%”)rs.executeQuery(“select id,loginid from hrmresource where lastname like ? and seclevel >= ?”,”%王%”,30)
executeUpdate(String sql,Object… params)sql:待执行的SQL语句params:用于替换sql中的?的参数,可以是0个或多个该方法用于更新记录
RecordSet中执行完毕后会返回true|false,
RecordSetTrans执行失败会抛出异常。
示例:
rs.executeUpdate(“insert into hrmresource(loginid,lastname) values(?,?)”,”wangxin”,”王鑫”)
rs.executeUpdate(“delete from hrmresource where id=?”,id)

13.3.2、数据库使用事务

使用 weaver.conn.RecordSetTrans 可以对数据库进行事务操作

参考代码

RecordSetTrans rst = new RecordSetTrans(); // 开启事务 rst.setAutoCommit(false); String sql = "update hrmresource lastname=? where id=?"; try { 	int a = 1/0; 	rst.executeUpdate(sql, "猪八戒", 2); 	// 提交事务 	rst.commit(); } catch (Exception e) { 	e.printStackTrace(); 	// 事务回滚 	rst.rollback(); } 

13.3、获取系统配置的访问地址

image-20220325171431255

 SystemComInfo system = new SystemComInfo(); //OA访问地址 String intranet = system.getOaaddress();  

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!