E9二开文档
@Author: 福州ebu 杨文杰
1. 前端开发根底
1.1 ECMAScript6 的应用
ECMAScript 和 JavaScript 的关系是:前者是后者的规格,后者是前者的一种实现。
ES6 既是一个历史名词,也是一个泛指,含意是 5.1 版当前的 JavaScript 的下一代规范,涵盖了 ES2015、ES2016、ES2017 等等,而 ES2015 则是正式名称,特指该年公布的正式版本的语言规范。本书中提到 ES6 的中央,个别是指 ES2015 规范,但有时也是泛指 “下一代 JavaScript 语言”。
1.2 ES6常见的语法
1.2.1 let 和 const 命令
ES6 新增了let
命令,用来申明变量。它的用法相似于var
,然而所申明的变量,只在let
命令所在的代码块内无效。
{ let a = 10; var b = 1;}a // ReferenceError: a is not defined.b // 1
const
申明一个只读的常量。一旦申明,常量的值就不能扭转。
const PI = 3.1415;PI // 3.1415PI = 3;// TypeError: Assignment to constant variable.
1.2.2 变量的解构赋值
ES6 容许依照肯定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)
如果解构不胜利,变量的值就等于undefined
- 数组的解构赋值
let [foo, [[bar], baz]] = [1, [[2], 3]];foo // 1bar // 2baz // 3let [ , , third] = ["foo", "bar", "baz"];third // "baz"let [x, , y] = [1, 2, 3];x // 1y // 3let [head, ...tail] = [1, 2, 3, 4];head // 1tail // [2, 3, 4]let [x, y, ...z] = ['a'];x // "a"y // undefinedz // []
- 对象的解构赋值
// 常见用法let { bar, foo, baz } = { foo: 'aaa', bar: 'bbb' };foo // "aaa"bar // "bbb"baz // undefined// foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foolet { foo: baz } = { foo: 'aaa', bar: 'bbb' };baz // "aaa"foo // error: foo is not defined// 嵌套应用let obj = { p: [ 'Hello', { y: 'World' } ]};// 第一个p作为变量,则进行赋值,第二个p作为模式,不会进行赋值let { p, p: [x, { y }] } = obj;x // "Hello"y // "World"p // ["Hello", {y: "World"}]
1.2.3 ... 运算符
- 函数
rest
参数的应用
function f(a, ...b) { console.log(a, b)}f(1,2,3,4,5) // 1 [2,3,4,5]
- 数组拆解
const a = [1,2,3]const b = [4,5,6]const c = [...a, ...b]c // [1,2,3,4,5,6]
- 对象拆解
const obj = { a: 111, b:222 }const copyObj = { ...obj, c: 333 }copyObj // { a: 111, b:222, c: 333 }
1.2.4 函数的扩大
- 参数默认值:ES6 容许为函数的参数设置默认值,即间接写在参数定义的前面。
// 根本用法function log(x, y = 'World') { console.log(x, y);}log('Hello') // Hello Worldlog('Hello', 'China') // Hello Chinalog('Hello', '') // Hello// 参数默认值能够与解构赋值的默认值,联合起来应用。function foo({x, y = 5}) { console.log(x, y);}foo({}) // undefined 5foo({x: 1}) // 1 5foo({x: 1, y: 2}) // 1 2foo() // TypeError: Cannot read property 'x' of undefined
- 箭头函数:ES6 容许应用(
=>
)定义函数。
// 根本用法var f = v => v;// 等同于var f = function (v) { return v;};// 箭头函数能够与变量解构联合应用。const full = ({ first, last }) => first + ' ' + last;// 等同于function full(person) { return person.first + ' ' + person.last;}// rest 参数与箭头函数联合const numbers = (...nums) => nums;numbers(1, 2, 3, 4, 5) // [1,2,3,4,5]const headAndTail = (head, ...tail) => [head, tail];headAndTail(1, 2, 3, 4, 5) // [1,[2,3,4,5]]
1.3 React根底
React 是一个用于构建用户界面的
Javascript
库。React 次要用于构建UI,很多人认为 React 是 MVC 中的 V(视图)。
React 起源于 Facebook 的外部我的项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源。
React 领有较高的性能,代码逻辑非常简单,越来越多的人已开始关注和应用它。
1.3.1 JSX语法
JSX 即 Javascript XML,它是对 JavaScript 语法扩大。React 应用 JSX 来代替惯例的 JavaScript。你也能够认为 JSX 其实就是 JavaScript。当遇到 <
,JSX就当HTML解析,遇到 {
就当 JavaScript 解析。
- 根本用法
const element = ( <h1 className="greeting"> Hello, world! </h1>);// 等价于const element = React.createElement( 'h1', {className: 'greeting'}, 'Hello, world!');
在
JSX
中嵌入表达式申明了一个名为
name
的变量,而后在JSX
中应用它,并将它包裹在大括号中:
const name = 'Josh Perez';const element = <h1>Hello, {name}</h1>;
1.3.2 React简略实例
class HelloMessage extends React.Component { render() { return ( <div> Hello {this.props.name} </div> ); }}ReactDOM.render( <HelloMessage name="React" />, document.getElementById('hello-example'));
2. E-code 前端开发平台
举荐 OA 上的所有前端开发对立应用 ecode 进行代码开发治理。
Ecode 官网文档: https://e-cloudstore.com/ecod...
E9 技术站地址: https://e-cloudstore.com/e9/i...
组件库地址: http://203.110.166.60:8087/#/...
本章节是针对 ecode
文档的细节补充
2.1 流程开发
对于流程页面上的前端开发,倡议不要间接应用代码块进行开发!所有的开发代码对立在 ecode 平台上进行,而后在流程表单代码块中插入如下代码,或者应用 全局流程代码块整合 计划加载代码。
// 倡议在代码块中增加 代码在ecode 中的文件门路,不便寻找对应的代码。// 默认分类/测试ecodeSDK.load({ // ${appId}泛值ecode平台中的文件夹主键id id: '${appId}', noCss: true, cb: function() {}})
2.2 建模开发
2.2.1 布局代码块
建模布局页面的应用形式与流程基本一致,在代码块中加载代码块。不倡议应用全局流程代码块整合进行加载。
2.2.2 自定义按钮
后端利用核心 -> 建模引擎 -> 查问
任选一个查问页面 -> 自定义按钮 -> 右键 -> 新建
- 办法体中存在多行代码时,每个语句必须以
;
结尾;否则会报错! params
的值等于‘field1+field2+field3’
这个值是一个字符串id
指的是数据ID
自定义按钮实现成果
应用 ecode 进行代码治理
新建前置文件
index.js
并将办法挂到全局对象window.g
下(window.g 为自定义对象,能够任意)自定义按钮的配置如下:
留神:全局办法的参数中,最初一个参数示意以后行的数据ID,如下例子所示
// ecode 中定义的办法function test = (p1, p2, p3, id) => { console.log(p1, p2, p3, id)}window.g = { test}// 自定义按钮配置// javascript:window.g.test(1,2,3) => 输入 1 2 3 数据ID// javascript:window.g.test(1,2,3, '任意值') => 输入 1 2 3 数据ID
2.2.3 页面扩大
后端利用核心 -> 建模引擎 -> 模块
任选一个模块 -> 页面扩大 -> 右键 -> 新建
扩大用处:卡片页面、查问列表(批量操作)、卡片页面和查问列表
- 卡片页面:能够设置页面扩大显示在卡片信息页面,能够抉择在新建页面、编辑页面、查看页面显示页面扩大。
- 查问列表(批量操作):设置在查问列表时,则会在援用该模块的查问列表的批量操作中显示页面扩大项,在批量操作中勾选后会在前台列表中显示对应的页面扩大项。
- 卡片页面和查问列表:能够设置页面扩大项既显示在对应的卡片页面又显示在查问列表(批量操作)中。
javascript:test()
: 该办法能够在建模引擎 -> 查问 -> 该模块的查问列表 -> 编辑代码块
中定义
前端按钮测试如下
- 页面扩大同样能够配置
ecode
应用,将链接指标地址改成:javascript: window.g.test()
即可,倡议这样做,不便后续代码保护。
3. 后端开发
E9 后端开发详见:https://e-cloudstore.com/e9/f...
本章节是针对笔记中未形容的开发点进行补充!
3.1 JavaWeb我的项目搭建
- 应用
Idea
创立一个Java
我的项目 - 增加
jar
依赖:File -> Project Structure -> Project Settings -> Libraries
须要增加的ecology
的依赖门路有: ecology/WEB-INF/lib
; resin/lib
; ecology/classbean
;
其中classbean
是必须要引入的, 其余两个按需引入
- 编译
Java
文件将编译后的class
文件放入ecology/classbean/
目录下即可
3.2 Maven我的项目搭建
- 将
ecology/classbean
打成jar
包,进入ecology/classbean
目录,执行以下命令
命令:jar -cvf ecology-[版本号].jar .
例如:jar -cvf ecology-9.1909.04.jar .
- 将
ecology-9.1909.04.jar
退出到本地 maven 仓库
// -Dfile参数指的是jar的门路mvn install:install-file -DgroupId=com.weaver -DartifactId=ecology -Dversion=9.1909.04 -Dpackaging=jar -Dfile=ecology-9.1909.04.jar
- 创立
maven
我的项目,并在POM.xml
中配置如下
<dependency> <groupId>com.weaver</groupId> <artifactId>ecology</artifactId> <version>9.1909.04</version></dependency>
3.3 自定义 Java 接口
3.3.1 流程节点前后附加操作
在节点前后附加操作中可设置接口动作,实现流程自定义附加操作
接口动作标识不能反复;接口动作类文件必须是类全名,该类必须实现接
weaver.interfaces.workflow.action
办法public String execute(RequestInfo request)
代码参考:
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; }}
接口配置:
后端利用核心 -> 流程引擎 -> 门路治理 -> 门路设置
任选一个流程 -> 流程设置 -> 节点信息
任选一个节点 -> 节点前 / 节点后附加操作
3.3.2 建模页面扩大接口
页面扩大 -> 接口动作 -> 自定义接口动作
执行页面扩大的后续操作,通过配置自定义
Java
接口动作类实现。接口动作类文件必须是类全名。该类必须继承
weaver.formmode.customjavacode.AbstractModeExpandJavaCode
办法public void doModeExpand(Map param)
参考代码如下:
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<String, Object> 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(); //------请在上面编写业务逻辑代码------ } } }}
接口配置:
后端利用核心 -> 建模引擎 -> 模块
任选一个模块 -> 页面扩大 -> 任选一个扩大名称 -> 接口动作 -> 点击
+
号 -> 自定义接口动作
3.3.3 打算工作接口
通过配置自定义 Java
接口的实现类,定时执行相应的代码
- 依照设定的工夫定时执行工作,打算工作标识不能反复
- 打算工作类必须是类的全名,该类必须继承
weaver.interfaces.schedule.BaseCronJob
类,重写办法public void execute() {}
- 工夫格局按
Cron
表达式的定义
参考代码如下:
import weaver.interfaces.schedule.BaseCronJob;public class CronTemplate extends BaseCronJob { @Override public void execute() { //------请在上面编写业务逻辑代码------ }}
配置:后端利用核心 -> 集成核心 -> 打算工作 -> 工作列表 -> 新建
通过打算工作列表的每个打算工作的自定义按钮,能够对每个工作进行状态操作,具体应用如下所示
状态详解:
- 启用: 打算工作将依据Cron表达式执行;
- 禁用: 打算工作将不再执行,重启服务也不会再次执行;
- 暂停: 针对打算工作进行进行,重启服务将恢复正常状态;
- 复原: 针对暂停状态的打算工作进行复原,复原后打算工作将继续执行;
- 执行: 单次执行打算工作,不影响Cron表达式周期执行;
- 测试: 查看填写的打算工作类是否符合规范(继承weaver.interfaces.schedule.BaseCronJob类,重写办法public void execute() {})
3.3.4 自定义按钮接口
通过配置自定义Java
类,判断自定义按钮在查问列表中是否显示
参考代码如下:
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"; }}
配置:后端利用核心 -> 建模引擎 -> 查问
任选一个查问列表 -> 自定义按钮 -> 右键 -> 新建
前端查问列表中,因为接口中返回false,则 受控按钮 不显示
3.4 Rest Api 接口
E-cology9 相比 E8,减少了 rest api接口定义框架 jersey
,应用该框架能够很不便的应用http申请进行相干开发。
3.4.1 凋谢接口
- 流程表单数据接口:https://www.evernote.com/l/Au...
- 流程代办列表接口:https://www.evernote.com/l/Au...
- 流程列表数据接口:https://www.evernote.com/l/Au...
3.4.2 自定义 Api 接口
创立 com.api.demo.web.TestActionApi.java
package com.api.demo.web;import com.demo.jack.web.TestAction;import javax.ws.rs.Path;@Path("/demo/test")public class TestActionApi extends TestAction {}
创立 com.demo.jack.web.TestAction
package com.demo.jack.web;import javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.core.MediaType;public class TestAction { @GET @Path("/hello") @Produces(MediaType.TEXT_PLAIN) public String hello() { return "hello weaver!"; }}
启动 resin
,关上浏览器输出:http://127.0.0.1/api/demo/test/hello
输入:hello weaver!
3.5 我的项目构造和代码标准
每个人都有属于本人的一套开发标准,以下是一套相对而言比拟标准的二开标准,仅供参考
3.5.1 应用 Weaverboot-E9(beta)
Weaverboot-E9 提供一套残缺的 IOC + AOP 的解决方案。能够很疾速的代理所有的接口。同时提供相似与spring 的依赖注入的写法。不便疾速编码。该计划目前属于内测版,但举荐应用!
官网文档: https://www.e-cloudstore.com/...
ecology/WEB-INF/web.xml
退出以下配置
<servlet> <servlet-name>WeaIocInitServlet</servlet-name> <servlet-class>com.weaverboot.frame.ioc.prop.init.WeaIocInitServlet</servlet-class> <load-on-startup>1</load-on-startup></servlet><servlet-mapping> <servlet-name>WeaIocInitServlet</servlet-name> <url-pattern>/weaIoc/init</url-pattern></servlet-mapping><filter> <filter-name>WeaComponentFilter</filter-name> <filter-class>com.weaverboot.frame.ioc.filter.WeaComponentFilter</filter-class></filter><filter-mapping> <filter-name>WeaComponentFilter</filter-name> <url-pattern>/api/*</url-pattern></filter-mapping>
ecology/WEB-INF/prop/
中创立weaverboot.properties
# 扫包门路scanPackage=com.demo.jack.**
ecology/WEB-INF/lib/
下增加Weaverboot-E9.jar
(暂不提供下载链接,想体验找云商店)
3.5.2 基于 weaverboot 的代码分层
临时不对数据层进行拆分, 未对mybatis
进行整合。间接应用 RecordSet 对数据库进行操作即可!
- 接口层
package com.demo.jack.web;import com.demo.jack.service.TestService;import com.weaverboot.frame.ioc.anno.fieldAnno.WeaAutowired;import lombok.extern.slf4j.Slf4j;import javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.core.MediaType;@Slf4j(topic = "debug")public class TestAction { @WeaAutowired private TestService testService; @GET @Path("/get") @Produces(MediaType.TEXT_PLAIN) public String testGet() { log.debug("{}", testService.getMessage()); return testService.getMessage(); }}
- 服务层
package com.demo.jack.service;public interface TestService { String getMessage();}
package com.demo.jack.service.impl;import com.demo.jack.service.TestService;import com.weaverboot.frame.ioc.anno.classAnno.WeaIocService;@WeaIocServicepublic class TestServiceImpl implements TestService { @Override public String getMessage() { return "this is test service impl ret list"; }}
3.5.3 应用 Fast-boot
FastBoot
框架是针对e9
二次开发中常见的业务场景的实现性能,进行代码抽离封装。奉行规范化,简单化,快速化,高复用的准则。其次要实现了数据库,文档文件,流程,建模,数学,流水号生成等相干工具类,从而简化开发过程,标准开发代码,进步开发效率!
文档详见: https://fzebu_code.gitee.io/c...
3.5.4 应用 lombok
- 下载
lombok.jar
idea
装置lombok plugin
- 代码中应用
import lombok.Getter;import lombok.Setter;import lombok.ToString;@Setter@Getter@ToStringpublic class TestDTO { private String name; private String password;}
3.5.5 日志框架的应用
Ecology
底层采纳的是log4j
日志框架, 可依据环境自定义日志配置
log4j
配置文件门路:ecology/WEB-INF/log4jinit.properties
- 关上配置文件, 在文件开端加上如下代码, 而后重启
resin
服务
# appenderlog4j.logger.debug=DEBUG,debuglog4j.appender.debug=org.apache.log4j.DailyRollingFileAppender# 按日期滚动文件log4j.appender.debug.DatePattern='_'yyyyMMdd'.log'# 自定义日志文件门路log4j.appender.debug.File=@debug/debug.loglog4j.appender.debug.layout=org.apache.log4j.PatternLayout# 输入内容格局log4j.appender.debug.layout.ConversionPattern=%d{HH:mm:ss.SSS}[%p] %l: %m%nlog4j.additivity.debug=false
- 代码中应用:
// 获取自定义的 logger, 其中 debug为配置文件中 log4j.logger.debug中的debugLogger logger = LoggerFactory.getLogger("debug");// 反对占位符输入, 不定参数logger.debug("debug级别音讯: {}, {}", "参数1", "参数2");logger.info("info级别音讯!");logger.warn("warn级别音讯!");logger.error("error级别音讯!");
- 最终日志输入门路:
倡议: 将重要的日志以 info
级别以上输入, 开发的日志以 debug
级别输入, 这样的话再正式环境下只需批改配置, 即可实现只输入 info
级别的日志, 缩小日志的输入!
# 将日志级别晋升至INFOlog4j.logger.debug=INFO,debug
3.6 数据库操作
3.6.1 CURD
应用weaver.conn.RecordSet
能够对数据库进行CURD
等数据库操作
参考代码:
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);
3.6.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();}
4. 缓存相干
4.1 缓存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
import com.cloudstore.dev.api.util.Util_DataCache;public Map<String,String> refreshDataFormDB() { Map<String,String> map = new HashMap<String, String>(); Map<String,String> 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.2 Redis的应用
- 本地下载
redis
ecology/WEB-INF/prop/weaver_new_session.properties
#1示意启用新的session形式,其余值示意不启用status=1#用于调试的USERIDdebugUsers=#session id生成模式,1示意自定义生成模式(UUID模式),其余值示意中间件自定义生成模式useCustomSessionId=1#同步频率设置(单位,秒)#主表同步频率SessionTableSync=2#明细表同步频率SessionItemTableSync=5#超时扫描频率SessionOverTime=300#垃圾数据清理扫描频率SessionLeak=3600#启动模式,默认是数据库模式#className=weaver.session.util.DBUtilclassName=weaver.session.util.RedisSessionUtil#redis ipredisIp=127.0.0.1#redis portredisPort=6379#redis passwordredisPassword=123456enableImmediatelySync=trueetoken=
4.3 SQL 缓存注意事项
Ecology 平台具备数据缓存机制,在我的项目中尽量不要间接对数据库进行操作,如执行存储过程或者触发器。如果切实没有方法则须要进行 Sql 缓存配置(切记!)
- 原则上禁止通过非程序渠道间接批改oa数据库数据。如果肯定要批改,请批改完数据后,chrome浏览器拜访/commcache/cacheMonitor.jsp界面,点击重启加载配置。这样操作批改的数据能够及时失效。
- 如果存在第三方程序修改oa数据库的表,则须要将会批改的表的名称以(名称=名称)的格局减少到例外配置文件:ecology\WEB-INF\prop\cacheBackList.properties中,而后再应用重启加载配置,使其失效。
- 如果客户二次开发中存在非RecordSet(零碎规范sql操作类)类批改数据库里的表,也须要将该表名按注意事项2的形式操作,将其退出例外配置文件中。
- 如果客户二次开发中还存在调用本人新建的存储过程,视图,函数(办法)。也须要将存储过程,视图,函数(办法)中波及到的表名退出到例外配置文件中ecology\WEB-INF\prop\cacheBackList.properties。而后再应用重启加载配置,使其失效。
- 集群环境,如果开启sql缓存,必须所有节点全副开启,敞开也必须所有节点同时全副敞开,否则必然存在缓存不同步问题
5. 异构零碎对接
5.1 接口白名单配置
对于 ecology 平台而言,所有的 rest api 接口都要通过登陆认证。否则不容许接入。在内网环境或者保障网络安全的状况下能够应用接口白名单配置。跳过登陆认证进行接口拜访。
weaver_session_filter.properties
(零碎)
内部配置文件,配置放行的门路地址。(启用了weaver_session_filter.properties
会主动笼罩原web.xml
中的门路)
weaver_session_filter_dev.properties
(用户自定义)
用户自定义配置文件,配置放行的门路地址(我的项目二开的门路倡议放用户定义配置文件,降级时不被笼罩)会主动笼罩web.xml 中的门路地址。
# 头部验证门路 实用于 EMcheckurl=/api/hrm/emmanager;# 头部验证放行门路 实用于 EMuncheckurl=/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 进行接口拜访相对而言更加平安,其数据不易被抓取。
官网版本:https://e-cloudstore.com/e9/f...
集体版本:Token认证
5.3 Webservice 的应用
Web Service是一个平台独立的,低耦合的,自蕴含的、基于可编程的web的应用程序,可应用凋谢的XML(规范通用标记语言下的一个子集)规范来形容、公布、发现、协调和配置这些应用程序,用于开发分布式的交互操作的应用程序
5.3.1 白名单配置
如果发现 http://oa地址/services/
无法访问,将须要调用该WEBSERVICE的IP增加到白名单中
在 ecology/WEB-INF/securityXML/weaver_security_custom_rules_1.xml
中的 <root>
节点上面增加相似如下的节点(IP能够指定某个网段,也能够指定具体IP):
<webservice-ip-list> <ip>80.16.</ip></webservice-ip-list>
5.3.2 应用 Http 调用 Webservice
WebService的相干办法能够通过应用 http 传输对应的 xml 字符串进行调用。能够应用SoapUI
解析webservice
接口信息
- SoapUI 介绍和应用形式能够参考博文: https://www.cnblogs.com/yatou...
- 软件下载:https://pan.baidu.com/s/1j36r...,提取码: 8v9x
应用HttpClient
以xml
报文模式调用webservice
服务
申请报文能够通过 SoapUI
查看
- 代码测试,其中
com.fzebu.fastboot.util.WebServiceUtil
源码地位:WebServiceUtil
package com.fzebu.fastboot.util;import com.fzebu.fastboot.ws.WebServiceUtil;import org.dom4j.DocumentException;import org.dom4j.Element;import java.io.IOException;import java.util.List;public class TestWebService { public static void main(String[] args) throws IOException, DocumentException { String url = "http://www.webxml.com.cn/webservices/ChinaTVprogramWebService.asmx"; String xml = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:web=\"http://WebXml.com.cn/\">\n" + " <soapenv:Header/>\n" + " <soapenv:Body>\n" + " <web:getTVstationDataSet>\n" + " <web:theAreaID>18</web:theAreaID>\n" + " </web:getTVstationDataSet>\n" + " </soapenv:Body>\n" + "</soapenv:Envelope>"; String resp = WebServiceUtil.execute(url, xml); Element rootElement = WebServiceUtil.getRootElement(resp); List<Element> elements = WebServiceUtil.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()); } }}
5.4 单点登录
第三方通过URL前面拼接
?ssoToken=
参数,容许间接关上 oa 页面官网文档: https://e-cloudstore.com/e9/f...
6. 其余开发
6.1 近程调试
该计划只能在测试或者开发环境中应用,不容许在生产环境中应用!切记 !!!
配置JVM
近程调试参数: resin\conf\resin.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
总结:更为具体的配置过程参考: https://www.jianshu.com/p/4c6...
6.2 本地代码调试
对于本地代码调试这块,上面介绍两种计划
- 传统调试计划
个别状况下,须要启动 e9 服务,而后编写 xx.jsp
进行代码测试,而后看输入的日志进行后果查看。这种调试形式有个缺点,就是须要启动 e9 服务,极大的耗费了电脑资源,并且应用日志的形式进行后果查看效率升高很多。
- 基于
junit
的代码调试
public class TestApp { @Before public void startEnv() { // 本地e9的demo门路 String rootPath = "D:\\Weaver\\ecology\\"; GCONST.setRootPath(rootPath); GCONST.setServerName("ecology"); } @Test public void test() { RecordSet rs = new RecordSet(); rs.executeQuery("select * from hrmresource"); // 一顿操作 }}
阐明:能够不应用 junit
,间接在main
中进行测试也是ok的 ,然而你必须要有startEnv()
办法外面的三句话,否则有效!
public static void main(String[] args) { String rootPath = "D:\\Weaver\\ecology\\"; GCONST.setRootPath(rootPath); GCONST.setServerName("ecology"); // 一顿操作}
6.3 容器化部署
具体部署材料: http://fzebu_code.gitee.io/cl...