1
头图

E9 Two Open Document

@Author: Fuzhou ebu Yang Wenjie

1. Front-end development foundation

1.1 Use of ECMAScript6

The relationship between ECMAScript and JavaScript is: the former is the specification of the latter, and the latter is an implementation of the former.

ES6 is not only a historical term, but also a general reference. It means the next-generation standard of JavaScript after version 5.1, covering ES2015, ES2016, ES2017, etc., while ES2015 is the official name, specifically referring to the language of the official version released that year standard. Where ES6 is mentioned in this book, it generally refers to the ES2015 standard, but sometimes it also refers to the "next-generation JavaScript language".

1.2 Common syntax of ES6

1.2.1 let and const commands

ES6 added the let command to declare variables. Its usage is similar to var , but the declared variables are only valid in the code block where the let

{
  let a = 10;
  var b = 1;
}

a // ReferenceError: a is not defined.
b // 1

const declares a read-only constant. Once declared, the value of the constant cannot be changed.

const PI = 3.1415;
PI // 3.1415

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

1.2.2 Deconstruction and Assignment of Variables

ES6 allows extracting values from arrays and objects and assigning values to variables according to certain patterns. This is called Destructuring.

If the deconstruction is not successful, the value of the variable is equal to undefined

  • Destructuring and Assignment of Array
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 // []
  • Object destructuring assignment
// 常见用法
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 ... operator

  • Use of function rest parameters
function f(a, ...b) {
    console.log(a, b)
}
f(1,2,3,4,5) // 1 [2,3,4,5]
  • Array disassembly
const a = [1,2,3]
const b = [4,5,6]
const c = [...a, ...b]
c // [1,2,3,4,5,6]
  • Object dismantling
const obj = { a: 111, b:222 }
const copyObj = { ...obj, c: 333 }
copyObj // { a: 111, b:222, c: 333 }

1.2.4 Function extension

  • Parameter default value: ES6 allows to set the default value for the function parameter, that is, it is written directly after the parameter definition.
// 基本用法
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
  • Arrow function: ES6 allows the use of ( => ) to define functions.
// 基本用法
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 basics

Javascript library for building user interfaces.

React is mainly used to build UI. Many people think that React is the V (view) in MVC.

React originated from Facebook's internal project to build an Instagram website, and it was open sourced in May 2013.

React has high performance, code logic is very simple, more and more people have begun to pay attention to and use it.

1.3.1 JSX syntax

JSX stands for Javascript XML, which is an extension of JavaScript syntax. React uses JSX to replace regular JavaScript. You can also think of JSX as JavaScript. When it encounters < , JSX is treated as HTML parsing, and { as JavaScript parsing.

  • Basic usage
const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);
// 等价于
const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);
  • Embed the expression in JSX

    Declare a name , then JSX and wrap it in curly braces:

const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;

1.3.2 React simple example

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 front-end development platform

It is recommended that all front-end development on OA use ecode for code development management.

Ecode official document: https://e-cloudstore.com/ecode/doc

E9 technical station address: https://e-cloudstore.com/e9/index2.html?tdsourcetag=s_pctim_aiomsg

Component library address: http://203.110.166.60:8087/#/pc/doc/common-index

This chapter is a detailed supplement ecode

2.1 Process development

Regarding front-end development on the process page, it is recommended not to directly use code blocks for development! All development codes are unified on the ecode platform, and then insert the following code into the process sheet code block, or use the global process code block to integrate the program loading code.

// 建议在代码块中添加 代码在ecode 中的文件路径,方便寻找对应的代码。
// 默认分类/测试
ecodeSDK.load({
    // ${appId}泛值ecode平台中的文件夹主键id
    id: '${appId}',
    noCss: true,
    cb: function() {}
})

2.2 Modeling development

2.2.1 Layout code block

The usage of the modeling layout page is basically the same as the process, and the code block is loaded in the code block. It is not recommended to use the global process code block to integrate for loading.

2.2.2 Custom button

Backend Application Center -> Modeling Engine -> Query

Choose a query page -> custom button -> right click -> new

  1. When there are multiple lines of code in the method body, each statement must ; ; otherwise, an error will be reported!
  2. params is equal ‘field1+field2+field3’ This value is a string
  3. id refers to the data ID

Custom button to achieve effect


Use ecode for code management

Create a new pre-file index.js and hang the method window.g (window.g is a custom object, it can be any)

The configuration of the custom button is as follows:

Note: Among the parameters of the global method, the last parameter represents the data ID of the current row, as shown in the following example

// 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 Page extension

Backend Application Center -> Modeling Engine -> Module

