文章目录
1、EC9系统说明
如需本地版本,请移步下载资源
https://download.csdn.net/download/u010048119/86444408?spm=1001.2014.3001.5503
1.1、系统核心框架
- 后端增加了分层、AOP、IOC、interceptor的支持
- 新架构要求service和Command层必须面向接口编程, 同时通过IOC和命令委托方式进行各层的解耦
- 新架构还提供全局interceptor和局部interceptor、SERVICE-AOP、COMMAND-AOP的支持,可以进行比如日志记录、声明性事务、安全性,和缓存等等功能的实现和无侵入二开
1.2、系统目录结构
WEAVER
ecology
classbean
存放编译后的CLASS文件
WEB-INF
lib
系统依赖Jar文件目录
prop
系统配置文件存放
2、环境搭建
2.1、Ecology测试环境搭建
步骤1:从服务器上拷贝WEAVER/ecology代码
从服务器拷贝ecology
相关代码到本地,目录服务器上文件如下图,需拷贝ecology
、Resin/Resin4
,如果本机已安装JDK
则可以不需拷贝JDK
步骤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、后端代码目录结构
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
中直接操作其他系统的数据。
后台设置
路径:集成中心
-功能集成
– 数据源设置
程序调用
//引入相关的类
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、流程流转过程理解
这是一个简单的流程图
对应实际的流程流转过程
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
设置
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分钟同步一次请求标题。计划任务标识必须唯一不能重复。
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;
}
}
自定义接口配置:
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文件中左侧标识) |
loginid | OA登录账号 |
返回值说明 | 用户登录令牌 |
---|---|
令牌生成规则 | 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、获取系统配置的访问地址
SystemComInfo system = new SystemComInfo();
//OA访问地址
String intranet = system.getOaaddress();