乐趣区

关于ecmascript:E9二开文档

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.1415

PI = 3;
// TypeError: Assignment to constant variable.

1.2.2 变量的解构赋值

ES6 容许依照肯定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)

如果解构不胜利,变量的值就等于undefined

  • 数组的解构赋值
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

let [, , third] = ["foo", "bar", "baz"];
third // "baz"

let [x, , y] = [1, 2, 3];
x // 1
y // 3

let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
  • 对象的解构赋值
// 常见用法
let {bar, foo, baz} = {foo: 'aaa', bar: 'bbb'};
foo // "aaa"
bar // "bbb"
baz // undefined


// foo 是匹配的模式,baz 才是变量。真正被赋值的是变量 baz,而不是模式 foo
let {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 World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello

// 参数默认值能够与解构赋值的默认值,联合起来应用。function foo({x, y = 5}) {console.log(x, y);
}

foo({}) // undefined 5
foo({x: 1}) // 1 5
foo({x: 1, y: 2}) // 1 2
foo() // 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 自定义按钮

后端利用核心 -> 建模引擎 -> 查问

任选一个查问页面 -> 自定义按钮 -> 右键 -> 新建

  1. 办法体中存在多行代码时,每个语句必须以 ; 结尾;否则会报错!
  2. params的值等于 ‘field1+field2+field3’ 这个值是一个字符串
  3. 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() {//------ 请在上面编写业务逻辑代码 ------}
}

配置:后端利用核心 -> 集成核心 -> 打算工作 -> 工作列表 -> 新建

通过打算工作列表的每个打算工作的自定义按钮,能够对每个工作进行状态操作,具体应用如下所示

状态详解:

  1. 启用: 打算工作将依据 Cron 表达式执行;
  2. 禁用: 打算工作将不再执行,重启服务也不会再次执行;
  3. 暂停: 针对打算工作进行进行,重启服务将恢复正常状态;
  4. 复原: 针对暂停状态的打算工作进行复原,复原后打算工作将继续执行;
  5. 执行: 单次执行打算工作,不影响 Cron 表达式周期执行;
  6. 测试: 查看填写的打算工作类是否符合规范(继承 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;

@WeaIocService
public 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
@ToString
public class TestDTO {
    private String name;
    private String password;
}

3.5.5 日志框架的应用

Ecology底层采纳的是 log4j 日志框架, 可依据环境自定义日志配置

log4j配置文件门路: ecology/WEB-INF/log4jinit.properties

  • 关上配置文件, 在文件开端加上如下代码, 而后重启 resin 服务
# 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
  • 代码中应用:
// 获取自定义的 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 级别音讯!");
  • 最终日志输入门路:

倡议: 将重要的日志以 info 级别以上输入, 开发的日志以 debug 级别输入, 这样的话再正式环境下只需批改配置, 即可实现只输入 info 级别的日志, 缩小日志的输入!

# 将日志级别晋升至 INFO
log4j.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
#用于调试的 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=

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 中的门路地址。

# 头部验证门路 实用于 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 进行接口拜访相对而言更加平安,其数据不易被抓取。
官网版本: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

应用 HttpClientxml 报文模式调用 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…

退出移动版