Choose a module -> page extension -> right click -> new

  • Extended use: card page, query list (batch operation), card page and query list

    • Card page: You can set the page extension to be displayed on the card information page, and you can choose to display the page extension on the new page, edit page, and view page.
    • Query list (batch operation): When set in the query list, the page expansion items will be displayed in the batch operation of the query list that refers to the module. After checking in the batch operation, the corresponding page expansion items will be displayed in the foreground list.
    • Card page and query list: You can set page extensions to be displayed both on the corresponding card page and in the query list (batch operation).
  • javascript:test() : This method can be defined in modeling engine -> query -> query list of the module -> edit code block

The front-end button test is as follows

  • The page extension can also be configured for ecode . link target address to: javascript: window.g.test() . It is recommended to do this to facilitate subsequent code maintenance.

3. Back-end development

For details of E9 backend development, please refer to: https://e-cloudstore.com/e9/file/E9BackendDdevelopmentGuide.pdf

This chapter is to supplement the development points not described in the notes!

3.1 Build a JavaWeb project

  • Use Idea create a Java project
  • Add jar dependency: File -> Project Structure -> Project Settings -> Libraries

The dependency paths ecology that need to be added ecology/WEB-INF/lib ; resin/lib ; ecology/classbean ;

Among them, classbean must be introduced, and the other two are introduced on demand

  • Compile the Java file and put the compiled class file into the ecology/classbean/ directory.

3.2 Maven project construction

  • ecology/classbean into the jar package, enter the ecology/classbean directory, and execute the following command

Command: jar -cvf ecology-[version number].jar.

For example: jar -cvf ecology-9.1909.04.jar .

  • Add ecology-9.1909.04.jar to the local maven warehouse
// -Dfile参数指的是jar的路径
mvn install:install-file -DgroupId=com.weaver -DartifactId=ecology -Dversion=9.1909.04 -Dpackaging=jar -Dfile=ecology-9.1909.04.jar
  • Create the maven project and configure it as follows POM.xml
<dependency>
    <groupId>com.weaver</groupId>
    <artifactId>ecology</artifactId>
    <version>9.1909.04</version>
</dependency>

3.3 Custom Java interface

3.3.1 Additional operations before and after the process node

Interface actions can be set in the additional operations before and after the node to complete the process custom additional operations

Interface identification operation can not be repeated; interface actions class file must be the full name of the class, then the class must implement weaver.interfaces.workflow.action method public String execute(RequestInfo request)

Code reference:

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;
    }
}

Interface configuration:

Backend Application Center -> Process Engine -> Path Management -> Path Settings

Choose a process -> process settings -> node information

Choose a node -> additional operations before node/after node

3.3.2 Modeling page extension interface

Page extension -> interface action -> custom interface action

Perform subsequent operations of page expansion by configuring a custom Java interface action class.

The interface action class file must be the full name of the class. This class must inherit the weaver.formmode.customjavacode.AbstractModeExpandJavaCode method public void doModeExpand(Map param)

The reference code is as follows:

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();
                //------请在下面编写业务逻辑代码------
            }
        }
    }
}

Interface configuration:

Backend Application Center -> Modeling Engine -> Module

Choose a module -> page extension -> choose an extension name -> interface action -> click + number -> custom interface action

3.3.3 Plan task interface
By configuring Java interface, execute the corresponding code regularly
  • The task is executed regularly according to the set time, and the scheduled task ID cannot be repeated
  • The scheduled task class must be the full name of the class, the class must inherit the weaver.interfaces.schedule.BaseCronJob class, and override the method public void execute() {}
  • The time format is defined Cron

The reference code is as follows:

import weaver.interfaces.schedule.BaseCronJob;

public class CronTemplate extends BaseCronJob {

    @Override
    public void execute() {
        //------请在下面编写业务逻辑代码------
    }
}

Configuration: Backend Application Center -> Integration Center -> Scheduled Tasks -> Task List -> New

Through the custom button of each scheduled task in the scheduled task list, you can perform status operations on each task. The specific use is as follows:

Detailed status:

  1. Enable: The scheduled task will be executed according to the cron expression;
  2. Disabled: The scheduled task will no longer be executed, and the service will not be executed again after restarting the service;
  3. Pause: Stop the scheduled task, restart the service and return to normal status;
  4. Resume: Resume the scheduled task in the suspended state, and the scheduled task will continue to be executed after it is resumed;
  5. Execute: execute the scheduled task once, without affecting the cycle execution of cron expression;
  6. Test: Check whether the filled scheduled task class conforms to the specification (inherit the weaver.interfaces.schedule.BaseCronJob class, override the method public void execute() {})
3.3.4 Custom button interface
By configuring the custom Java class, determine whether the custom button is displayed in the query list

The reference code is as follows:

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";
    }
}

Configuration: Backend Application Center -> Modeling Engine -> Query

