diff --git a/Ecology9开发手册.md b/Ecology9开发手册.md new file mode 100644 index 0000000..d28716e --- /dev/null +++ b/Ecology9开发手册.md @@ -0,0 +1,1210 @@ +# Ecology9 开发手册 + +> 在线地址: [http://wcode.store/#/./weaver/Ecology9%E5%BC%80%E5%8F%91%E6%89%8B%E5%86%8C](http://wcode.store/#/./weaver/Ecology9开发手册) + +## 1. 环境搭建 + +### 1.1 Ecology安装和启动 + +- 准备 `ecology` | `resin` | `jdk1.8[可直接使用已安装的]` +- 修改resin配置 `resin/config/resin.conf` + +```xml +// 修改jdk路径:相对路径或者绝对路径 + + +// 修改ecology路径 + +``` + +- 修改resin启动配置 `resin/resinstart.bat` + +其中`java_home` 为`jdk`的路径,可以是相对路径也可以是绝对路径 + +```properties +set java_home=C:\Program Files\Java\jdk1.8.0_151 +``` + +- 启动`resin` 点击`resinstart.bat` +- 初始验证码文件路径 `ecology/WEB-INF/code.key` + +### 1.2 主要目录介绍 + +- `ecology/classbean`:存放编译后的class文件 +- `ecology/log`:系统中日志存放目录 +- `ecology/WEB-INF/prop`:`web`配置文件目录 +- `ecology/WEB-INF/lib`:系统`jar`包路径 + +### 1.3 数据库配置 + +> 如果数据库与Ecology不在同一台服务器上,则可以修改数据库配置文件中的数据库配置。 +> +> 数据库配置文件路径:`ecology/WEB-INF/prop/weaver.properties` + +```properties +# sqlServer +DriverClasses = com.microsoft.sqlserver.jdbc.SQLServerDriver +ecology.url = jdbc:sqlserver://host:port;DatabaseName=dbname +ecology.user = username +ecology.password = password +``` + +```properties +# oracle +DriverClasses = oracle.jdbc.OracleDriver +ecology.url = jdbc:oracle:thin:@host:port:ecology +ecology.user = username +cology.password = password +``` + +--- + +## 2. E9常见表结构 + +### 2.1 流程相关数据存储表 + +| 数据库表名 | 中文说明 | 备注 | +| ------------------------ | ---------------- | ------------------------------ | +| workflow_base | 流程基本信息 | isbill=1 | +| workflow_bill | 流程表单信息 | id > 0固定表名 id < 0 动态生成 | +| workflow_billfield | 表单字段信息 | | +| workflow_billdetailtable | 表单明细表 | | +| workflow_nodebase | 节点信息 | | +| workflow_flownode | 流程节点信息 | | +| workflow_nodelink | 流程出口信息 | | +| workflow_nodegroup | 节点操作人信息 | | +| workflow_groupdetail | 节点操作人详情 | | +| workflow_requestbase | 请求基本信息 | | +| workflow_currentoperator | 请求节点操作人 | | +| workflow_requestlog | 请求签字意见 | | +| workflow_nownode | 请求当前节点 | | +| workflow_browserurl | 系统浏览按钮信息 | | +| workflow_selectitem | 下拉框信息 | | + +### 2.2 人力资源相关数据存储 + +| 表名 | 说明 | 备注 | +| -------------------- | ---------------------------- | ---- | +| HrmResource | 人力资源基本信息表 | - | +| HrmResource_online | 人员在线信息表 | - | +| HrmResourceManager | 系统管理员信息表 | - | +| HrmDepartment | 人力资源部门表 | - | +| HrmDepartmentDefined | 人力资源部门自定义字段信息表 | - | +| HrmSubCompany | 人力资源分部表 | - | +| hrmroles | 角色信息表 | - | +| hrmrolemembers | 角色人员 | - | +| hrmjobtitles | 岗位信息表 | - | + +## 3. 前端开发 + +> `ecology9`前端上采用`react`+`antd`+`mobx`+`react-router`等框架实现的单页面应用 + +### 3.1 流程开发 + +> 流程表单前端接口:[E9流程表单前端接口API](https://e-cloudstore.com/ecode/doc?appId=98cb7a20fae34aa3a7e3a3381dd8764e&tdsourcetag=s_pctim_aiomsg#E9%E6%B5%81%E7%A8%8B%E8%A1%A8%E5%8D%95%E5%89%8D%E7%AB%AF%E6%8E%A5%E5%8F%A3API](https://e-cloudstore.com/ecode/doc?appId=98cb7a20fae34aa3a7e3a3381dd8764e&tdsourcetag=s_pctim_aiomsg#E9流程表单前端接口API)) + +- 所有接口统一封装在全局对象`window.WfForm`中 +- 表单字段相关操作,不推荐使用jQuery,禁止原生JS直接操作DOM结构! +- 在开发过程中,推荐都使用API接口操作,由产品统一运维;同时使用API才能完整的兼容移动终端 + +### 3.2 建模开发 + +#### 3.2.1 布局代码块 + +> 建模布局代码块使用上与流程表单的代码块基本一致,区别在于接口的SDK不同,建模表单的所有接口统一封装在全局对象 `window.ModeForm`中。 +> +> [建模前端接口API](https://e-cloudstore.com/ecode/doc.html?appId=e783a1d75a784d9b97fbd40fdf569f7d&tdsourcetag=s_pctim_aiomsg) + +#### 3.2.2 自定义按钮 + +> 后端应用中心 -> 建模引擎 -> 查询 +> +> 任选一个查询页面 -> 自定义按钮 -> 右键 -> 新建 +> +> ![1570360554483](asset/1570360554483.png) + +- 方法体中存在多行代码时,每个语句必须以`;`结尾;否则会报错! + +- `params`的值等于 ` ‘field1+field2+field3’` 这个值是一个字符串 + +- `id`指的是数据`ID` + +> 前端显示 + +![1570109435919](asset/1570109435919.png) + +- **配置`ecode`使用** + +> 新建前置文件 `index.js`并将方法挂到全局对象 `window.g` 下 + +![1570109735133](asset/1570109735133.png) + +> 新建自定义按钮 + +![1570109991787](asset/1570109991787.png) + +![1570110063242](asset/1570110063242.png) + +#### 3.2.3 页面扩展 + +> 后端应用中心 -> 建模引擎 -> 模块 +> +> 任选一个模块 -> 页面扩展 -> 右键 -> 新建 +> +> ![1570110626080](asset/1570110626080.png) + +- 扩展用途:卡片页面、查询列表(批量操作)、卡片页面和查询列表 + - 卡片页面:可以设置页面扩展显示在卡片信息页面,可以选择在新建页面、编辑页面、查看页面显示页面扩展。 + - 查询列表(批量操作):设置在查询列表时,则会在引用该模块的查询列表的批量操作中显示页面扩展项,在批量操作中勾选后会在前台列表中显示对应的页面扩展项。 + - 卡片页面和查询列表:可以设置页面扩展项既显示在对应的卡片页面又显示在查询列表(批量操作)中。 +- `javascript:test()`: 该方法可以在 `建模引擎 -> 查询 -> 该模块的查询列表 -> 编辑代码块` 中定义 + +![1570110945435](asset/1570110945435.png) + +![1570110988895](asset/1570110988895.png) + +> 前端按钮测试如下 + +![1570110886190](asset/1570110886190.png) + +- 页面扩展同样可以配置 `ecode`使用,将**链接目标地址**改成: `javascript: window.g.test()`即可,建议这样做,方便后续代码维护。 + +### 3.3 Ecode在线编辑 + +> ecode官方文档:https://e-cloudstore.com/ecode/doc +> +> E9 技术站地址: https://e-cloudstore.com/e9/index2.html?tdsourcetag=s_pctim_aiomsg +> +> 使用已经封装好的组件进行页面开发或者页面改写会更加便捷迅速。 + +### 3.4 动态注入代码 + +> 通过前置加载动态注册代码,完全脱离代码块的实现方式。**非官方的方案,使用中有任何问题概不负责!** +> +> 官方用法请参考:[全局流程代码块整合](https://e-cloudstore.com/ecode/doc#4、全局流程代码块整合) + +注意:**Ecode部分版本不能使用,更新至最新版本即可** + +- 打开ecode页面,将 [config.js](https://github.com/Y-Aron/wcode/blob/master/WEB-INF/config.js) 中的代码复制到 `系统配置 -> config.js` 中 + +- 使用 `Wcode.runScript` 动态注入代码,参数说明如下 + +| 参数 | 类型 | 可选 | 默认 | 说明 | +| ------- | --------------- | ---- | --------------- | ------------------------------------------------------------ | +| id | string | 必填 | ‘’ | 流程代码块,则 id 指的是 流程的workflowid;建模代码块,则 id 指的是 模块的 modeId;查询列表代码块,则 id 指的是查询列表的id,即 customid | +| mode | string | 必填 | '' | Wcode.WF_TYPE: 流程代码块;MODE_TYPE:建模代码块;LIST_TYPE:查询列表代码块 | +| appId | function | 必填 | '' | ecode 中应用的 id, 可使用 `${appid}` 占位符替换 | +| nodeId | integer\|string | 选填 | 0 | 流程使用,指定节点时才加载代码,不指定则只在创建节点时加载 | +| type | integer\|string | 选填 | 0 | 建模使用,指定布局时才加载代码,不指定则只在新建布局时加载 | +| menuIds | string | 选填 | ‘ALL_MODE_LIST’ | 列表使用,指定查询列表在哪个菜单下时加载,不指定则默认所有菜单下存在该列表都加载。 | +| noCss | boolean | 选填 | true | 是否禁止单独加载css,通常为了减少css数量,css默认前置加载 | +| cb | function | 选填 | function() {} | 代码块成功加载完毕的回调方法 | + +> 在 Ecode 中任意创建一个应用,应用下新建一个 `register.js` 的前置文件,根据不同场景加入对应的代码 + +- 流程节点使用 + +```javascript +Wcode.runScript({ + mode: Wcode.WF_TYPE, + id: '4', + appId: '${appId}' +}) +``` + +- 建模布局使用 + +```javascript +Wcode.runScript({ + mode: Wcode.MODE_TYPE, + id: '1', + appId: '${appId}', + type: Wcode.SHOW_TEMPLATE, +}) +``` + +- 查询列表使用 + +```javascript +Wcode.runScript({ + mode: Wcode.LIST_TYPE, + id: '1', + appId: '${appId}' +}) +``` + +--- + +## 4. 后端开发 + +> 代码案例:[E9Demo](https://github.com/Y-Aron/E9Demo/tree/master) +> +> 工具类 wcode 代码: https://github.com/Y-Aron/wcode + +### 4.1 `Java`项目环境搭建 + +#### 4.1.1 `web.xml` 部分配置 + +> `API` 接口的`xml`配置 + +```xml + + + restservlet + com.sun.jersey.spi.container.servlet.ServletContainer + + com.sun.jersey.config.property.packages + + com.cloudstore;com.api + + 1 + + + restservlet + /api/* + + /port/* + +``` + +注意: /api/* 的请求必须在用户登录时才能进行访问。否则会被过滤器过滤。其 web.xml 配置 SessionFilter 实 +现了过滤拦截。当然也可以自定义接口前缀,如上配置了 /port/* + +```xml + + SessionFilter + com.cloudstore.dev.api.service.SessionFilter + + + SessionFilter + + /api/* + + + SessionFilter + /page/interfaces/*.jsp + +``` + +#### 4.1.2 项目环境搭建 + +> 传统 `JavaWeb` 项目搭建 + +- 创建`Java`项目 +- 添加所需依赖 + +**File -> Project Structure -> Project Settings -> Libraries** + +需要添加的`ecology`的依赖路径有: `ecology/WEB-INF/lib`; `resin/lib`; `ecology/classbean`; + +其中`classbean`是必须要引入的, 其他两个按需引入 + +- 编译`Java`文件将编译后的`class`文件放入`ecology/classbean/`目录下即可 + +**注意:** `ecology/classbean` 最好备份, 因为`IDEA`在编译的时候可能会清除掉已有的`classbean` + +> 使用 `Maven` 构建项目 + +相对于传统的 `JavaWeb` 项目而言,使用 maven 可以做到快速搭建项目,项目结构层次分明,并且 jar 间的依赖关系可以得到直观的体现。当然需要二开人员对 maven 有一定的了解,并且熟悉 ec 系统所使用的依赖,防止版本冲突。 + +后端项目结构以及开发案例详见手册: [E9后端开发指南](https://e-cloudstore.com/e9/file/E9BackendDdevelopmentGuide.pdf) + +#### 4.1.3 Java项目结构 + +> 一般情况下遵循以下项目结构进行后端开发 + +其中,`com.api.wcode`和`com.engine.wcode`中的 `wcode`为自定义包名,不与已有的包重复即可。 + +```xml-dtd +com.api.wcode + |-- web 接口定义层 +com.engine.wcode + |-- web 接口实现层 + |-- service 服务定义层 + |-- impl 服务实现层 + |-- domain 数据层 + |-- cmd 原子操作层定义 + |-- dao Dao层 + |-- mapper mapper接口定义层 +``` + +### 4.2 后端API路径规范 + +| 模块 | 文件路径(含下级) | 接口访问地址 | +| -------- | ------------------- | ------------------ | +| 流程 | com.api.workflow | /api/workflow/… | +| 门户 | com.api.portal | /api/portal/… | +| 文档 | com.api.doc | /api/doc/… | +| 建模 | com.api.formmode | /api/formmode/… | +| 移动建模 | com.api.mobilemode | /api/mobilemode/… | +| 会议 | com.api.meeting | /api/meeting/… | +| 人力 | com.api.hrm | /api/hrm/… | +| 财务 | com.api.fna | /api/fna/… | +| 项目 | com.api.prj | /api/prj/… | +| 公文 | com.api.odoc | /api/odoc/… | +| 集成 | com.api.integration | /api/integration/… | +| 微博 | com.api.blog | /api/blog/… | + +### 4.3 自定义`Java`接口 + +#### 4.3.1 流程节点前后附加操作 + +> 在节点前后附加操作中可设置接口动作,完成流程自定义附加操作 +> +> 接口动作标识不能重复;接口动作类文件必须是类全名,该类必须实现接 `weaver.interfaces.workflow.action` 方法 `public String execute(RequestInfo request)` + +参考代码如下 + +```java +package com.engine.wcode.action; + +import com.weaver.general.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import weaver.hrm.User; +import weaver.interfaces.workflow.action.Action; +import weaver.soa.workflow.request.*; + +public class TestAction implements Action { + + private String customParam; //自定义参数 + private final Logger logger = LoggerFactory.getLogger(TestAction.class); + + @Override + public String execute(RequestInfo requestInfo) { + logger.debug("进入action requestid = {}", requestInfo.getRequestid()); + showCurrentForm(requestInfo); + + showFormProperty(requestInfo); + + showDetailsTables(requestInfo); + + logger.debug("Action 执行完成,传入自定义参数:{}", this.getCustomParam()); +// requestInfo.getRequestManager().setMessagecontent("返回自定义的错误消息"); +// requestInfo.getRequestManager().setMessageid("自定义消息ID"); +// return FAILURE_AND_CONTINUE; // 注释的三句话一起使用才有效果! + return SUCCESS; + } + + private void showCurrentForm(RequestInfo requestInfo) { + String requestid = requestInfo.getRequestid(); // 请求ID + String requestLevel = requestInfo.getRequestlevel(); // 请求紧急程度 + // 当前操作类型 submit:提交/reject:退回 + String src = requestInfo.getRequestManager().getSrc(); + // 流程ID + String workFlowId = requestInfo.getWorkflowid(); + // 表单名称 + String tableName = requestInfo.getRequestManager().getBillTableName(); + // 表单数据ID + int bill_id = requestInfo.getRequestManager().getBillid(); + // 获取当前操作用户对象 + User user = requestInfo.getRequestManager().getUser(); + // 请求标题 + String requestName = requestInfo.getRequestManager().getRequestname(); + // 当前用户提交时的签字意见 + String remark = requestInfo.getRequestManager().getRemark(); + // 表单ID + int form_id = requestInfo.getRequestManager().getFormid(); + // 是否是自定义表单 + int isbill = requestInfo.getRequestManager().getIsbill(); + + logger.debug("requestid: {}", requestid); + logger.debug("requestLevel: {}", requestLevel); + logger.debug("src: {}", src); + logger.debug("workFlowId: {}", workFlowId); + logger.debug("tableName: {}", tableName); + logger.debug("bill_id: {}", bill_id); + logger.debug("user: {}", user); + logger.debug("requestName: {}", requestName); + logger.debug("remark: {}", remark); + logger.debug("form_id: {}", form_id); + logger.debug("isbill: {}", isbill); + } + /** + * 获取主表数据 + */ + private void showFormProperty(RequestInfo requestInfo) { + logger.debug("获取主表数据 ..."); + // 获取表单主字段值 + Property[] properties = requestInfo.getMainTableInfo().getProperty(); + for (Property property : properties) { + // 主字段名称 + String name = property.getName(); + // 主字段对应的值 + String value = Util.null2String(property.getValue()); + logger.debug("name: {}, value: {}", name, value); + } + } + + /** + * 取明细数据 + */ + private void showDetailsTables(RequestInfo requestInfo) { + logger.debug("获取所有明细表数据 ..."); + // 获取所有明细表 + DetailTable[] detailTables = requestInfo.getDetailTableInfo().getDetailTable(); + if (detailTables.length > 0) { + for (DetailTable table: detailTables) { + // 当前明细表的所有数据,按行存储 + Row[] rows = table.getRow(); + for (Row row: rows) { + // 每行数据再按列存储 + Cell[] cells = row.getCell(); + for (Cell cell: cells) { + // 明细字段名称 + String name = cell.getName(); + // 明细字段的值 + String value = cell.getValue(); + logger.debug("name: {}, value: {}", name, value); + } + } + } + } + } + + public String getCustomParam() { + return customParam; + } + + public void setCustomParam(String customParam) { + this.customParam = customParam; + } +} +``` + +> 配置:后端应用中心 -> 流程引擎 -> 路径管理 -> 路径设置 +> +> 任选一个流程 -> 流程设置 -> 节点信息 +> +> 任选一个节点 -> 节点前 / 节点后附加操作 +> +> ![1570114991641](asset/1570114991641.png) +> +> ![1570158010000](asset/1570158010000.png) + +#### 4.3.2 页面扩展接口 + +> 页面扩展 -> 接口动作 -> 自定义接口动作 +> +> 执行页面扩展的后续操作,通过配置自定义 `Java`接口动作类实现。 +> +> 接口动作类文件必须是类全名。该类必须继承 `weaver.formmode.customjavacode.AbstractModeExpandJavaCode` 方法 `public void doModeExpand(Map param)` + +参考代码 + +```java +package com.engine.wcode.formmode.extend; + +import weaver.conn.RecordSet; +import weaver.general.Util; +import weaver.hrm.User; +import weaver.soa.workflow.request.RequestInfo; +import weaver.formmode.customjavacode.AbstractModeExpandJavaCode; + +import java.util.Map; + +public class ModeExpandTemplate extends AbstractModeExpandJavaCode { + + @Override + public void doModeExpand(Map param) throws Exception { + // 当前用户 + User user = (User) param.get("user"); + int billid = -1; // 数据id + int modeid = -1; // 模块id + RequestInfo requestInfo = (RequestInfo) param.get("RequestInfo"); + if (requestInfo != null) { + billid = Util.getIntValue(requestInfo.getRequestid()); + modeid = Util.getIntValue(requestInfo.getWorkflowid()); + if (billid > 0 && modeid > 0) { + RecordSet rs = new RecordSet(); + //------请在下面编写业务逻辑代码------ + } + } + } +} +``` + +> 配置:后端应用中心 -> 建模引擎 -> 模块 +> +> 任选一个模块 -> 页面扩展 -> 任选一个扩展名称 -> 接口动作 -> 点击 `+` 号 -> 自定义接口动作 +> +> ![1570158149458](asset/1570158149458.png) + +#### 4.3.3 计划任务 + +> 通过配置自定义 `Java`接口的实现类,定时执行相应的代码 + +- 按照设定的时间定时执行任务,计划任务标识不能重复 +- 计划任务类必须是类的全名,该类必须继承 `weaver.interfaces.schedule.BaseCronJob`类,重写方法`public void execute() {}` +- 时间格式按`Cron`表达式的定义 + +**参考代码** + +```java +package com.engine.wcode.cron; + +import weaver.interfaces.schedule.BaseCronJob; + +public class CronTemplate extends BaseCronJob { + + @Override + public void execute() { + //------请在下面编写业务逻辑代码------ + } +} +``` + +> 配置:后端应用中心 -> 集成中心 -> 计划任务 -> 任务列表 -> 新建 +> +> ![1570158310329](asset/1570158310329.png) + +> **通过计划任务列表的每个计划任务的自定义按钮,可以对每个任务进行状态操作,具体使用如下所示** +> +> ![1570156694722](asset/1570156694722.png) + +状态详解: + +1. 启用: 计划任务将根据Cron表达式执行; + +2. 禁用: 计划任务将不再执行,重启服务也不会再次执行; + +3. 暂停: 针对计划任务进行停止,重启服务将恢复正常状态; + +4. 恢复: 针对暂停状态的计划任务进行恢复,恢复后计划任务将继续执行; + +5. 执行: 单次执行计划任务,不影响Cron表达式周期执行; + +6. 测试: 检查填写的计划任务类是否符合规范(继承weaver.interfaces.schedule.BaseCronJob类,重写方法public void execute() {}) + +#### 4.3.4 自定义按钮接口 + +> 通过配置自定义`Java`类,判断自定义按钮在查询列表中是否显示 + +**参考代码** + +```java +package com.engine.wcode.formmode.button; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import weaver.formmode.interfaces.PopedomCommonAction; + +public class CustomBtnShowTemplate implements PopedomCommonAction { + + private Logger logger = LoggerFactory.getLogger(CustomBtnShowTemplate.class); + + /** + * 得到是否显示操作项 + * @param modeid 模块id + * @param customid 查询列表id + * @param uid 当前用户id + * @param billid 表单数据id + * @param buttonname 按钮名称 + * @retrun "true"或者"false"true显示/false不显示 + */ + @Override + public String getIsDisplayOperation(String modeid, String customid,String uid, String billid, String buttonname) { + logger.debug("modeId: {}", modeid); + logger.debug("customId: {}", customid); + logger.debug("uid: {}", uid); + logger.debug("billId: {}", billid); + logger.debug("buttonname: {}", buttonname); + return "false"; + } +} +``` + +> 配置:后端应用中心 -> 建模引擎 -> 查询 +> +> 任选一个查询列表 -> 自定义按钮 -> 右键 -> 新建 +> +> ![1570158498273](asset/1570158498273.png) + +**前端查询列表中,由于接口中返回false,则 ==受控按钮== 不显示** + +![1570158575523](asset/1570158575523.png) + +### 4.4 数据库操作 + +#### 4.4.1 CURD + +> 使用 `weaver.conn.RecordSet`可以对数据库进行 `CURD` 等数据库操作 + +**参考代码:** + +```java +RecordSet rs = new RecordSet(); +String sql = "select loginid, lastname from hrmresource where id=?"; +// 防止sql注入, objects 为动态参数 +rs.executeQuery(sql, 2); +if (rs.next()) { + String loginid = rs.getString("loginid"); + String lastname = rs.getString("lastname"); +} +String updateSql = "update hrmresource lastname=? where id=?"; +// 返回是否更新成功 +boolean bool = rs.executeUpdate(sql, "孙悟空", 2); +``` + +#### 4.4.2 使用事务 + +> 使用`weaver.conn.RecordSetTrans`可以对数据库进行事务操作 + +**参考代码** + +```java +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(); +} +``` + +#### 4.4.3 Mybatis的使用 + +> 目前E9没有成熟的使用Mybatis的方案,以下是通过自己的研究给出一个不成熟的方案,有`Bug`概不负责! +> +> 支持多数据源,数据源配置如下: +> +> 后端应用中心 -> 集成中心-> 数据源设置 -> 新建 +> +> ![1570191781927](asset/1570191781927.png) + +> **`xml` ⽅式开发** + +**创建 `mapper` 接⼝** + +```java +package com.engine.wcode.mapper; + +import java.util.List; +import java.util.Map; + +public interface TestMapper { + List> selectAll(); +} +``` + +在 `../ecology/WEB-INF/config/mapper/ `路径下创建 `test.xml` + +```xml + + + + +``` + +> **注解⽅式开发** +> +> 与`xml`⽅式相⽐,使⽤注解开发的⽅便之处在于不⽤写`mapper.xml`⽂件 + +**创建 `mapper` 接⼝** + +```java +package com.engine.wcode.mapper; + +import org.apache.ibatis.annotations.Select; + +import java.util.List; +import java.util.Map; + +public interface HrmMapper { + @Select("select loginid, password, lastname from hrmresource") + List> selectHrm(); +} +``` + +> 使用 `Mybatis` 操作数据库 + +- 获取 `Mapper` + +```java +package com.wcode.db; + +import org.apache.ibatis.session.Configuration; +import org.apache.ibatis.session.ExecutorType; +import org.apache.ibatis.session.LocalCacheScope; +import org.apache.ibatis.session.SqlSession; +import weaver.conn.ConnectionPool; +import weaver.conn.WeaverConnection; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static weaver.conn.mybatis.MyBatisFactory.sqlSessionFactory; + +/** +* ⽅法参数不接受 null或 "" +* @author Y-Aron +* @create 2019/5/8 +*/ +public class MapperUtil { + + private static final Map cacheMapper = new ConcurrentHashMap<>(1); + + private static final Map cacheSqlSession = new ConcurrentHashMap<>(1); + + public static T getMapper(Class clazz) { + return MapperUtil.getMapper(clazz, false); + } + + public static T getMapper(Class clazz, boolean enableCache) { + return MapperUtil.getMapper(clazz, null, ExecutorType.SIMPLE, enableCache); + } + + public static T getMapper(Class clazz, String dataSource) { + return MapperUtil.getMapper(clazz, dataSource, false); + } + + public static T getMapper(Class clazz, String dataSource, boolean enableCache) { + return MapperUtil.getMapper(clazz, dataSource, ExecutorType.SIMPLE, enableCache); + } + + public static T getMapper(Class clazz, String dataSource, ExecutorType executorType, boolean enableCache) { + String threadName = Thread.currentThread().getName(); + SqlSession sqlSession = cacheSqlSession.get(threadName); + if (sqlSession == null) { + ConnectionPool pool = ConnectionPool.getInstance(); + WeaverConnection connection = pool.getConnection(dataSource); + Configuration config = sqlSessionFactory.getConfiguration(); + if (executorType == null) { + executorType = config.getDefaultExecutorType(); + } + if (enableCache) { + config.setLocalCacheScope(LocalCacheScope.STATEMENT); + } + sqlSession = sqlSessionFactory.openSession(executorType, connection); + } + cacheSqlSession.put(threadName, sqlSession); + return MapperUtil.getMapper(clazz, sqlSession); + } + + public static T getMapper(Class clazz, SqlSession sqlSession) { + if (cacheMapper.containsKey(clazz)) { + //noinspection unchecked + return (T) cacheMapper.get(clazz); + } + Configuration config = sqlSession.getConfiguration(); + if (!config.hasMapper(clazz)) { + config.addMapper(clazz); + } + T mapper = sqlSession.getMapper(clazz); + cacheMapper.put(clazz, mapper); + return mapper; + } + + private static SqlSession getCurrentSqlSession() { + if (cacheSqlSession.size() == 0) return null; + return cacheSqlSession.get(Thread.currentThread().getName()); + } +} +``` + +- 数据库操作 + +```java +HrmMapper mapper = MapperUtil.getMapper(HrmMapper.class); +mapper.selectHrm(); +``` + +### 4.5 缓存SDK + +> 缓存基类:`Util_DataCache` + +| 方法名称 | 方法作用 | +| -------------------------------------------------------- | --------------------------------------------------------- | +| getObjVal(String name) | 从所有缓存获取 缓存数据 (主要函数) | +| setObjVal(String name, Object value) | 设置所有缓存数据 (主要函数) | +| setObjVal(String name, Object value,int seconds) | 设置所有缓存数据 支持 超时自动消失 (主要函数) | +| containsKey(String name) | 判断该键名的所有缓存是否存在 | +| clearVal(String name) | 清除该键名的所有缓存 | +| setObjValWithEh(String name,Object value) | 设置本地缓存 ( 特定情况下使用) | +| getObjValWithEh(String name) | 获取本地缓存(特定情况下使用) | +| setObjValWithRedis(String name,Object value) | 设置Redis缓存 需要自己释放数据( 特定情况下使用) | +| setObjValWithRedis(String name,Object value,int seconds) | 单独设置Redis缓存 超时时间(s)后释放数据( 特定情况下使用) | +| getObjValWithRedis(String name) | 单独获取Redis缓存( 特定情况下使用) | +| containsKeylWithEh(String name) | 判断本地缓存是否存在该键名( 特定情况下使用) | +| clearValWithEh(String name) | 清除本地缓存( 特定情况下使用) | +| containsKeyWithRedis(String name) | 判断Redis上是否存在该键名( 特定情况下使用) | +| clearValWithRedis(String name) | 清除Redis缓存 | + +> 检查页面 + +`chechRedis.jsp` 检查`Redis`环境的状态 + +`getRedis.jsp` 检查`DataKey`的数据 + +注意数据变更后必须再次执行`setObjVal`把数据推送到`Redis` + +```java +import com.cloudstore.dev.api.util.Util_DataCache; +public Map refreshDataFormDB() { + Map map = new HashMap(); + Map mapdb = getSystemIfo("y"); + map.putAll(mapdb); + if(mapdb.size()>0) { + Util_DataCache.setObjVal(em_url, mapdb.get(em_url)); + Util_DataCache.setObjVal(em_corpid, mapdb.get(em_corpid)); + Util_DataCache.setObjVal(accesstoken,mapdb.get(accesstoken)); + Util_DataCache.setObjVal(ec_id,mapdb.get(ec_id)); + Util_DataCache.setObjVal(ec_url, mapdb.get(ec_url)); + Util_DataCache.setObjVal(ec_name, mapdb.get(ec_name)); + Util_DataCache.setObjVal(rsa_pub, mapdb.get(rsa_pub)); + Util_DataCache.setObjVal(ec_version, mapdb.get(ec_version)); + Util_DataCache.setObjVal(ec_iscluster, mapdb.get(ec_iscluster)); + Util_DataCache.setObjVal(em_url, mapdb.get(em_url)); + Util_DataCache.setObjVal(em_url_open, mapdb.get(em_url_open)); + } + return map; +} +``` + +### 4.6 Rest API 接口 + +##### 4.6.1 流程表单数据接口 + +> https://www.evernote.com/l/AuMO8ps7HVpMlYkjCMpRC9xyc1VYIcbo1I0/ + +##### 4.6.2 流程待办列表接口 + +> https://www.evernote.com/l/AuM0l0TdGS9OvZuHd1eztup5KNwIgFokDTU/ + +##### 4.6.3 流程列表数据接口 + +> https://www.evernote.com/l/AuP8WpYtOmhHkYgnhs7aOKy_AL9kMACGWm4/ + +## 5. 对接异构系统 + +### 5.1 接口白名单配置 + +##### 5.1.1 `web.xml` 配置 + +> 在`web.xml`中配置(兼容以前的格式使用`weaver_session_filter.properties`后可以不添加参数配置) +> +> `SessionCloudFilter`过滤器修改一下`unchecksessionurl`路径主要功能超时自动跳转首页 + +- `checkurl` 头部验证路径 适用于 EM + +- `uncheckurl` 头部验证放行路径 适用于 EM + +- `unchecksessionurl`路径为不检查放行的路径(白名单) + +```xml + + SessionCloudFilter + com.cloudstore.dev.api.service.SessionFilte + + + checkurl + /api/hrm/emmanager; + + + + uncheckurl + /api/ec/dev/app/getCheckSystemInfo;/api/ec/dev/app/emjoin; + + + unchecksessionurl + + + +// ……(其他配置信息不动) +``` + +##### 5.1.2 `properties`配置 + +- `weaver_session_filter.properties`(系统) + +外部配置文件,配置放行的路径地址。(启用了`weaver_session_filter.properties`会自动覆盖原`web.xml`中的路径) + +- `weaver_session_filter_dev.properties`(用户自定义) + +用户自定义配置文件,配置放行的路径地址(项目二开的路径建议放用户定义配置文件,升级时不被覆盖)会自动覆盖web.xml 中的路径地址。 + +```properties +# 头部验证路径 适用于 EM +checkurl=/api/hrm/emmanager; +# 头部验证放行路径 适用于 EM +uncheckurl=/api/ec/dev/app/getCheckSystemInfo;/api/ec/dev/app/emjoin; +# session验证放行 不检查放行的路径(白名单) +unchecksessionurl=/api/doc/upload/mobile/uploadFile;/api/doc/upload/mobile/shareFile;/weaver/weaver.file.FileDownload;/api/ec/dev/app/getCheckSystemInfo;/api/ec/dev/app/emjoin;/api/hrm/emmanager/; +``` + +### 5.2 Token认证 + +> [Token认证](http://wcode.store/#/./weaver/Token异构系统认证) + +### 5.3 单点登录 + +> 单点登录:直接通过URL打开 `E9` 页面 + +- 在 `ecology/WEB-INF/web.xml` 文件默认加上以下配置 + +```xml + + getToken + weaver.weaversso.GetToken + + + getToken + ssologin/getToken + + + WeaverLoginFilter + weaver.weaversso.WeaverLoginFilter + + + WeaverLoginFilter + *.jsp + *.html + +``` + +- 在 `ecology/WEB-INF/prop/WeaverLoginClient.properties` 配置文件中加入以下参数 + +其中 `test` 指的是下文中的 `appid` 参数,`127.0.0.1` 指的是授权的 IP 地址 + +```properties +test=127.0.0.1 +``` + +- 重启 `E9` 服务 + +- 使用 `Java` 测试 + +```java +package com.wcode.util; + +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.protocol.HTTP; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * @author King + * @version 1.0.0 + * @create 2019/11/5 16:17 + */ +public class SsoUtils { + + private static final String SSO_API = "/ssologin/getToken"; + + public static String getToken(String ip, int port, String appId, String loginId) throws IOException { + String url = ip + ":" + port + SSO_API; + HttpPost req = new HttpPost(url); + List params = new ArrayList<>(2); + params.add(new BasicNameValuePair("appid", appId)); + params.add(new BasicNameValuePair("loginid", loginId)); + req.setEntity(new UrlEncodedFormEntity(params, HTTP.DEF_CONTENT_CHARSET)); + return HttpUtils.getString(req); + } + + public static void main(String[] args) throws IOException { + String token = SsoUtils.getToken("http://127.0.0.1", 80, "test", "lcs"); + System.out.println("ssoToken: " + token); + String url = "http://127.0.0.1/systeminfo/version.jsp"; + HttpPost req = new HttpPost(url); + List params = new ArrayList<>(1); + params.add(new BasicNameValuePair("ssoToken", token)); + req.setEntity(new UrlEncodedFormEntity(params)); + System.out.println(HttpUtils.getString(req)); + } +} +``` + +控制台输出内容如下: + +![1572943794860](asset/1572943794860.png) + +## 6. 其他开发 + +### 6.1 日志配置 + +> `Ecology`底层采用的是`log4j`日志框架, 可根据环境自定义日志配置 +> +> `log4j`配置文件路径: `ecology/WEB-INF/log4jinit.properties` + +- 打开配置文件, 在文件末尾加上如下代码, 然后重启`resin`服务 + +```properties +# appender +log4j.logger.debug=DEBUG,debug +log4j.appender.debug=org.apache.log4j.DailyRollingFileAppender +# 按日期滚动文件 +log4j.appender.debug.DatePattern='_'yyyyMMdd'.log' +# 自定义日志文件路径 +log4j.appender.debug.File=@debug/debug.log +log4j.appender.debug.layout=org.apache.log4j.PatternLayout +# 输出内容格式 +log4j.appender.debug.layout.ConversionPattern=%d{HH:mm:ss.SSS}[%p] %l: %m%n +log4j.additivity.debug=false +``` + +- 代码中使用: + +```java +// 获取自定义的 logger, 其中 debug为配置文件中 log4j.logger.debug中的debug +Logger logger = LoggerFactory.getLogger("debug"); +// 支持占位符输出, 不定参数 +logger.debug("debug级别消息: {}, {}", "参数1", "参数2"); +logger.info("info级别消息!"); +logger.warn("warn级别消息!"); +logger.error("error级别消息!"); +``` + +- 最终日志输出路径: + +![1570369325637](asset/1570369325637.png) + +**建议**: 将重要的日志以 `info` 级别以上输出, 开发的日志以 `debug` 级别输出, 这样的话再正式环境下只需修改配置, 即可实现只输出 `info` 级别的日志, 减少日志的输出! + +```properties +# 将日志级别提升至INFO +log4j.logger.debug=INFO,debug +``` + +### 6.2 Redis 配置 + +- 本地下载`redis` +- `ecology/WEB-INF/prop/weaver_new_session.properties` + +```properties +#1表示启用新的session方式,其他值表示不启用 +status=1 +#用于调试的USERID +debugUsers= +#session id生成模式,1表示自定义生成模式(UUID模式),其他值表示中间件自定义生成模式 +useCustomSessionId=1 +#同步频率设置(单位,秒) +#主表同步频率 +SessionTableSync=2 +#明细表同步频率 +SessionItemTableSync=5 +#超时扫描频率 +SessionOverTime=300 +#垃圾数据清理扫描频率 +SessionLeak=3600 + +#启动模式,默认是数据库模式 +#className=weaver.session.util.DBUtil +className=weaver.session.util.RedisSessionUtil +#redis ip +redisIp=127.0.0.1 +#redis port +redisPort=6379 +#redis password +redisPassword=123456 +enableImmediatelySync=true +etoken= +``` + +### 6.3 lombok 配置 + +- 下载 `lombok.jar` +- `idea` 安装 `lombok plugin` + +![1571882600348](asset/1571882600348.png) + +- 代码中使用 + +```java +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@ToString +public class TestDTO { + private String name; + private String password; +} +``` + +### 6.4 Webservice 使用 + +> 使用`SoapUI` 解析 `webservice`接口 + +- SoapUI 介绍和使用方式可以参考博文: https://www.cnblogs.com/yatou-de/p/9273346.html +- 软件下载:https://pan.baidu.com/s/1j36r6_NO_pcTfNDCwjLrog,提取码: 8v9x + +> 使用 `HttpClient` 以 `xml` 报文形式调用 `webservice` 服务 + +请求报文可以通过 `SoapUI` 查看 + +![1571909908394](asset/1571909908394.png) + +```java +import com.wcode.util.WsUtils; + +import java.io.IOException; + +public class TestWebService { + + public static void main(String[] args) throws IOException, DocumentException { + String url = "http://www.webxml.com.cn/webservices/ChinaTVprogramWebService.asmx"; + String xml = "\n" + + " \n" + + " \n" + + " \n" + + " 18\n" + + " \n" + + " \n" + + ""; + String resp = WsUtils.execute(url, xml); + Element rootElement = WsUtils.getRootElement(resp); + List elements = WsUtils.getElements(rootElement, "TvStation"); + for (Element element : elements) { + Element e1 = element.element("tvStationID"); + System.out.println(e1.getTextTrim()); + Element e2 = element.element("tvStationName"); + System.out.println(e2.getTextTrim()); + } + } +} +``` + +### 6.5 SQL缓存注意事项 + +- 原则上禁止通过非程序渠道直接修改oa数据库数据。如果一定要修改,请修改完数据后,chrome浏览器访问/commcache/cacheMonitor.jsp界面,点击重启加载配置。这样操作修改的数据可以及时生效。 +- 如果存在第三方程序修改oa数据库的表,则需要将会修改的表的名称以(名称=名称)的格式增加到例外配置文件:ecology\WEB-INF\prop\cacheBackList.properties中,然后再使用重启加载配置,使其生效。 +- 如果客户二次开发中存在非RecordSet(系统标准sql操作类)类修改数据库里的表,也需要将该表名按注意事项2的方式操作,将其加入例外配置文件中。 +- 如果客户二次开发中还存在调用自己新建的存储过程,视图,函数(方法)。也需要将存储过程,视图,函数(方法)中涉及到的表名加入到例外配置文件中ecology\WEB-INF\prop\cacheBackList.properties。然后再使用重启加载配置,使其生效。 +- 集群环境,如果开启sql缓存,必须所有节点全部开启,关闭也必须所有节点同时全部关闭,否则必然存在缓存不同步问题 + +### 6.6 远程调试 + +> 该方案只能在测试或者开发环境中使用,不允许在生产环境中使用!**切记 !!!** + +配置`JVM`远程调试参数: `resin\conf\resin.properties` + +```properties +# 初始配置 +jvm_args : -Xmx5550m -Xms5550m -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+DisableExplicitGC -javaagent:wagent.jar +# 修改后的配置 +jvm_args : -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9090 -Xmx5550m -Xms5550m -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+DisableExplicitGC -javaagent:wagent.jar +``` + +![1573458126874](asset/1573458126874.png) + +总结:更为详细的配置过程参考: https://www.jianshu.com/p/4c657bf02cb3 + +### 6.7 容器化部署 + +> 具体部署资料: http://wcode.store/#/./docker/rancher diff --git a/泛微系统部署.md b/泛微系统部署.md new file mode 100644 index 0000000..2544b0a --- /dev/null +++ b/泛微系统部署.md @@ -0,0 +1,1239 @@ +# 泛微平台系统部署 + +> 本文主要描述了泛微平台环境部署的几种方案,包括 `window / linux` 环境下的 `e-cology`,`e-mobile`部署,集群部署,docker 微服务部署等。 + +## 1. 单机部署 + +> 通常情况下,如果客户的服务器系统是 `window server`,那么在部署 `e-cology`时,数据库一般选用 `sql server`(版本建议在2014以上) + +### 1.1 SQL Server 部署 + +SQL Server 的安装包可以在 https://msdn.itellyou.cn/ 中获取,在安装包的选择上需要注意的是: + +` sql_server_xx_express_with_tools` = ` sql_server_xx_express` + ` sql_server_xx_management_studio` + +- `sql_server_xx_express`:表示企业版数据库 +- `sql_server_xx_management_studio`:数据库管理工具软件。 + +这里我们选择的是 ` cn_sql_server_2014_express_with_tools_x64 `,因为该安装包中包含数据库管理工具。 + +![image-20200130143748999](asset/image-20200130143748999.png) + +安装 `SQL Server 2014` + +- 提取安装包,开始安装。**注意以下窗口在安装过程中不允许关闭掉,否则会安装失败!** + +![image-20200130144717795](asset/image-20200130144717795.png) + +- 一直下一步,直到以下步骤时进行`sa` 账号密码设置 + +![image-20200130150253400](asset/image-20200130150253400.png) + +- 选择下一步,等待安装完毕即可 + +![image-20200130151159103](asset/image-20200130151159103.png) + +### 1.2 Oracle 部署 + +> 如果客户服务器系统是 linux,那么一般采用 `Oracle` 或 `MySql` 作为数据库,这边要向客户表述 `Oracle` 与 `MySQL`的区别,其主要区别是 `Oracle` 属于商业产品,盗版可能会被告,但是其性能卓越,抗压性较强。`MySQL` 属于开源产品,抗压性较弱。 +> +> 一般企业用户所使用的 `linux` 发行版本都是 `CentOS` 或者 `Red Hat`,接下来会以 `CentOS` 系统为例进行 Oracle 部署的介绍 + +#### 1.2.0 快速安装 + +如果选择脚本安装的方式,则只要看 `1.2.0` 即可,其他的为具体步骤。 + +脚本地址: + +- `install.sh`: https://github.com/Y-Aron/cloud-note/blob/master/weaver/shell/oracle/install.sh +- `dbca.rsp`: https://github.com/Y-Aron/cloud-note/blob/master/weaver/shell/oracle/dbca.rsp +- `new_sid.sh`: https://github.com/Y-Aron/cloud-note/blob/master/weaver/shell/oracle/new_sid.sh + +`shell` 脚本安装步骤如下: + +- 上传 `install.sh`,`dbca.rsp`,`new_sid.sh` 到与`oracle`安装包同级目录下 + +- 切换至 root 用户,执行 `install.sh` 脚本 + +```bash +su root +./install.sh +``` + +- `dbca.rsp`:静默安装 `oracle sid` 的相关配置文件,可根据实际情况自行配置 + +- 当出现 `Successfully Set Software` 提醒时,执行 `new_sid.sh` + +```bash +./new_sid.sh +``` + +#### 1.2.1 安装前准备 + +- 使用 `Xshell` 软件连接服务器:软件安装自行百度 + +- 配置镜像源:复制并执行以下命令 + +```shell +cd /etc/yum.repos.d/ +# 下载并安装阿里云镜像 +yum install wget +sudo wget http://mirrors.aliyun.com/repo/Centos-7.repo +sudo mkdir repo_bak +mv /etc/yum.repos.d/repo_bak/Centos-7.repo /etc/yum.repos.d/ +# 清除并重新生成yum缓存 +yum clean all +yum makecache +``` + +- 下载 `Oracle11gR2`:https://pan.baidu.com/s/1gA33_cOlyzq6Bu3C4R8Vfw + +#### 1.2.2 安装 Oracle + +- 安装所需的软件包 + +```shell +yum -y install binutils compat-libstdc++-33 compat-libstdc++-33.i686 elfutils-libelf elfutils-libelf-devel gcc gcc-c++ glibc glibc.i686 glibc-common glibc-devel glibc-devel.i686 glibc-headers ksh libaio libaio.i686 libaio-devel libaio-devel.i686 libgcc libgcc.i686 libstdc++ libstdc++.i686 libstdc++-devel make sysstat unixODBC unixODBC +``` + +- 创建用户组和用户 + +```shell +# 创建 oinstall 用户组 +groupadd oinstall +# 创建 dba 用户组 +groupadd dba +# 创建 oracle 用户 +useradd -g oinstall -G dba oracle +# 设置密码 +passwd oracle +``` + +- 修改`kernel` 内核参数 + +``` shell +vi /etc/sysctl.conf +# --------------------------------------- +# 配置文件内加入 修改以下参数。如果没有可以自己添加,如果默认值比参考值大,则不需要修改。 +# 这个内核参数用于设置系统范围内共享内存段的最大数量。该参数的默认值是 4096 。通常不需要更改。 +kernel.shmmni = 4096 +# 该参数定义了共享内存段的最大尺寸(以字节为单位)。缺省为32M,对于oracle来说,该缺省值太低了,# 通常将其设置为2G。 +kernel.shmmax = 2147483648 +# 该参数表示系统一次可以使用的共享内存总量(以页为单位)。缺省值就是2097152,通常不需要修改。 +kernel.shmall = 2097152 +kernel.sem = 250 32000 100 128 +fs.aio-max-nr = 1048576 +# 设置最大打开文件数 +fs.file-max = 65536 +# 可使用的IPv4端口范围 +net.ipv4.ip_local_port_range = 9000 65500 +net.core.rmem_default = 262144 +net.core.rmem_max = 4194304 +net.core.wmem_default = 262144 +net.core.wmem_max = 1048586 +# --------------------------------------- + +# 保存退出后设置立刻生效 +sysctl -p +``` + +- 修改系统资源限制 + +```shell +vi /etc/security/limits.conf + +# 配置文件下方加入 +oracle soft nproc 2047 +oracle hard nproc 16384 +oracle soft nofile 1024 +oracle hard nofile 65536 +oracle soft stack 10240 + +# 修改用户验证选项 关联设置 +vi /etc/pam.d/login +# 在最后一条规则之前加入以下session配置 +session required /lib64/security/pam_limits.so +session required pam_limits.so +``` + +- 创建安装目录和设置目录权限 + +```shell +# oracle: 安装目录 +mkdir -p /usr/local/oracle/product/11.2.0/db_1 +# oradata: 数据存储目录 +mkdir /usr/local/oracle/oradata +# flash_recovery_area: 恢复目录 +mkdir /usr/local/oracle/flash_recovery_area +# oraInventory: 清单目录 +mkdir /usr/local/oraInventory +chown -R oracle:oinstall /usr/local/oracle +chown -R oracle:oinstall /usr/local/oraInventory +chmod -R 775 /usr/local/oracle +chmod -R 775 /usr/local/oraInventory +``` + +- 上传文件到 `/home` 目录下,并解压 + +```shell +yum install unzip +unzip linux.x64_11gR2_database_1of2.zip +unzip linux.x64_11gR2_database_2of2.zip +``` + +- 准备oracle安装应答模板文件 `db_install.rsp` + +```shell +cp /home/database/response/* /usr/local/oracle/ +# 编辑应答文件的相关配置 +vi /usr/local/oracle/db_install.rsp +# ------------------------------------- +# 安装类型,只装数据库软件 +oracle.install.option=INSTALL_DB_SWONLY +# 安装组 +UNIX_GROUP_NAME=oinstall +# INVENTORY目录(**不填就是默认值,本例此处需修改,因个人创建安装目录而定) +INVENTORY_LOCATION=/usr/local/oraInventory +# 选择语言  +SELECTED_LANGUAGES=en,zh_CN +# oracle_home: 路径根据目录情况注意修改 本例安装路径/usr/local/oracle +ORACLE_HOME=/usr/local/oracle/product/11.2.0/db_1 +# oracle_base: 注意修改 +ORACLE_BASE=/usr/local/oracle +# oracle版本 +oracle.install.db.InstallEdition=EE +# 自定义安装,否,使用默认组件 +oracle.install.db.isCustomInstall=false +# dba用户组 +oracle.install.db.DBA_GROUP=dba +# oper用户组 +oracle.install.db.OPER_GROUP=dba +# 注意此参数 设定一定要为true +DECLINE_SECURITY_UPDATES=true +# ------------------------------------- +``` + +- 切换用户并开始静默安装 + +```shell +# 切换到oracle / 进入解压目录 +su oracle +cd /home/database/ +# 防止报错 +unset DISPLAY +./runInstaller -silent -ignorePrereq -responseFile /usr/local/oracle/db_install.rsp + +# /home/database是安装包解压后的路径,此处根据安装包解压所在位置做修改,因人而异。 +  # runInstaller 是主要安装脚本 +  # -silent 静默模式 +  # -force 强制安装 +  # -ignorePrereq忽略warning直接安装 +  #-responseFile读取安装应答文件 +``` + +- 出现以下提醒则表示安装成功 + +![image-20200202005200486](asset/image-20200202005200486.png) + +- 安装成功后还需要执行以下命令 + +```shell +su root +密码: +cd /usr/local/oraInventory/ +./orainstRoot.sh +cd /usr/local/oracle/product/11.2.0/db_1/ +./root.sh +``` + +- 设置Oracle用户环境变量 + +```shell +# 切换至oracle账号 +su oracle +# 编辑用户环境变量 +echo 'export ORACLE_BASE=/usr/local/oracle +export ORACLE_HOME=$ORACLE_BASE/product/11.2.0/db_1 +export LANG="zh_CN.UTF-8" +export NLS_LANG="SIMPLIFIED CHINESE_CHINA.AL32UTF8" +export NLS_DATE_FORMAT="yyyy-mm-dd hh24:mi:ss" +export PATH=$PATH:$ORACLE_HOME/bin ' >> ~/.bashrc +# 立即生效 +source ~/.bashrc +``` + +- 配置监听以及监听的相关命令 + +```shell +# 静默方式配置监听 +netca /silent/responseFile /usr/local/oracle/netca.rsp +# 启动监听 +lsnrctl start +# 暂停监听 +lsnrctl stop +# 查看监听 +lsnrctl status +# 检查是否监听正常启动 +netstat -tnulp | grep 1521 +(No info could be read for "-p": geteuid()=1001 but you should be root.) +tcp6 0 0 :::1521 :::* LISTEN +``` + +#### 1.2.3 静默方式建立新库 + +- 新建 `dbca.rsp` + +```shell +su oracle +vi /home/oracle/dbca.rsp +# -------------------------------------------------- +[GENERAL] +RESPONSEFILE_VERSION = "11.2.0" +# 必须指定为创建数据库 +OPERATION_TYPE = "createDatabase" +[CREATEDATABASE] +# 数据库的Global database name +GDBNAME = "orcl" +# 数据库的实例名 +SID = "orcl" +TEMPLATENAME = "General_Purpose.dbc" +STORAGETYPE=FS +# 指定数据文件存储的目录 +DATAFILEDESTINATION =/usr/local/oracle/oradata +# 指定数据文件恢复的目录 +RECOVERYAREADESTINATION=/usr/local/oracle/flash_recovery_area +# 指定字符集 +CHARACTERSET = "AL32UTF8" +# 指定国家字符集 +NATIONALCHARACTERSET= "AL16UTF16" +LISTENERS=LISTENER +TOTALMEMORY = "700" +# 指定sys用户密码[必填] +SYSPASSWORD = "123456" +# 指定system用户密码[必填] +SYSTEMPASSWORD = "123456" +# 指定使用自动内存管理 +AUTOMATICMEMORYMANAGEMENT = "TRUE" +# -------------------------------------------------- +``` + +- 以静默方式开始创建数据库 + +```shell +dbca -silent -responseFile /home/oracle/dbca.rsp +``` + +- 修改 Oracle 用户的环境变量 + +```shell +vi ~/.bashrc +# -------------------------------------------------- +# 与上述安装的数据库SID一致 +export ORACLE_SID=orcl +export ORACLE_OWNER=$ORACLE_SID +# -------------------------------------------------- + +# 立即生效 +source ~/.bashrc + +# 修改监听文件 +vi /usr/local/oracle/product/11.2.0/db_1/network/admin/listener.ora + +# -------------------------------------------------- +# 添加SID相关配置,注意 SID_NAME区分大小写! +SID_LIST_LISTENER = + (SID_LIST = + (SID_DESC = + (ORACLE_HOME =/usr/local/oracle/product/11.2.0/db_1) + (SID_NAME = orcl) + ) + ) + +LISTENER = + (DESCRIPTION_LIST = + (DESCRIPTION = + (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521)) + (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521)) + ) + ) + +ADR_BASE_LISTENER = /usr/local/oracle +# -------------------------------------------------- + +# 重启监听 +lsnrctl stop +lsnrctl start +``` + +- 出现以下信息则表明服务启动成功 + +![image-20200202131123106](asset/image-20200202131123106.png) + +#### 1.2.4 开启远程连接 + +```shell +# 关闭centos7防火墙 +systemctl stop firewalld.service +# 关闭开机启动 +systemctl disable firewalld.service +# 安装iptables防火墙 +yum install iptables-services +# 新增1521接口 +iptables -A INPUT -p tcp --dport 1521 -j ACCEPT +service iptables save +# 设置开机启动 +systemctl enable iptables +# 重启iptabls服务 +systemctl restart iptables.service +``` + +#### 1.2.5 开机自动启动 + +```shell +vi /usr/local/oracle/product/11.2.0/db_1/bin/dbstart +# ------------------------------- +# 修改ORACLE_HOME_LISTNER参数 +ORACLE_HOME_LISTNER=$ORACLE_HOME +# ------------------------------- + +vi /usr/local/oracle/product/11.2.0/db_1/bin/dbshut +# ------------------------------- +# 修改ORACLE_HOME_LISTNER参数 +ORACLE_HOME_LISTNER=$ORACLE_HOME +# ------------------------------- + +vi /etc/oratab +# ------------------------------- +# 修改为 :Y +orcl:/usr/local/oracle/product/11.2.0/db_1:Y +# ------------------------------- +``` + +切换到 root 用户,执行 `vi /etc/init.d/oracle` + +```shell +#!/bin/sh +# chkconfig: 345 61 61 +# description: Oracle 11g R2 AutoRun Servimces +# /etc/init.d/oracle +# Run-level Startup script for the Oracle Instance, Listener, and +# Web Interface +export ORACLE_BASE=/usr/local/oracle +export ORACLE_HOME=$ORACLE_BASE/product/11.2.0/db_1 +export ORACLE_SID=orcl +export ORACLE_UNQNAME=$ORACLE_SID +export PATH=$ORACLE_HOME/bin:/user/sbin:$PATH +export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH +ORA_OWNR="oracle" +# if the executables do not exist -- display error +if [ ! -f $ORACLE_HOME/bin/dbstart -o ! -d $ORACLE_HOME ] +then +echo "Oracle startup: cannot start" +exit 1 +fi +# depending on parameter -- startup, shutdown, restart +# of the instance and listener or usage display +case "$1" in +start) +# Oracle listener and instance startup +su $ORA_OWNR -lc $ORACLE_HOME/bin/dbstart +echo "Oracle Start Succesful!OK." +;; +stop) +# Oracle listener and instance shutdown +su $ORA_OWNR -lc $ORACLE_HOME/bin/dbshut +echo "Oracle Stop Succesful!OK." +;; +reload|restart) +$0 stop +$0 start +;; +*) +echo $"Usage: `basename $0` {start|stop|reload|reload}" +exit 1 +esac +exit 0 +``` + +保存退出后执行以下命令 + +```shell +cd /etc/init.d +chmod +x oracle +chkconfig --add oracle +chkconfig oracle on +``` + +#### 1.2.6 创建表空间与用户 + +- 进入`sqlplus` + +```shell +sqlplus / as sysdba +``` + +- 创建表空间 + +```sql +create tablespace e9 logging datafile'/usr/local/oracle/oradata/orcl/e9.dbf' size 1024m autoextend on next 100m maxsize 10240m extent management local; +``` + +- 创建用户 + +```sql +create user weaver identified by 123456 default tablespace e9; +``` + +- 5.4 给用户赋权限 + +```sql +grant dba to weaver; +``` + +#### 1.2.7 常见问题 + +- `ORA-01034: ORACLE not available ORA-27101` + +```bash +# Step1: 启动oracle监听 +lsnrctl start +# Step2: 设置实例名,实例名一般是"orcl" +set ORACLE_SID=orcl +# Step3: 启动oracle服务 +# 进入 sql 控制台,执行 startup命令,如果被告知已经启动,可以先输入shutdown immediate, 然后在输入startup +sqlplus / as sysdba +startup; +``` + +### 1.3 下载与安装 E9 + +> 安装包下载文档:https://www.e-cology.com.cn/spa/document/index.jsp?id=3861088&newsDataType=fullSearch&router=1#/main/document/detail?_key=niim1h +> +> 将 `ecology`,`jdk`, `resin` 下载并放置在同一目录下 + +#### 1.3.1 E9 程序包介绍 + +- `Ecology`:`E9` 的主程序包 +- `Jdk`:`Java` 运行程序 +- `Resin`:`Resin` 中间件 + +#### 1.3.2 Resin 基本配置 + +`resin/conf/resin.xml` + +```xml + + + + + +``` + +`resin/conf/resin.properties` + +```properties +# 修改服务端口 +app.http : 80 +app.https : 8443 +``` + +#### 1.3.3 Resin-Win 配置 + +在 `window` 环境下,`resin/resinstart.bat` 为启动文件,可右键编辑内容,其中 `java_home` 为 `jdk` 路径,这里使用相对路径即可,当然也可以使用绝对路径 。单击 `resinstart.bat` 启动服务 + +```bash +set java_home=../jdk +resin.exe +``` + +#### 1.3.4 Resin-Linux 配置 + +- 编译安装 `resin` + +```bash +# prefix: resin路径 +# with-java-home: jdk路径 +cd /usr/local/weaver/resin +chmod +x ./configure +./configure --prefix=/usr/local/weaver/resin --with-java-home=/usr/local/weaver/jdk --enable-64bit +make +make install +``` + +- 修改相关配置文件 + +```bash +# 修改 resin/bin/resin.sh 中的jdk路径 +sed -i "s/jdk1.8.0_151/jdk/g" /usr/local/weaver/resin/bin/resin.sh +sed -i "s/weaver/local\\/weaver/g" /usr/local/weaver/resin/bin/resin.sh +# 修改 resin.sh 路径 +sed -i "s/weaver/local\\/weaver/g" /usr/local/weaver/resin/bin/startresin.sh +sed -i "s/weaver/local\\/weaver/g" /usr/local/weaver/resin/bin/stopresin.sh +# 修改 resin/conf/resin.xml 中的jdk和ecology路径 +# jdk 必须是绝对路径,ecology可以是绝对路径也可以是相对 路径 +sed -i "s/#INSTALLDIR#JDK\\\bin\\\javac/\\/usr\\/local\\/weaver\\/jdk\\/bin\\/javac/g" /usr/local/weaver/resin/conf/resin.xml +sed -i "s/#INSTALLDIR#ecology/..\\/ecology/g" /usr/local/weaver/resin/conf/resin.xml +``` + +- 启动 `resin`,打开浏览器输入 `http://127.0.0.1` 即可使用 `e9` + +### 1.4 Redis 部署以及配置 + +> E9 默认使用 `ehcache2.x` 进行数据缓存,支持使用 `redis` 进行数据缓存。 +> +> Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。 + +#### 1.4.1 window 安装 Redis + +window安装 redis 比较简单,下载安装包即可,地址: https://github.com/microsoftarchive/redis/releases + +下载安装包 `Redis-x64-3.2.100.msi`,点击下一步即可~ + +![image-20200201225802580](asset/image-20200201225802580.png) + +#### 1.4.2 Linux 安装 Redis + +- 安装编译环境 + +```bash +# ubuntu +sudo apt-get install make gcc +# centos +yum install make gcc +``` + +- 安装 redis + +```bash +cd ~ +# 下载 redis 源码 +wget http://download.redis.io/releases/redis-5.0.6.tar.gz +# 解压 +tar xzf redis-5.0.6.tar.gz +# 切换到解压目录 +cd redis-5.0.6 +# 切换到 root 权限 +su root +# 编译安装 +make PREFIX=/usr/local/redis install +``` + +- 配置和启动 + +> redis.conf 是 redis 的配置文件,redis.conf 在 redis 源码目录下 +> +> 拷贝配置文件到安装目录下 + +```bash +# 进入源码目录 +cd ~/redis-5.0.6 +# 拷贝配置文件至安装目录 +cp ~/redis-5.0.6/redis.conf /usr/local/redis/redis.conf +``` + +- 前台启动 + +```bash +# 进入安装目录 +cd /usr/local/redis/bin +./redis-server +``` + +- 后端模式启动 + +修改 redis.conf 配置文件,daemonize 参数设置为 yes,表示以后端模式启动 + +![image-20191114111003527](asset/image-20191114111003527.png) + +修改完毕后保存退出,重新启动 redis + +```bash + # 进入安装目录 + cd /usr/local/redis + # 已后端模式启动 redis + ./bin/redis-server ./redis.conf +``` + +#### 1.4.3 E9 使用 Redis + +` ecology/WEB-INF/prop/weaver_new_session.properties `,开启redis并修改相关配置,注意redis的密码一定要有,否则会报错! + +```properties +# 1表示启用新的session方式,其他值表示不启用 +status=1 +# 用于调试的USERID +debugUsers= +# session id生成模式,1表示自定义生成模式(UUID模式),其他值表示中间件自定义生成模式 +useCustomSessionId=1 +# 同步频率设置(单位,秒) +# 主表同步频率 +SessionTableSync=2 +# 明细表同步频率 +SessionItemTableSync=5 +# 超时扫描频率 +SessionOverTime=300 +# 垃圾数据清理扫描频率 +SessionLeak=3600 + +#启动模式,默认是数据库模式 +# className=weaver.session.util.DBUtil +className=weaver.session.util.RedisSessionUtil +# redis ip +redisIp=127.0.0.1 +# redis port +redisPort=6379 +# redis password, 注意密码必须设置,否则会报错! +redisPassword=123456 +enableImmediatelySync=true +etoken= +``` + +使用 redis 可视化工具可以看到如下结果,则表明启动了redis + +![image-20200201224037086](asset/image-20200201224037086.png) + +## 2. 集群部署 + +> `e9` 集群部署与 `e8` 基本一致,只增加了一个`redis` 配置。 +> +> 集群方案有很多,比如:`ec+nginx+weblogic` ,`ec+nginx+resin`,`ec+F5+resin`,本文只介绍 `ec+nginx+resin` + +#### 2.0 集群准备 + +集群部署需要准备: + +- 一台文件服务器(`NFS`)服务器地址:`192.168.44.143` +- 一台主服务器(`Ecology+MySQL+Nginx`)服务器地址:`192.168.44.139` +- 一台从服务器(`Ecology`)服务器地址:`192.168.44.144` + +#### 2.1 文件服务器配置 + +##### 2.1.1 NFS 服务器部署 + +- 安装`nfs` + +```bash +yum install -y nfs-utils +# 设置开启启动 +sudo systemctl enable rpcbind +sudo systemctl enable nfs +``` + +- 配置对外共享文件:`/etc/exports` + +```bash +vi /etc/exports +# 在 /etc/exports 中添加以下内容 +# 意思是将本地文件夹 /data 共享给192.168.44.139和144服务器 +# 也可以用*号代替,比如: /data *(rw,sync,no_root_squash) +# 意思是将本地文件夹 /data 共享到所有和这个文件服务器相通的机器 +/data 192.168.44.139(rw,sync,no_root_squash) +/data 192.168.44.144(rw,sync,no_root_squash) +``` + +- 重启`nfs`服务 + +```bash +exportfs -rv +systemctl restart nfs +# 针对 rhel5 +systemctl resatrt portmap +# 针对 rhel6 +systemctl restart rpcbin +``` + +##### 2.1.2 文件同步配置 + +> 切换至主(从)服务器操作 + +- 在需要共享的节点挂载共享文件到对应目录 + +```bash +# 主服务器:192.168.44.139 +yum install -y nfs-utils +# 创建挂载目录 +mkdir /data +# 设置文件挂载 +mount -t nfs 192.168.44.143:/data /data +``` + +- 将 ecology 以下目录拷贝到 `/data/e9` 中,一般情况下主服务器做拷贝即可。 + +```bash +# 备份文件,注意这里使用mv而不是cp +cd /usr/local/weaver/ecology +mkdir -p nfs_bak/WEB-INF +# 移动以下目录至 nfs_bak 下 +\mv album formmode mobilemode mobile email filesystem images images_face images_frame LoginTemplateFile messager m_img others page upgrade wui nfs_bak +# 进入WEB-INF目录,移动以下文件夹至 nfs_bak/WEB-INF 下 +cd WEB-INF +\mv securityRule securityXML service lib/keys weaver_security_rules.xml weaver_security_config.xml hrmsettings.xml ../nfs_bak/WEB-INF + +# 将相关文件拷贝到 /data 目录下 +# 在/data中创建 ec/WEB-INF 目录 +mkdir -p /data/ec/WEB-INF +\cp -rf /usr/local/weaver/ecology/nfs_bak /data/ec +# 以下两个文件是不存在的,需要手动创建 +mkdir -p /data/ec/LoginTemplateFile /data/ec/others +``` + +- 创建软链接 + +```bash +ln -sf /data/ec/album /usr/local/weaver/ecology +ln -sf /data/ec/formmode /usr/local/weaver/ecology +ln -sf /data/ec/mobilemode /usr/local/weaver/ecology +ln -sf /data/ec/email /usr/local/weaver/ecology +ln -sf /data/ec/filesystem /usr/local/weaver/ecology +ln -sf /data/ec/images /usr/local/weaver/ecology +ln -sf /data/ec/images_face /usr/local/weaver/ecology +ln -sf /data/ec/images_frame /usr/local/weaver/ecology +ln -sf /data/ec/LoginTemplateFile /usr/local/weaver/ecology +ln -sf /data/ec/messager /usr/local/weaver/ecology +ln -sf /data/ec/m_img /usr/local/weaver/ecology +ln -sf /data/ec/others /usr/local/weaver/ecology +ln -sf /data/ec/page /usr/local/weaver/ecology +ln -sf /data/ec/upgrade /usr/local/weaver/ecology +ln -sf /data/ec/wui /usr/local/weaver/ecology +ln -sf /data/ec/WEB-INF/securityRule /usr/local/weaver/ecology/WEB-INF +ln -sf /data/ec/WEB-INF/securityXML /usr/local/weaver/ecology/WEB-INF +ln -sf /data/ec/WEB-INF/service /usr/local/weaver/ecology/WEB-INF +ln -sf /data/ec/WEB-INF/lib/keys /usr/local/weaver/ecology/WEB-INF/lib/keys +ln -sf /data/ec/WEB-INF/weaver_security_rules.xml /usr/local/weaver/ecology/WEB-INF/weaver_security_rules.xml +ln -sf /data/ec/WEB-INF/weaver_security_config.xml /usr/local/weaver/ecology/WEB-INF/weaver_security_config.xml +ln -sf /data/ec/WEB-INF/hrmsettings.xml /usr/local/weaver/ecology/WEB-INF/hrmsettings.xml +``` + +##### 2.1.3 缓存同步设置 + +- 配置 `/etc/hosts`:清空原有127默认配置,将集群各节点 `ip`地址加入到`hosts`中 + +![image-20200207081746240](asset/image-20200207081746240.png) + +- 修改 `ecology/WEB-INF/weaver.properties`,加入以下内容。注意,所有节点都需要配置! + +```properties +# 主节点ip(集群中任意一个节点,但有且只能有一个) +MainControlIP = 192.168.44.139 +# 本机ip:本机服务端口port +ip = 192.168.44.144:80 +broadcast=231.12.21.132 +syncType=http +# initial_hosts为参数为所有的应用服务器的节点的访问地址 +# 格式:ip1:port,ip2:port (中间以逗号分隔) +initial_hosts= 192.168.44.139:80,192.168.44.144:80 +``` + +#### 2.2 部署 Nginx + +- 在主服务器(192.168.44.139)下载安装 `nginx` + +```bash +# 下载nginx安装包 +yum install -y wget +wget https://nginx.org/download/nginx-1.17.8.tar.gz +# 下载编译依赖包 +yum install -y gcc-c++ pcre pcre-devel zlib zlib-devel openssl openssl-devel +tar -zxvf nginx-1.17.8.tar.gz +cd nginx-1.17.8 +# 编译安装 +./configure --prefix=/usr/local/nginx +make && make install +# 查看安装目录 +whereis nginx +# nginx: /usr/local/nginx +``` + +- 编辑 `/usr/local/nginx/conf/nginx.conf` + +```nginx +worker_processes 1; + +events { + worker_connections 1024; +} + +http { + upstream ecologycluster { + ip_hash; + # e-cology服务器地址1 + server 192.168.44.139:80; + # e-cology服务器地址2 + server 192.168.44.144:80; + # ... + } + include mime.types; + default_type application/octet-stream; + + sendfile on; + + keepalive_timeout 65; + server { + listen 8889; + server_name e9; + location / { + root html; + index index.html index.htm index.jsp; + proxy_pass http://ecologycluster; + proxy_next_upstream http_502 http_504 http_500 http_404 http_403 error timeout invalid_header; + proxy_redirect off; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $http_host; + proxy_read_timeout 3600; + proxy_send_timeout 3600; + access_log off; + send_timeout 300; + } + } +} +``` + +- 启动`nginx` + +```bash +cd /usr/local/nginx/sbin +./nginx -c /usr/local/nginx/conf/nginx.conf +``` + +- 打开浏览器输入 `http://192.168.44.139:8889`, 注意这里访问的是 `nginx` 地址! + +#### 2.3 故障测试 + +- 将两台服务器都停掉,再访问 `http://192.168.44.139:8889` +- 开启从服务器,将主服务器(192.168.44.139)停掉,再访问 `http://192.168.44.139:8889` +- 开启主服务器,将从服务器(192.168.44.144)停掉,再访问 `http://192.168.44.139:8889` + +## 3. Docker 部署 + +> Docker 部署适用于客户服务器系统为 `linux`,`window` 系统不推荐使用。 +> +> Docker 部署不是成熟方案,并且需要一定技术支撑,该方案量力而为。 +> +> 下面使用 `CentOS` 系统进行`Docker-E9`部署 + +#### 3.1 Docker 安装 + +```bash +# step 1: 安装必要的一些系统工具 +sudo yum install -y yum-utils device-mapper-persistent-data lvm2 +# Step 2: 添加软件源信息 +sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo +# Step 3: 更新并安装Docker-CE +sudo yum makecache fast +sudo yum -y install docker-ce +# Step 4: 开启Docker服务 +sudo service docker start +``` + +#### 3.2 配置加速器 + +```bash +# 配置阿里云加速器 +echo "{ + \"registry-mirrors\": [\"https://xh36jugz.mirror.aliyuncs.com\"] +}">/etc/docker/daemon.json +# 重启docker +sudo systemctl daemon-reload +sudo systemctl restart docker +``` + +#### 3.3 制作 E9 镜像 + +> 创建目录:`mkdir /usr/local/weaver` + +##### 3.3.1 使用 `ubuntu` 依赖 + +- 上传 `Ecology9.00.xxxx.xx.zip`,`jdk-8u231-linux-x64.tar.gz`, `Resin-4.0.58.zip` 至 `/usr/local/weaver` 目录 +- 解压文件 + +```bash +# 安装解压工具,如果已经安装可省略 +yum install unzip +# 解压文件夹, ecology按照具体的版本号 +unzip Ecology9.00.xxxx.xx.zip +unzip Resin-4.0.58.zip +unzip jdk-8u231-linux-x64.tar.gz +# 对解压出来的文件夹重命名 +mv Resin resin +mv jdk1.8.0_231 jdk +``` + +- 修改 resin 相关配置:查看 [1.3.4 Resin-Linux 配置](#1.3.4 Resin-Linux 配置) + +- 创建 `ubuntu` 依赖的 `Dockerfile` + +```bash +echo 'FROM ubuntu +COPY ecology/ /usr/local/weaver/ecology/ +COPY resin/ /usr/local/weaver/resin/ +COPY jdk/ /usr/local/weaver/jdk/ +EXPOSE 8080 +RUN chmod +x /usr/local/weaver/resin/bin/resin.sh +CMD ["/bin/sh", "-c", "/usr/local/weaver/resin/bin/resin.sh console"]'>/usr/local/weaver/Dockerfile +``` + +##### 3.3.2 使用 `resin:e9` 依赖 + +- 使用该依赖则只需上传 `Ecology9.00.xxxx.xx.zip` 至 `/usr/local/weaver` 目录即可 + +- 解压文件 + +```bash +# 安装解压工具,如果已经安装可省略 +yum install unzip +# 解压文件夹, ecology按照具体的版本号 +unzip Ecology9.00.xxxx.xx.zip +``` + +- 创建 `resin:e9` 依赖的 `Dockerfile` + +```bash +echo 'FROM registry.cn-hangzhou.aliyuncs.com/weaver/resin:e9 +COPY ecology/ /usr/local/weaver/ecology/'>Dockerfile +``` + +##### 3.3.3 构建镜像 + +- 路径切换到 `/usr/local/weaver` 下,执行镜像构建命令,注意末尾的 `.` 号是必须的! + +```bash +cd /usr/local/weaver +# ec系统瘦身 +rm -rf $(find /usr/local/weaver/ecology -name="**.map.js") +# 修改初始验证码 +sed -i 's/wEAver2018/1/g' /usr/local/weaver/ecology/WEB-INF/code.key +# 开始构建镜像 +docker build -t e9:191202 . +``` + +- 出现以下信息表示镜像构建成功 + +![image-20200202145325222](asset/image-20200202145325222.png) + +##### 3.3.4 镜像瘦身 + +> `e-cology9` 构建镜像时,会存在一个让客户吐槽的问题,那就是构建出的镜像过大,从图中可以看出,`e9:191202` 镜像包已经达到 `5.05GB` 大小,下面介绍几个镜像瘦身的方案,大约能瘦身 `1-2G` 左右 + +通过软件分析`e-cology9` 程序,发现文件扩展名为 `.map`, `.jar`, `.js` 的文件占比重最大。其中 `.jar` 为后端文件,`.js` 为前端文件,这两个不要轻易的进行删减!那么我们可以动的只剩下 `.map` 文件了。 + +![image-20200206212702901](asset/image-20200206212702901.png) + +关于 `.map.js` 文件介绍: + +`source map`文件是`js`文件压缩后,文件的变量名替换对应、变量所在位置等元信息数据文件,一般这种文件和`min.js`主文件放在同一个目录下。 比如压缩后原变量是map,压缩后通过变量替换规则可能会被替换成a,这时source map文件会记录下这个mapping的信息,这样的好处就是说,在调试的时候,如果有一些 `js`报错,那么浏览器会通过解析这个map文件来重新merge压缩后的`js`,使开发者可以用未压缩前的代码来调试,这样会给我们带来很大的方便! + +**换句话说以 .map 后缀的文件,唯一的作用是方便在开发过程中进行调试,但是在生产环境中,可以被删除。** + +OK,删除掉 `.map` 文件后,整个程序的体积瞬间少了 `1.0GB` 左右,接下来还有一个能删除的目录,那就是 `ecology/data`,这个目录下存放的是数据库初始化的 `sql` 文件,从图中可以看出这些 `sql` 文件差不多占 `200M` 左右,个人建议第一次构建镜像时不要删除这些文件,等待数据库初始化完毕,二次构建镜像时把这些文件删除,这样 `e-cology9` 镜像体积又能瘦下来了~ + +![image-20200206214039366](asset/image-20200206214039366.png) + +#### 3.4 安装 docker-compose + +> 百度云盘下载:https://pan.baidu.com/s/1bEGXrwbQo32Gu8UbXgyFQQ +> +> 下载 `docker-compose` 上传至 `/usr/local/bin/` 下,然后执行以下命令 + +```shell +chmod +x /usr/local/bin/docker-compose +``` + +#### 3.5 启动 Ecology + +##### 3.5.1 创建 `docker-compose.yml` + +```yml +version: '3.1' +services: + ecology: + restart: always + image: e9-mysql:190902 + container_name: e9 + ports: + - 8080:80 + volumes: + - ./ecology/album:/usr/local/weaver/ecology/album + - ./ecology/formmode:/usr/local/weaver/ecology/formmode + - ./ecology/messager:/usr/local/weaver/ecology/messager + - ./ecology/mobilemode:/usr/local/weaver/ecology/mobilemode + - ./ecology/mobile:/usr/local/weaver/ecology/mobile + - ./ecology/email:/usr/local/weaver/ecology/email + - ./ecology/filesystem:/usr/local/weaver/ecology/filesystem + - ./ecology/images_face:/usr/local/weaver/ecology/images_face + - ./ecology/images_frame:/usr/local/weaver/ecology/images_frame + - ./ecology/license:/usr/local/weaver/ecology/license + - ./ecology/log:/usr/local/weaver/ecology/log + - ./ecology/LoginTemplateFile:/usr/local/weaver/ecology/LoginTemplateFile + - ./ecology/m_img:/usr/local/weaver/ecology/m_img + - ./ecology/wui:/usr/local/weaver/ecology/wui + - ./ecology/others:/usr/local/weaver/ecology/others + - ./ecology/page:/usr/local/weaver/ecology/page + - ./ecology/upgrade:/usr/local/weaver/ecology/upgrade + - ./ecology/WEB-INF/securityRule:/usr/local/weaver/ecology/WEB-INF/securityRule + - ./ecology/WEB-INF/securityXML:/usr/local/weaver/ecology/WEB-INF/securityXML + - ./ecology/WEB-INF/service:/usr/local/weaver/ecology/WEB-INF/service + - ./ecology/WEB-INF/prop:/usr/local/weaver/ecology/WEB-INF/prop + - ./resin/log:/usr/local/weaver/resin/log + - ./resin/logs:/usr/local/weaver/resin/logs + environment: + TZ: Asia/Shanghai +``` + +##### 3.5.2 数据持久化说明 + +在 `docker` 中,无论是原生的 `-v` 参数也好,还是 `docker-compose` 的 `volumes` 参数也罢。在启动容器时,会将宿主机上的相关目录复制到容器内部。以 `ecology/album` 目录为例,当宿主机上 `./ecology/album`目录不存在,或者该目录下不存在任何文件,那么启动容器后,使用 `exec` 命令登陆容器后会发现容器内的 `/usr/local/ecology/album` 目录下的所有文件都被清空! + +![image-20200207144203566](asset/image-20200207144203566.png) + +**总结:在启动容器时,需要手动创建所要持久化的目录,并且将相关目录下的文件`copy`到对应目录中** + +如果使用已经构建好的镜像,不确定镜像内的文件是什么。那么可以采用以下方案: + +1. 启动容器时先不挂载数据卷:`docker run -itd --name=e9 e9-mysql:190902` +2. 使用 `cp` 命令将容器内的文件 `copy` 到宿主机中:`sudo docker cp containerID:container_path host_path` + +![image-20200207145051503](asset/image-20200207145051503.png) + +##### 3.5.3 启动服务 + +- 执行 `docker-compose up` 启动服务,出现以下信息表示服务启动成功 + +![image-20200203033722839](asset/image-20200203033722839.png) + +- 打开浏览器输入:`http://ip:8080` + +## 4. 移动平台部署 + +> 移动平台可以通过泛微官方地址: +> +> https://emobile.weaver.com.cn/emp/download + +#### 4.1 常规部署 + +关于 `E-mobile7` 常规部署参考 `泛微移动平台安装手册` 即可! + +#### 4.2 独立部署 + +`E-Mobile7` 包含 `em7` ,`redis`,`mysql`,`active-mq`,`tomcat` 五大组成部分。其中 `em7` 依赖于 `tomcat` 启动。其他部分均可独立部署。也就是说 `E-Mobile7` 可以拆分成四大部分独立部署。 + +相关配置可查看: https://yq.weaver.com.cn/eb/qa/view/#/question/5fb7e8e6124948129b1bfada0737f9f6 + +#### 4.3 Docker部署 + +##### 4.3.1 镜像制作 + +- 下载解压安装包和补丁包 + +![image-20200210134926003](asset/image-20200210134926003.png) + +![image-20200210135000703](asset/image-20200210135000703.png) + +```bash +tar -zxvf emp_install_linux64_20191226.tar.gz +# 如果已经安装unzip则跳过 +# yum install unzip +unzip -o emp_patch_20200109.zip +``` + +- 创建 `/usr/local/docker/emp`,将 `appsvr`,`jdk`,`work` copy到该目录下 + +```bash +mkdir -p /usr/local/docker/emp +\cp -r appsvr /usr/local/docker/emp +\cp -r jdk /usr/local/docker/emp +\cp -r work /usr/local/docker/emp +``` + +- 使用 `ubuntu` 依赖的 `Dockerfile` + +```bash +FROM ubuntu +COPY appsvr/tomcat /usr/local/emp/tomcat/ +COPY work/ /usr/local/emp/work/ +COPY start.sh /usr/local/emp/ +COPY jdk/ /usr/local/jdk/ +ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/jdk/bin:/usr/local/emp/tomcat/bin:/usr/local/emp/tomcat/bin +ENV TZ=Asia/Shanghai +ENV JAVA_HOME=/usr/local/jdk +ENV CLASSPATH=/usr/local/jdk/lib/dt.jar:/usr/local/jdk/lib/tools.jar +ENV CATALTNA_HOME=/usr/local/emp/tomcat +ENV CATALINA_HOME_BASE=/usr/local/emp +ENV LC_ALL=zh_CN.gbk +ENV LANG=zh_CN.gbk +EXPOSE 8095 +EXPOSE 8999 +EXPOSE 9443 +RUN [ "/bin/sh", "-c", "chmod +x /usr/local/emp/start.sh" ] +CMD [ "/bin/sh", "-c", "/usr/local/emp/start.sh" ] +``` + + +- 下载 [start.sh](https://github.com/Y-Aron/cloud-note/blob/master/weaver/shell/emp/start.sh) 至 `/usr/local/docker/emp` + +- 创建 `/usr/local/docker/emp/docker-compose.yml` + +```yaml +version: '3.1' +services: + em7: + build: + context: . + dockerfile: Dockerfile + restart: always + image: em7 + container_name: em7 + ports: + - 8999:8999 + environment: + EMP_ACTIVEMQ_ENABLED: "true" + EMP_ACTIVEMQ_IP: "192.168.44.155" + EMP_ACTIVEMQ_PORT: 61616 + EMP_ACTIVEMQ_USER: "system" + EMP_ACTIVEMQ_PASSWORD: "manager" + EMP_JTA_ENABLED: "false" + EMP_DB_TYPE: "mysql" + EMP_DB_NAME: "emp_app" + EMP_DB_IP: "192.168.44.155" + EMP_DB_PORT: 3306 + # oracle 使用 EMP_DB_SID: orcl + EMP_DB_USERNAME: "root" + EMP_DB_PASSWORD: 123456 + EMP_REDIS_ENABLED: "true" + EMP_REDIS_HOST: "192.168.44.155" + EMP_REDIS_PORT: 6381 + EMP_REDIS_PASSWORD: "WEAVERemobile7*()" + EMP_REDIS_DB: 0 + # # 集群配置 + # 集群节点ID:全局唯一 + EMP_CLUSTER_NODE_ID: 1 + # CDN地址 + EMP_CDN_URL: + # session存储介质,支持none、jdbc和redis + # none表示session存储在servlet容器(即原生session) + # jdbc表示session存储在数据库,redis表示session存储在redis里面(需配置redis数据源) + EMP_SESSION_STORE_TYPE: "none" + # session有效期默认7天 + EMP_SESSION_TIMEOUT: "7d" + # 基本信息缓存方式,支持none、ehcache和redis + # none表示不缓存数据 + # ehcache表示数据缓存在ehcache里面 + # redis表示数据缓存在redis里面(需配置redis数据源) + EMP_BASE_CACHE_TYPE: "ehcache" + # 操作日志保留期限(天),小于或者等于0表示不清理 + EMP_LOG_RETAIN_DAYS: 30 + # 从OA下载的文件保留期限(天),小于或者等于0表示不清理 + EMP_DOWNLOAD_RETAIN_DAYS: 10 +``` + +- 构建镜像命令:`docker-compose build` + +![image-20200211204511641](asset/image-20200211204511641.png) + +##### 4.3.2 启动 Ecology + +- 使用命令:`docker-compose up` + +![image-20200211205007406](asset/image-20200211205007406.png) + +- 打开浏览器,输入 `http://ip:port` 即可进入`E-Mobile7`后台! \ No newline at end of file