Choose a query list -> custom button -> right click -> new

In the front-end query list, because the interface returns false, the controlled button not displayed

3.4 Rest Api interface

Compared with E8, E-cology9 adds the rest api interface definition framework jersey , which can be used to easily use http requests for related development.
3.4.1 Open interface
3.4.2 Custom Api interface

Created 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 {
}

Created 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!";
    }
}

Start resin , open the browser and enter: http://127.0.0.1/api/demo/test/hello

Output: hello weaver!

3.5 Project structure and code specification

Everyone has their own set of development specifications, the following is a relatively standardized set of two-open specifications, for reference only
3.5.1 Use Weaverboot-E9 (beta)

Weaverboot-E9 provides a complete IOC + AOP solution. Can proxy all interfaces very quickly. At the same time, it provides a way of writing dependency injection similar to that of spring. Convenient and fast coding. This program is currently in the internal beta, but it is recommended!

Official document: https://www.e-cloudstore.com/ecode/doc.html?appId=bb6e1c9796c1483cb8ed7c15df025ea8

  • ecology/WEB-INF/web.xml add the following configuration
<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/ created weaverboot.properties
# 扫包路径
scanPackage=com.demo.jack.**
  • Add ecology/WEB-INF/lib/ Weaverboot-E9.jar (download link is not currently provided, I want to experience the cloud store)
3.5.2 Code layering based on weaverboot
For the time being, the data layer will not be split, and mybatis will not be integrated. Just use RecordSet to operate the database directly!
  • Interface layer
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();
    }
}
  • Service layer
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 Using Fast-boot
FastBoot framework is aimed at the e9 of common business scenarios in the secondary development of 06103aa870fc9e, and the code is extracted and packaged. Pursue the principles of standardization, simplicity, speed, and high reuse. It mainly implements related tools such as database, document file, process, modeling, mathematics, serial number generation, etc., so as to simplify the development process, standardize the development code, and improve the development efficiency!
For details, please refer to: https://fzebu_code.gitee.io/cloud-note/#/./weaver/FastBoot/index
3.5.4 Using lombok
  • Download lombok.jar
  • idea install lombok plugin
  • Used in the code
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Setter
@Getter
@ToString
public class TestDTO {
    private String name;
    private String password;
}
3.5.5 Use of Log Framework

Ecology bottom uses log4j logging framework, can be customized according to the environmental configuration log

log4j Configuration file path: ecology/WEB-INF/log4jinit.properties

  • Open the configuration file, add the following code at the end of the file, and then restart the resin service
# 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
  • Used in the code:
// 获取自定义的 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级别消息!");
  • Final log output path:

suggestion : output important logs at the info and output the developed logs at the debug . In this case, you only need to modify the configuration in the formal environment to output only info , reducing the output of the logs!

# 将日志级别提升至INFO
log4j.logger.debug=INFO,debug

3.6 Database operations

3.6.1 CURD
Use weaver.conn.RecordSet to perform database operations such as CURD

reference code:

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 Using transactions
Use weaver.conn.RecordSetTrans to perform transaction operations on the database

Reference code

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. Cache related

4.1 Cache SDK
Cache base class: Util_DataCache
Method nameMethod effect
getObjVal(String name)Get cached data from all caches (main function)
setObjVal(String name, Object value)Set all cached data (main function)
setObjVal(String name, Object value,int seconds)Set all cached data to support timeout and disappear automatically (main function)
containsKey(String name)Determine whether all caches of the key name exist
clearVal(String name)Clear all caches of the key name
setObjValWithEh(String name,Object value)Set up local cache (used under specific circumstances)
getObjValWithEh(String name)Obtain the local cache (used under certain circumstances)
setObjValWithRedis(String name,Object value)To set up Redis cache, you need to release the data yourself (used under specific circumstances)
setObjValWithRedis(String name,Object value,int seconds)Release the data after setting the Redis cache timeout (s) separately (used under specific circumstances)
getObjValWithRedis(String name)Obtain Redis cache separately (used under specific circumstances)
containsKeylWithEh(String name)Determine whether the key name exists in the local cache (used under specific circumstances)
clearValWithEh(String name)Clear local cache (used under specific circumstances)
containsKeyWithRedis(String name)Determine whether the key name exists on Redis (used under specific circumstances)
clearValWithRedis(String name)Clear Redis cache
Check page

chechRedis.jsp Check the status of the Redis

getRedis.jsp Check the data of DataKey

Note that after the data is changed, setObjVal must be executed again to push the data to 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 Use of Redis
  • Local download 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 cache considerations
The Ecology platform has a data caching mechanism. Try not to directly manipulate the database in the project, such as executing stored procedures or triggers. If there is really no way, you need to configure the Sql cache (remember!)
  • In principle, it is forbidden to directly modify oa database data through non-program channels. If you must modify the data, please visit the /commcache/cacheMonitor.jsp interface in the chrome browser and click restart to load the configuration. In this way, the modified data can take effect in time.
  • If there is a third-party program to modify the table of the oa database, you need to add the name of the modified table in the format of (name=name) to the exception configuration file: ecology\WEB-INF\prop\cacheBackList.properties, and then use it Restart and load the configuration to make it take effect.
  • If there is a non-RecordSet (system standard sql operation class) class in the secondary development of the customer to modify the table in the database, the table name also needs to be operated in the way of Note 2 and added to the exception configuration file.
  • If the customer still calls his own newly created stored procedures, views, functions (methods) in the secondary development. It is also necessary to add the table names involved in the stored procedures, views, and functions (methods) to the exception configuration file ecology\WEB-INF\prop\cacheBackList.properties. Then use restart to load the configuration to make it take effect.
  • In a cluster environment, if SQL cache is turned on, all nodes must be turned on, and all nodes must be turned off at the same time when it is turned off, otherwise there will be a problem of cache out of synchronization.

5. Heterogeneous system docking

5.1 Interface whitelist configuration

For the ecology platform, all rest api interfaces must undergo login authentication. Otherwise, access is not allowed. The interface whitelist configuration can be used in the internal network environment or in the case of ensuring network security. Skip login authentication for interface access.
  • weaver_session_filter.properties (system)

External configuration file, configure the path address of the release. (Enable weaver_session_filter.properties will automatically overwrite the original path in web.xml

  • weaver_session_filter_dev.properties (user-defined)

User-defined configuration file, configure the release path address (it is recommended to put the user-defined configuration file in the path of the second project, and it will not be overwritten during upgrade), it will automatically overwrite the path address in 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 authentication

Compared with the interface whitelist, the use of tokens for interface access is relatively safer, and its data is not easy to be crawled.
Official version: https://e-cloudstore.com/e9/file/TokenAuthenticationSteps.pdf
Personal version: Token authentication

5.3 Use of Webservice

Web Service is a platform-independent, low-coupling, self-contained, programmable web-based application that can be described, published, discovered, and coordinated using open XML (a subset of the standard Universal Markup Language) standard And configure these applications for the development of distributed interactive operation applications
5.3.1 Whitelist configuration
If it is found that http://oa address/services/ cannot be accessed, add the IP that needs to call the WEBSERVICE to the whitelist

Add a node similar to the following below the <root> node in ecology/WEB-INF/securityXML/weaver_security_custom_rules_1.xml (IP can specify a certain network segment, or you can specify a specific IP):

<webservice-ip-list>
    <ip>80.16.</ip>
</webservice-ip-list>
5.3.2 Use Http to call Webservice
The related methods of WebService can be called by using http to transmit the corresponding xml string. You can use SoapUI parse the webservice interface information
Use HttpClient to webservice service in the form of xml

The request message can be viewed through SoapUI

  • Code test, where com.fzebu.fastboot.util.WebServiceUtil source code location: 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 Single sign-on

The third party splices the ?ssoToken= parameter behind the URL, allowing to open the oa page directly

Official document: https://e-cloudstore.com/e9/file/Third-partysinglesign-onEcologysolution.pdf

6. Other development

6.1 Remote debugging

This solution can only be used in a test or development environment, not in a production environment! Remember! ! !

Configure JVM remote debugging parameters: 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

Summary: For more detailed configuration process reference: https://www.jianshu.com/p/4c657bf02cb3

6.2 Local code debugging

Regarding the local code debugging, two solutions are introduced below
  • Traditional debugging scheme

Under normal circumstances, you need to start the e9 service, then write xx.jsp to test the code, and then look at the output log to check the result. This debugging method has a drawback, that is, it needs to start the e9 service, which greatly consumes computer resources, and the efficiency of viewing results using the log method is much lower.

  • Code debugging based on 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");
        // 一顿操作
    }
}

Note: It is not necessary to use junit , and it is ok to test directly in main startEnv() method, otherwise it will be invalid!

public static void main(String[] args) {
    String rootPath = "D:\\Weaver\\ecology\\";
    GCONST.setRootPath(rootPath);
    GCONST.setServerName("ecology");
    // 一顿操作
}

6.3 Containerized deployment

Specific deployment information: http://fzebu_code.gitee.io/cloud-note/#/./weaver/%E6%B3%9B%E5%BE%AE%E7%B3%BB%E7%BB%9F% E9%83%A8%E7%BD%B2?id=_3-docker-%e9%83%a8%e7%bd%b2

闫雪
37 声望9 粉丝